はじめに
UnitVで色検出する際に役立つポイントやテクニックについてまとめました。
デバイス & 開発環境
特定の色を検出する
import sensor
import image
sensor.reset() # カメラの初期化
sensor.set_pixformat(sensor.RGB565) # RGB565フォーマットを使用
sensor.set_framesize(sensor.QVGA) # QVGAフレームサイズを使用
sensor.skip_frames(time = 2000) # 2秒間フレームをスキップして安定化
threshold = [(30, 100, 15, 127, 15, 127)] # 検出する色のしきい値を設定
while(True):
img = sensor.snapshot() # 画像を取得
blobs = img.find_blobs(threshold) # しきい値内の色を検出
if blobs:
for b in blobs:
img.draw_rectangle(b[0:4]) # 検出した色を矩形で囲む
img.draw_cross(b[5], b[6]) # 検出した色の中心に十字を描く
カメラから画像を取得し、指定されたしきい値内の色を find_blobs()
で検出しています。もし検出された色があれば、それらの領域を矩形で囲み、中心に十字を描画します。
しきい値はLab色空間で指定します。MaixPyの「ツール」>「マシンビジョン」>「しきい値エディタ」より、「フレームバッファ」を選択することで現在カメラに写っている画像に対してしきい値調整ができます。
複数の色を検出する
import sensor
import image
sensor.reset() # カメラの初期化
sensor.set_pixformat(sensor.RGB565) # RGB565フォーマットを使用
sensor.set_framesize(sensor.QVGA) # QVGAフレームサイズを使用
sensor.skip_frames(time = 2000) # 2秒間フレームをスキップして安定化
thresholds = [(30, 100, 15, 127, 15, 127), # Red
(30, 100, -64, -8, -32, 32), # Green
(0, 15, 0, 40, -80, -20)] # Blue
while(True):
img = sensor.snapshot() # 画像を取得
blobs = img.find_blobs(thresholds) # しきい値内の色を検出
if blobs:
for b in blobs:
if b.code() == 1: # Red
img.draw_rectangle(b[0:4], color=(255, 0, 0))
img.draw_cross(b[5], b[6], color=(255, 0, 0))
if b.code() == 2: # Green
img.draw_rectangle(b[0:4], color=(0, 255, 0))
img.draw_cross(b[5], b[6], color=(0, 255, 0))
if b.code() == 4: # Blue
img.draw_rectangle(b[0:4], color=(0, 0, 255))
img.draw_cross(b[5], b[6], color=(0, 0, 255))
複数の色を検出したい場合は、しきい値をリストにして find_blob()
に渡すことで、一度に検出できます。最大32個まで指定できるようです。どの色が検出されたかは、 blob
の code()
を呼び出すことで確認できます。しきい値の順番に応じてビットが立つため、この場合Redは 1
、Greenは 2
、Blueは 4
となります。
検出を安定化させる
オートゲイン・オートホワイトバランスのオフ
import sensor
import image
sensor.reset() # カメラの初期化
sensor.set_pixformat(sensor.RGB565) # RGB565フォーマットを使用
sensor.set_framesize(sensor.QVGA) # QVGAフレームサイズを使用
sensor.set_auto_gain(False) # オートゲインをオフ
# sensor.set_auto_whitebal(False) # オートホワイトバランスをオフ 画像全体が黄色っぽくなってしまう
sensor.set_auto_whitebal(False, rgb_gain_db = (25, 20, 40)) # ゲインを設定しておく
sensor.skip_frames(time = 2000) # 2秒間フレームをスキップして安定化
OpenMVのドキュメントやMaixPyのドキュメントを見てみると、どうやら色の検出をする際は、 sensor.set_auto_gain()
と sensor.set_auto_whitebal()
を False
に設定することが望ましいようです。
しかし、sensor.set_auto_whitebal()
を False
に設定すると画像全体が黄色っぽくなることがあります。その場合、 rgb_gain_db = (25, 20, 40)のようにゲインを指定すると良いみたいです。ゲインの値は周囲の環境に合わせて調整してください。sensor.__write_reg(0x80, 0xEF)
のように手動でレジスタを書き換えると良いかもしれません。
明度・彩度・コントラストの調整
import sensor
import image
sensor.reset() # カメラの初期化
sensor.set_pixformat(sensor.RGB565) # RGB565フォーマットを使用
sensor.set_framesize(sensor.QVGA) # QVGAフレームサイズを使用
sensor.set_auto_gain(False) # オートゲインをオフ
sensor.set_auto_whitebal(False, rgb_gain_db = (25, 20, 40)) # ゲインを設定しておく
sensor.set_brightness(0) # 明度の調整
sensor.set_saturation(0) # 彩度の調整
sensor.set_contrast(2) # コントラストの調整
sensor.skip_frames(time = 2000) # 2秒間フレームをスキップして安定化
明度・彩度・コントラストを -3~+3
の範囲で調整することが出来ます。色検出ではコントラストを少し高めに設定しておくと良いでしょう。
面積が最大となる領域を求める
import sensor
import image
sensor.reset() # カメラの初期化
sensor.set_pixformat(sensor.RGB565) # RGB565フォーマットを使用
sensor.set_framesize(sensor.QVGA) # QVGAフレームサイズを使用
sensor.set_auto_gain(False) # オートゲインをオフ
sensor.set_auto_whitebal(False, rgb_gain_db = (25, 20, 40)) # ゲインを設定しておく
sensor.set_brightness(0) # 明度の調整
sensor.set_saturation(0) # 彩度の調整
sensor.set_contrast(2) # コントラストの調整
sensor.skip_frames(time = 2000) # 2秒間フレームをスキップして安定化
threshold = [(30, 100, 15, 127, 15, 127)] # 検出する色のしきい値を設定
while(True):
img = sensor.snapshot() # 画像を取得
blobs = img.find_blobs(threshold) # しきい値内の色を検出
if blobs:
max_blob = max(blobs, key=lambda b: b.area()) # 面積が最大の領域を取得
img.draw_rectangle(max_blob[0:4]) # 検出した色を矩形で囲む
img.draw_cross(max_blob[5], max_blob[6]) # 検出した色の中心に十字を描く
blob.area()
や blob.pixels()
を使うことで、領域の面積やピクセル数を求めることができます。max_blob = max(blobs, key=lambda b: b.area())
の部分で面積が最大となる領域を求めています。
参考資料
MaixPyのドキュメントには抜けている情報が多いため、OpenMVのドキュメントも参考にした方が良いです。逆に、OpenMVのドキュメントにはMaixPyではまだ実装されていない関数も含まれているので注意が必要です。