Ayataの

社会人カジュアルゲーマーのゲームブログです

【Pythonでコーナー検出】理論と実装の勉強

これまでエッジ処理の理論と実装について勉強しました。

ayatalog.hatenablog.jp

今回からコーナー検出について勉強していきたいと思います。

目次


1. コーナー検出の概要

コーナー検出器は、エッジ検出器と並び特徴点を抽出する代表的な検出器です。
wikiを見るとコーナーの定義は、「コーナーとは2つのエッジの交点と定義することができる」とあります。(コーナー検出法 - Wikipedia) 定義通りだとコーナーのような点(x,y方向共に輝度が大きく変わっている点)を見つけるだけなので、実際に物体のコーナーであるかは別途判定が必要になります。しかし、以下に挙げるような検出器ではコーナーを見つけると同時に、コーナーであることの判定を行っています。

2. コーナー検出器の種類

ここでは、いくつかのコーナー検出器を挙げ概要を説明します。しっかり理解できていない部分しかないので、詳しくはこつこつ勉強したいと思います。
有名なものはヘシアンコーナー検出器、モラベックコーナー検出器、ハリスコーナー検出器、FASTコーナー検出器などがあります。

■ヘシアンコーナー検出器
曲率を考える手法。画像をx,y平面 + 輝度の3次元空間としてとらえたときに、コーナーでは曲率が大きくなるとして検出します。

■モラベックコーナー検出器
画像内で小領域を作り、領域を動かします。その時、領域内にコーナーがあればどの方向に動かしても大きく変化し、コーナーが無ければ変化が少ないとして検出します。これを領域の自己相関のスコアとして処理していきます。

■ハリスコーナー検出器
モラベックコーナー検出器の改良版。より直線性を考慮したものになっているらしい、らしい、、

■FASTコーナー検出器
名前の通り高速にコーナーを計算する手法。注目画素をコーナーか非コーナーかに分類するという問題とみなし、決定木により解いていきます。適切な決定木は機械学習により得られます。

3. コーナー検出の雑実装

「コーナーとは2つのエッジの交点と定義することができる」を真に受けてそのまま実装してみます。
この前作ったx,y方向のエッジ処理を組み合わせて、コーナー検出にしていきます。
今回はエッジ処理において求められたエッジ強度に対して、しきい値を設定することでコーナーを検出しました。適当にエッジ強度が255より大きければコーナーとして判定するものにしました。出力結果を以下に示します。入力画像に対してエッジが求められ、エッジの交点がコーナーとして正しく検出されました。

f:id:Ayata:20210320130759p:plain:w400
入力画像
f:id:Ayata:20210320130802p:plain:w400
エッジ処理結果
f:id:Ayata:20210320130813p:plain:w400
コーナー検出結果

↓以下ソースコード

import matplotlib.pyplot as plt
import cv2 #OpenCVのインポート
import numpy as np

#画像パス
FILE_PATH = 'C:/Users/.../aaa.png'

#画像の読み込み
img = cv2.imread(FILE_PATH)

#画像サイズの取得
height, width, color = img.shape
print("width = " + str(height))
print("height = " + str(height))
print("color channel = " + str(color))

#グレースケールへの変換
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#1次微分のフィルタ
#横方向
fil_x = np.array([[0, 0, 0],
                          [-1, 0, 1],
                          [0, 0, 0]])

#縦方向
fil_y = np.array([[0, -1, 0],
                          [0, 0, 0],
                          [0, 1, 0]])

#空間フィルタリングの演算部
N = 1
img_fil_x = np.zeros((height - N, width - N))
img_fil_y = np.zeros((height - N, width - N))

#横方向の演算
for x in range(N, width - N, 1):
    for y in range(N, height - N, 1):
        a = 0
        for i in range(-N, N+1, 1):
            for j in range(-N, N+1, 1):
                a = a + img_gray[y+j, x+i]*fil_x[j+N, i+N]
        img_fil_x[y-1, x-1] = abs(a)

#縦方向の演算
for x in range(N, width - N, 1):
    for y in range(N, height - N, 1):
        a = 0
        for i in range(-N, N+1, 1):
            for j in range(-N, N+1, 1):
                a = a + img_gray[y+j, x+i]*fil_y[j+N, i+N]
        img_fil_y[y-1, x-1] = abs(a)

#コーナーの計算
img_edge_xy = np.zeros((height - N, width - N))
img_corner_xy = np.zeros((height - N, width - N))
for x in range(width - N):
    for y in range(height - N):
        #エッジ強度
        img_edge_xy[x, y] = pow(pow(img_fil_x[y, x], 2) + pow(img_fil_y[y, x], 2), 0.5)

        # コーナー判定(しきい値は適当)
        if pow(pow(img_fil_x[y, x],2) + pow(img_fil_y[y, x],2), 0.5) > 255:
            img_corner_xy[y, x] = pow(pow(img_fil_x[y, x],2) + pow(img_fil_y[y, x],2), 0.5)
        else:
            img_corner_xy[x, y] = 0

まとめ

今回はコーナー検出器の概要の勉強と、コーナー検出器を定義通りに雑実装しました。
次回はヘシアンコーナー検出器について勉強・実装をしていきたいと思います。