はじめに
今年の2月頃に収穫サポートロボット「TANG」の試作機を制作しました。
それから約半年が経過し、ハードウェア・ソフトウェアともにアップデートしたのでその詳細について
まとめていこうと思います。
今回からは、ソフトウェアをアップデートしたので、その内容について書いていきます。
前回の赤色検出方法
赤色検出では、PythonとOpenCVを用いました。
アルゴリズムは以下のように非常にシンプルです。
(1),(2) 閾値を設けて2値化
HSV画像とは、色相(Hue)、彩度(Saturation)、明度(Value)の3つの組み合わせで表現した画像です。
このHSV画像を用いて、赤色とそれ以外の色で2値化します。
この2値化するとき、これ以上は赤色と判定し、それ以下は赤色以外であるという閾値を設けています。
具体的には、HSV空間における赤色は、Hueの値が{0 ~ 30},{150 ~ 179}です。(参考サイト)
その他のS値とV値は、環境に応じて適宜変更します。
この関数では、2値化された画像から輪郭を計算します。
OpenCvにおける輪郭の定義はこちらが参考になります。
下の画像は、cv::findContours()に渡される2値化された画像のイメージ図です。
そして、この関数ではその画像をもとにそれぞれの輪郭をインデックスで区別し、
右の表のようにリストとして出力されます。
また、各indexには、輪郭の位置情報が入ってます。
さらに、この関数によって出力された変数contours[i]には、輪郭の各点の位置情報を持っており、
contours[i][j]は、contours[i]のj番目の頂点を指しています。
先程cv2.findContours()によって出力された輪郭の情報をもとに面積を計算します。
そして、最も大きい面積を持つ輪郭のインデックスを保持します。
この関数では、2次元の点の配列で表現された輪郭をもとに中心座標や内包する円の半径を出力してくれます。
これを使うことで、(4)のロボットが今からどこに行くべきかを計算することができます。
今回の赤色検出方法
前述した手法より、より高速に、かつシンプルに処理を行う
cv::connectedComponents関数を実装しました。
この手法の良い点は、前述したような複雑な処理をすべてこの関数一つで、かつより高速にやってくれるところです。
この関数では、先程同様に2値化された画像の繋がっている0でないピクセルに、同じ一意のラベル付けを行います。
さらに、ラベリングされたオブジェクトの中心や面積も計算してくれます。
(ちなみに、このラベル付けされた領域の特徴を解析することをブロブ解析と呼びます。)
実際のコードは以下のとおりです。
# ブロブ解析
def analysisBlob(self, binary_img):
# 2値画像のラベリング処理
# labelは画像のラベリング結果を保持している二次元配列
# label[0] ラベルの数
# label[1] ラベル番号が入った配列データ
# label[2] ラベリングされたオブジェクトの詳細情報
# (x, y, h, size), x, y, w, hは、オブジェクトの外形矩形の左上のx座標、
# y座標、高さ、label[3] オブジェクトの面積
label = cv2.connectedComponentsWithStats(binary_img)
# ブロブ情報を項目別に抽出,背景は0としてラベリングされるので削除
data = np.delete(label[2], 0, 0)
center = np.delete(label[3], 0, 0)
# ブロブ面積最大のインデックス
try:
max_index = np.argmax(data[:, 4]) # 4列目のすべての中から最大値のindexを取得
except ValueError:
print("ValueError")
maxblob = {}
return maxblob
# 面積最大ブロブの情報格納用
maxblob = {}
# 面積最大ブロブの各種情報を取得
# 左上座標(x, y)
maxblob["upper_left"] = (data[:, 0][max_index], data[:, 1][max_index])
maxblob["width"] = data[:, 2][max_index] # 幅
maxblob["height"] = data[:, 3][max_index] # 高さ
maxblob["area"] = data[:, 4][max_index] # 面積
maxblob["center"] = center[max_index] # 中心座標
return maxblob
この手法を使って赤色検出を行った結果を以下に示します。
かなりきれいに赤色だけを抽出できていますね〜
Raspbeperry pi 4で実行してみると、だいたい160FPSくらいでました。
これはリアルタイムで人物追従をするのには十分な速度がでていますね。