2015年10月27日火曜日

画像のORB特徴量を抽出[Python]

1.実行結果

実行してみた結果を載せてみる。とりあえず定番Lenaさん。左右反転して横にしてみたが,まぁそこそこの精度で認識できている。
本当は詳しい説明などをしたいのだが,残念ながらそんな知識はないのでとりあえず公式サイト最強ということでごまかす。リンク先は英語です。

2.ソースコード

まぁコメントは大目に書いたつもりだけれど,「画像を読み込む」→「特徴量抽出」→「類似する特徴量を探す」→「類似する部分を描く」という感じ。類似する部分を描くという作業は実際に何かを作るときは必要ないのだけれども,なんかそれ専用のdrawMatches関数なるものが定義されているので使ってみた。
# -*- coding: utf-8 -*-
import numpy as np
import cv2

# ORB特徴量を抽出するためのもの
orb = cv2.ORB_create()

# 画像を読み込み
img1 = cv2.imread("img1.jpg")
img2 = cv2.imread("img2.jpg")

# 各画像のキーとなる場所(keypoint)とその詳細(description)を計算
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# 特徴量がどれだけ似ているかを調べるためのもの
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# 一致している(類似している)ものを判定
matches = bf.match(des1,des2)

# 似ている点を線で引いてくれる関数
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10],None, flags=2)

# 結果の保存
cv2.imwrite("match.jpg",img3)

特定の色の物体の座標を検出[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()