アナログメーター 4(マッチング)
以前の記事に書いたように「機械式アナログメーターの指示値を推測するアプリケーションに挑戦中です。
機械式アナログメーター(ガスボンベの圧力ゲージ)の指示値を推測すると言う目標に向けて、携帯のカメラで撮影した画像1枚を使い、味見的にどこまでやれそうか感触を確認しています。
前回の物体検出に続いて、OpenCVによるテンプレートマッチングを試しました。
(タイトルは短く抑えるためにマッチングと書きましたにしました。)
テンプレートマッチングは指針の角度から指示値を推測するために、文字盤の中から所定の文字位置を検出するために必要な要素だと考えています。
文字 0 と 10 の位置(座標)と前回の円検出で得た中心座標を結ぶ2本の線分の角度と、前々回の指針の指示角度から、アナログメーターの指示値を推測出来るように思います。
タイトル画像の白い枠がマッチング結果として検出された部分です。
今回はサンプル画像の中から「0」「5」「10」の表示部分を切り抜いてテンプレートにしました。同じ画像の一部をテンプレートにしているのでうまく出来て当然なので、サンプル画像を±15度傾けた画像でもうまく出来るか確認しました。傾けた時に「20」を「10」と間違えたので、画像の左60%だけにして試したところ±15度の範囲で問題なく検出するようになりました。
これなら、前回試した物体検出を行わなくても、テンプレートマッチングだけで十分使えそうな気がします。
いつもながら、Webページを参考にしています。
今回は、こちらのページを主に参考にしました。
ありがとうございます。
Google Colaboratory
自分のPCに様々な環境を作ることなく、いろいろ試せるのでGoogle Colaboratory で実験しています。
ディレクトリー構造は以下の通りです。
My Drive/Colab/meter1 今回のワークディレクトリ
My Drive/Colab/meter1/images1/CVtest3.jpg サンプル画像
My Drive/Colab/meter1/images1/temp/0.jpg テンプレート0
My Drive/Colab/meter1/images1/temp/5.jpg テンプレート5
My Drive/Colab/meter1/images1/temp/10.jpg テンプレート10
サンプル画像は前回同様なので割愛します。
前々回の記事からサンプル画像をダウンロード出来ます。
テンプレート画像は以下の通りです。
ColaboratoryにMy Drive をマウントするために、以下を実行して指示に従います。
(セッション開始後に1回実行します。)
# drive マウント
from google.colab import drive
drive.mount('/content/drive/')
%cd "/content/drive/My Drive/Colab/meter1"
%ls
(最後の2行はワークディレクトリに移動して ls を実行しています。)
ソースコード
次のソースコードで、タイトル画像の結果を得ています。
import cv2
import numpy as np
%cd "/content/drive/My Drive/Colab/meter1"
# Input Image
img = cv2.imread("./images1/CVtest3.jpg",0)
# rotate
#h, w, c = img.shape
h, w = img.shape
center = w / 2, h / 2
ang = 0 # Rotation angle
M = cv2.getRotationMatrix2D(center=center, angle=ang, scale=1)
imgr = cv2.warpAffine(img, M, dsize=(w, h), borderValue=(255, 255, 255))
# trim
# img[top : bottom , left : right]
img = imgr[0 : h, 0: int(0.55*w)]
cv2.imwrite('res_temp1.jpg',img)
# Template Image
TempFilename = []
TempValname = []
for i in range(3):
TempFilename.append(str(i*5)+'.jpg')
TempValname.append('Template'+str(i*5))
# Image read
TempValname[i] = cv2.imread('./images1/temp/' + TempFilename[i],0)
print(TempFilename)
img_temp = img.copy()
# Template matching
for i in range(3):
w, h = TempValname[i].shape[::-1] # Template image size
res = cv2.matchTemplate(img, TempValname[i], cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(str(i) + ' -> max_val: ' + str('{:.3f}'.format(max_val)), ', max_loc: ' + str(max_loc))
# Result image
top_left = max_loc
btm_right = (top_left[0]+w, top_left[1]+h)
#img_temp = img.copy()
cv2.rectangle(img_temp, top_left, btm_right, (255, 0, 0), 2)
cv2.imwrite('res_temp2.jpg',img_temp)
これは±0度のコードです。
途中にある以下の行で回転角度を振っています。
ang = 0 # Rotation angle
実行結果
/content/drive/My Drive/Colab/meter1
['0.jpg', '5.jpg', '10.jpg']
0 -> max_val: 0.985 , max_loc: (198, 494)
1 -> max_val: 0.997 , max_loc: (151, 317)
2 -> max_val: 0.989 , max_loc: (255, 167)
True
当然ですが、ほぼ満点のマッチング結果です。
以下のファイルを出力します。
My Drive/Colab/meter1/res_temp1.jpg 検出準備画像
My Drive/Colab/meter1/res_temp2.jpg タイトル画像
検出準備画像は以下のような結果でした。
角度を振ってみましたが、明るさを振ったらどうなるのか、白黒に変換したら良くなるのかなど試してみたいと思います。
何等か参考に成れば幸いです。
出来ればサポート頂けると、嬉しいです。 新しい基板や造形品を作る資金等に使いたいと思います。