2015年10月27日火曜日

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

 今日はPythonのOpenCVを使って特定の色の物体の座標を検出した。青色の物体がどこにあるかを検出できたりします。

1.アルゴリズム

まずHSV色空間を用いて取り出したい色を抽出します。この場合は青色を抽出しました。
ここで「理想的な状況ですね。羨ましいです」などと言ってはいけません(笑)。ノイズが有る状況でリアルタイムで画像認識している人は本当にすごいと思いますね。
 余談はさておき,抽出した画像は0と1の二値化されたwidth×heightの行列とみなせますね。ここで要素数がwidthの横ベクトルを左からかけたり,要素数がheightの縦ベクトルをかけるとこのようになります。
なんとなくイメージつきますかね。ヒストグラムみたいなものが作れるというわけです。やったぁ。しかも行列の積とかはライブラリにあるので自分で作るよりも間違いなく高速になるはずです。
 そしてこのヒストグラムの中で最も大きい部分を各座標のx,yとするわけです。まぁこれだとノイズがあるとノイズを認識してしまうかもしれないですが……。
 実行結果はこんな感じ。
 ただ実際にやるときはもう少しアルゴリズムを修正する必要がありそうです。1フレーム前の座標をフィルタにするなりした方がいいかもしれません。

2.ソースコード


# -*- coding: utf-8 -*-
import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
    # フレームをキャプチャする
    ret, frame = cap.read()

    # hsv色空間に変換
    hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    
    # 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])
    upper_color = np.array([140, 255, 255])
    
    # 色を抽出する
    ex_img = cv2.inRange(hsv,low_color,upper_color)
    
    # 要素がすべて1の縦ベクトル
    vvec =  np.ones((ex_img.shape[1],1))
    
    # 要素がすべて1の横ベクトル
    hvec =  np.ones((1,ex_img.shape[0]))
    
    # 1次元の縦ベクトル・横ベクトルを掛ける
    hvec = np.dot(hvec,ex_img)
    vvec = np.dot(ex_img,vvec)
    
    # 積の中で最も大きいインデックスを抽出
    x = np.argmax(hvec)
    y = np.argmax(vvec)
    
    # 抽出した座標に丸を描く
    cv2.circle(frame,(x,y),10,(0,255,0))
    
    # 画面に表示する
    cv2.imshow('frame',frame)

    # キーボード入力待ち
    key = cv2.waitKey(1) & 0xFF

    # qが押された場合は終了する
    if key == ord('q'):
        break
    # sが押された場合は保存する
    if key == ord('s'):
        path = "photo.jpg"
        cv2.imwrite(path,frame)


# 後始末
cap.release()
cv2.destroyAllWindows()

0 件のコメント:

コメントを投稿