Loading [MathJax]/extensions/tex2jax.js

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]

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.参考