こんにちは。
「喫茶店探しを自動化したい」の記事のサードパーティAPIを使うと、学習させた形が画像全体のどこにあるのか…の大体の位置を取得できます。
ここで、四隅の点をきっちり取れたらできることも拡がりそうだな?って思ったので少し調査と試作を進めてみました。今回は喫茶店のマッチのパッケージを認識してみます。
使うマッチはこちらです!
AKAZEアルゴリズムを採用
OpenCVではSIFTやSURFなどの特徴点抽出方法が使えますが、どうやらどちらもライセンス問題(少し面倒くさそう)があるそうです。OpenCV3のAKAZEはそれらの問題を解決したバージョンとのことですので、これを採用したいと思います。
参考までに環境を載せておきます。入れ方使い方は検索すると出てくると思いますので、ここでは割愛します。特にPython実行前に正しくパスを通すように気をつけましょう。
Ubuntu 16.04.3
Python 3.5.2
OpenCV 3.4.0
公式のサンプルを改変した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 |
import numpy as np import cv2 import sys MIN_MATCH_COUNT = 10 args = sys.argv img1 = cv2.imread(args[1],0) #packageImage img2 = cv2.imread(args[2],0) #userImage akaze = cv2.AKAZE_create() kp1, des1 = akaze.detectAndCompute(img1,None) kp2, des2 = akaze.detectAndCompute(img2,None) bf = cv2.BFMatcher() matches = bf.knnMatch(des1,des2,k = 2) good = [] for m,n in matches: if m.distance < 0.7*n.distance: good.append(m) if len(good)>MIN_MATCH_COUNT: src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0) matchesMask = mask.ravel().tolist() h,w = img1.shape pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2) dst = cv2.perspectiveTransform(pts,M) print('true') print(np.int32(dst)[0][0][0],np.int32(dst)[0][0][1]) print(np.int32(dst)[1][0][0],np.int32(dst)[1][0][1]) print(np.int32(dst)[2][0][0],np.int32(dst)[2][0][1]) print(np.int32(dst)[3][0][0],np.int32(dst)[3][0][1]) else: print('false') |
第1引数に先ほどのマッチのパッケージ画像、第2引数にそのマッチが写り込んだ画像を渡して実行すると四隅の点が返ってきていそうな感じがします。
周囲の色だけ抜いてみる
四隅が取れるならばそこに何かを被せたり切り抜いたりいろいろできます。
今回はimageMagickを使って、マッチの周囲の色だけモノクロにしてみます。
コマンドでもできますが、PHPで実行できるように組んだのでソースを載せておきます。エラー処理は適宜行なってくださいませ。
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 |
//パッケージ位置認識 $command = 'python get_package_xy_akaze.py park.jpg user.jpg'; exec($command,$res1,$res2); $package_xy = array(); for($i=1;$i<5;$i++){ $res1[$i] = str_replace('(','',$res1[$i]); $res1[$i] = str_replace(')','',$res1[$i]); $res1[$i] = str_replace(' ','',$res1[$i]); $tmp = explode(',',$res1[$i]); $package_xy[] = array((int)$tmp[0],(int)$tmp[1]); } //誤認識検知 if((abs($package_xy[0][1]-$package_xy[1][1]) < 50) || abs($package_xy[1][0]-$package_xy[2][0]) < 50){ echo 'パッケージ位置座標が小さすぎる可能性があります。'; exit; } //画像加工 $original_size = getimagesize('user.jpg'); $command = 'convert -size '.$original_size[0].'x'.$original_size[1].' xc:none -draw \'polygon '.($package_xy[0][0]).','.($package_xy[0][1]).' '.($package_xy[1][0]).','.($package_xy[1][1]).' '.($package_xy[2][0]).','.($package_xy[2][1]).' '.($package_xy[3][0]).','.($package_xy[3][1]).'\' tmp1.png'; exec($command,$res1,$res2); $command = 'convert user.jpg tmp1.png -compose CopyOpacity -composite tmp2.png'; exec($command,$res1,$res2); $command = 'convert user.jpg -type GrayScale tmp3.png'; exec($command,$res1,$res2); $command = 'composite tmp2.png tmp3.png -compose over tmp4.png'; exec($command,$res1,$res2); |
2〜11行目まででPythonの実行結果から四隅の座標を数値として配列に保管します。
14〜17行目では誤認知を避けるためにあまりにも小さい認識結果をエラーとしています。
20〜28行目ではconvertコマンド(imageMagick)を使って画像をマスク化やモノクロ化、合成しています。
マッチ以外の色が綺麗に抜けました(゜-゜)