Loading [MathJax]/jax/output/HTML-CSS/config.js

2015年10月27日火曜日

特定の色の物体の座標を検出[Python]

1. 概要

PythonのOpenCVを使って特定の色の物体の座標を検出するプログラムのサンプルを書いた.青色の物体がどこにあるかを検出できるようにしてあります.
手法は以下のような手順です

  1. HSV色空間に変換して
  2. 青色を部分を抽出して
  3. 抽出した各部分をラベリングして
  4. ラベリングした塊の面積,座標を計算
  5. 最も面積の大きい座標を返す

2. ソースコード

import cv2
import numpy as np
# 0 <= h <= 179 (色相) OpenCVではmax=179なのでR:0(180),G:60,B:120となる
# 0 <= s <= 255 (彩度) 黒や白の値が抽出されるときはこの閾値を大きくする
# 0 <= v <= 255 (明度) これが大きいと明るく,小さいと暗い
# ここでは青色を抽出するので120±20を閾値とした
LOW_COLOR = np.array([100, 75, 75])
HIGH_COLOR = np.array([140, 255, 255])
# 抽出する青色の塊のしきい値
AREA_RATIO_THRESHOLD = 0.005
def find_specific_color(frame,AREA_RATIO_THRESHOLD,LOW_COLOR,HIGH_COLOR):
"""
指定した範囲の色の物体の座標を取得する関数
frame: 画像
AREA_RATIO_THRESHOLD: area_ratio未満の塊は無視する
LOW_COLOR: 抽出する色の下限(h,s,v)
HIGH_COLOR: 抽出する色の上限(h,s,v)
"""
# 高さ,幅,チャンネル数
h,w,c = frame.shape
# hsv色空間に変換
hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
# 色を抽出する
ex_img = cv2.inRange(hsv,LOW_COLOR,HIGH_COLOR)
# 輪郭抽出
_,contours,hierarchy = cv2.findContours(ex_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# 面積を計算
areas = np.array(list(map(cv2.contourArea,contours)))
if len(areas) == 0 or np.max(areas) / (h*w) < AREA_RATIO_THRESHOLD:
# 見つからなかったらNoneを返す
print("the area is too small")
return None
else:
# 面積が最大の塊の重心を計算し返す
max_idx = np.argmax(areas)
max_area = areas[max_idx]
result = cv2.moments(contours[max_idx])
x = int(result["m10"]/result["m00"])
y = int(result["m01"]/result["m00"])
return (x,y)
def test():
img = cv2.imread("sample.jpg")
# 位置を抽出
pos = find_specific_color(
img,
AREA_RATIO_THRESHOLD,
LOW_COLOR,
HIGH_COLOR
)
if pos is not None:
cv2.circle(img,pos,10,(0,0,255),-1)
cv2.imwrite("result.jpg",img)
def main():
# webカメラを扱うオブジェクトを取得
cap = cv2.VideoCapture(0)
while True:
ret,frame = cap.read()
if ret is False:
print("cannot read image")
continue
# 位置を抽出
pos = find_specific_color(
frame,
AREA_RATIO_THRESHOLD,
LOW_COLOR,
HIGH_COLOR
)
if pos is not None:
# 抽出した座標に丸を描く
cv2.circle(frame,pos,10,(0,0,255),-1)
# 画面に表示する
cv2.imshow('frame',frame)
# キーボード入力待ち
key = cv2.waitKey(1) & 0xFF
# qが押された場合は終了する
if key == ord('q'):
break
cv2.destroyAllWindows()

3. 結果

test()でsamle.jpgに対して処理を行います.またmain()でウェブカメラの画像をリアルタイムで処理します.
以下はsample.jpgに処理を適用した結果です.



4.参考




1 件のコメント:

  1. 昨日からPythonの学習を始めブログを拝見している者です。
    Opencvライブラリを用い、やりたかった内容と酷似していた為、
    とりあえず記載頂いているソースコードを読み解こうと思ったのですが
    上手く実行することができません。
    差し障りなければ以下お答え願えませんでしょうか。
    状況としてはステップオーバー(1行ずつ実行した際に
    defの中身とtestの中身を飛ばして実行しているように見えます、結果は出力されません)

    1.frame(14行目)には何か指定しなければならないのでしょうか
    2.img = cv2.imread("sample.jpg") (51行目)をCドライブ内で
     絶対参照で指定していますがこれは問題でしょうか。(imwriteも同様)
    3.他に当方が指定する項目はありますでしょうか

    初心者の質問で分かり辛く申し訳ありませんが宜しくお願い致します。

    返信削除