勉強しないとな~blog

ちゃんと勉強せねば…な電気設計エンジニアです。

OpenCVやってみる-13. Harrisコーナー検出

今回はHarrisコーナー検出をやります。
今更ですが、チュートリアルサイトの順番通りでなく、多少飛ばしている部分もあります。

Harrisコーナー検出 — OpenCV-Python Tutorials 1 documentation

Harrisコーナー検出

理論はチュートリアルサイトに書いてある通りです。
今回はcv2.cornerHarris()関数をさくっと試してみます。
画像は前回と同じ。

import cv2
img1 = cv2.imread('harupan_200317_1.jpg')
img2 = cv2.imread('harupan_210402_1.jpg')
img3 = cv2.imread('harupan_210402_2.jpg')
img1 = cv2.resize(img1, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_AREA)
img2 = cv2.resize(img2, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_AREA)
img3 = cv2.resize(img3, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_AREA)

import numpy as np
img123 = np.hstack((img1,img2,img3))
cv2.imshow('harupan', img123)

f:id:nokixa:20210706090007p:plain

右の2つは同じ台紙を違う角度から撮影しているので、もしかしたらカメラの位置、角度の推定等できるかも。
いや、同じパターンがたくさんあるから難しいのか?
同じシールの検出等できるだろうか。

cv2.cornerHarris()ではいくつかパラメータがありますが、チュートリアルサイトと同じ値でやってみます。

img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
img3_gray = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY)

img1_harris = cv2.cornerHarris(img1_gray, 2, 3, 0.04)
img2_harris = cv2.cornerHarris(img2_gray, 2, 3, 0.04)
img3_harris = cv2.cornerHarris(img3_gray, 2, 3, 0.04)

結果は、元画像と同じサイズのndaray配列となります。

>>> type(img1_harris)
<class 'numpy.ndarray'>
>>> img1_harris.shape
(403, 302)

特徴点を画像上に描画するとこんな感じ。

img1_cp = img1.copy()
img2_cp = img2.copy()
img3_cp = img3.copy()

img1_cp[img1_harris > 0.01*img1_harris.max()] = [0,255,0]
img2_cp[img2_harris > 0.01*img2_harris.max()] = [0,255,0]
img3_cp[img3_harris > 0.01*img3_harris.max()] = [0,255,0]

img123 = np.hstack((img1_cp, img2_cp, img3_cp));
cv2.imshow("Images", img123)

チュートリアルでは、検出点画像に膨張処理をして見やすくしていましたが、 今回はまずそのまま見てみました。細かい特徴点があるかもしれないので。

f:id:nokixa:20210708231025p:plain

シールや台紙の細かい模様が特徴点として抽出されています。
よく見ると、台紙のコーナーも検出されているようです。

膨張処理をして表示してみます。

img1_harris = cv2.dilate(img1_harris, None)
img2_harris = cv2.dilate(img2_harris, None)
img3_harris = cv2.dilate(img3_harris, None)
img1_cp[img1_harris > 0.01*img1_harris.max()] = [0,255,0]
img2_cp[img2_harris > 0.01*img2_harris.max()] = [0,255,0]
img3_cp[img3_harris > 0.01*img3_harris.max()] = [0,255,0]
img123 = np.hstack((img1_cp, img2_cp, img3_cp));
cv2.imshow("Images", img123)

f:id:nokixa:20210709090829p:plain

台紙のコーナーがちょっと分かりやすくなりました。


パラメータ変えてみる

シールの細かい文字しか特徴として出て来ませんでしたが、シールの点数のほうを 特徴として抽出できないだろうか。

cv2.cornerHarrisの引数の詳細を見てみましたが、blockSizeは使えなさそう。

特徴検出 — opencv 2.2 documentation

画像フィルタリング — opencv 2.2 documentation

ksizeを7にしてみたらどうだろう?
これはSobelフィルタのカーネルサイズになります。
カーネルサイズ3以外でのカーネルがどうなるのかというと、
以下のサイトにカーネルの取得方法が書かれていました。
cv2.getDerivKernels関数を使えばいいようです。結果も書かれています。

python - What are the kernel coefficients for OpenCV's Sobel filter for sizes larger than 3 x 3? - Stack Overflow

このカーネルの感じからすると、細かい変化はならされるように思います。 カーネルサイズ変更は有効なのでは?

img1_harris = cv2.cornerHarris(img1_gray, 2, 7, 0.04)
img2_harris = cv2.cornerHarris(img2_gray, 2, 7, 0.04)
img3_harris = cv2.cornerHarris(img3_gray, 2, 7, 0.04)
img1_harris = cv2.dilate(img1_harris, None)
img2_harris = cv2.dilate(img2_harris, None)
img3_harris = cv2.dilate(img3_harris, None)
img1_cp = img1.copy()
img2_cp = img2.copy()
img3_cp = img3.copy()
img1_cp[img1_harris > 0.01*img1_harris.max()] = [0,255,0]
img2_cp[img2_harris > 0.01*img2_harris.max()] = [0,255,0]
img3_cp[img3_harris > 0.01*img3_harris.max()] = [0,255,0]
img123 = np.hstack((img1_cp, img2_cp, img3_cp));
cv2.imshow("Images", img123)

f:id:nokixa:20210710003005p:plain

細か過ぎるパターンは特徴点としては検出されないようになっています。
一応期待通り。

ここまで

Harrisコーナー検出はこのへんにしておきます。
他にも特徴点抽出の方法が色々紹介されていたので、引き続きやってみようと思います。