前回やった白いボールの輪郭描画に引き続き、赤いボールも同時に輪郭を描画してみます。
環境・バージョン
Windows10
Python 3.6.1
OpenCV 3.3.1
輪郭描画のコード
前回と処理の流れは変わらないのですが、複数回の処理を関数にまとめるなど、コードは若干整理しています。
ただ私自身、Pythonの構文も学びながら書くレベルなので参考程度に・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
import cv2 import numpy as np cap = cv2.VideoCapture('xxxx.mp4') # 任意の動画 while(1): _, frame = cap.read() #マスク画像取得 def getMask(l, u): # HSVに変換 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower = np.array(l) upper = np.array(u) if lower[0] >= 0: mask = cv2.inRange(hsv, lower, upper) else: #赤用(彩度、明度判定は簡略化) h = hsv[:, :, 0] s = hsv[:, :, 1] mask = np.zeros(h.shape, dtype=np.uint8) mask[((h < lower[0]*-1) | (h > upper[0])) & (s > lower[1])] = 255 return cv2.bitwise_and(frame,frame, mask= mask) # 輪郭取得 def getContours(img,t,r): gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) ret, thresh = cv2.threshold(gray, t, 255, cv2.THRESH_BINARY) imgEdge, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 一番大きい輪郭を抽出 contours.sort(key=cv2.contourArea, reverse=True) #一つ以上検出 if len(contours) > 0: cnt = contours[0] # 最小外接円を描く (x,y), radius = cv2.minEnclosingCircle(cnt) center = (int(x),int(y)) radius = int(radius) if radius > r: return cv2.circle(frame,center,radius,(0,255,0),2) else: return frame else: return frame # 白・赤マスク res_white = getMask([0,0,100], [180,45,255]) res_red = getMask([-10,45,30], [170,255,255]) #輪郭取得 getContours(res_white, 45, 75) # (画像, 明度閾値, 最小半径) contours_frame = getContours(res_red, 45, 75) # 再生 cv2.imshow('video',contours_frame) k = cv2.waitKey(25) & 0xFF #Q で終了 if k == ord('q'): break cv2.destroyAllWindows() |
実行してみると・・・
実際は動画で、しっかりと転がる赤いボールを追尾して認識しています。
赤いボールは途中から転がってくるので、それまで白いボールの赤文字のロゴが誤認されてしまいました。
そこで、半径が75以上のものしかボールと認識しない条件を加えています。
赤を識別する問題
他にも少し問題となったのが、赤いボールの識別です。
H(色相)の範囲指定が、前回のようにはいきません。
赤のHは分断されているからです。
赤を指定するときは、0~10 かつ 170 ~ 180 というような条件式が必要です。
上記コードでは、getMask([最小H,最小S,最小V], [最大H,最大S,最大V])という関数を作り、最小Hに負の値を指定すると、赤の条件式に切り替わります。
赤の条件式は「pythonで赤い物体を認識しよう」を参考とさせて頂きました。
同じ色のボールが複数あったときは?
赤と白、一つずつのボール認識は、比較的簡単だと思います。
これが赤6つとかになると、ボール同士がくっついて輪郭が一体化し、誤認しそうです。
くっついたボール、陰になって一部見えないボールなど、イレギュラーな認識については、haar-like機械学習と組み合わせで、地道に認識精度を上げていくのでしょう。
地道なことはせず、次回はボールの軌道描画を行います。
拝見させて頂きましたとても分かりやすく勉強になります.
質問なんですが、私は丸のシールを物体に張り付けて検出したいと思います.そこで色の範囲を赤, 緑, 青と複数してしたいのですがどうしたらよろしいでしょうか教えてください
miura様。色の範囲を赤, 緑, 青と複数指定する方法を、下記に掲載しました。
https://temari.co.jp/blog/2020/12/28/opencv-11/
各色1つのみ検出するコードで、例えば赤の丸シールが2つあった場合、1つしか検出しません。
やりたいことの要件に合っているか分かりませんが、参考になれば幸いです。