静寂とプログラミング

技術について書いたり、日常について書いたり

画像局所記述子 - Harris Corner 検出器

はじめに

実践コンピュータビジョンに書かれているものを自分の整理のために、まとめたものです。また、他の言語で書き直することで理解も深まるので、今回はSwiftで書き直したいと思います。(まだ、未完記事です)

画像の局所記述子とは

画像間の対応づけをするために使われる。 そのなかでも一番簡単なHarrisコーナー検出器について書きたいと思います。


Harrisコーナー検出器

判別関数
以下の関数が判別関数である。

    \frac{\det(M_1) }{\mathrm{Tr}(M_1)}

  1. 微分係数を計算する
  2. Harris行列の成分を計算する
  3. 判別式と対角成分(判別関数)を計算する

閾値を超えるコーナー候補を調べる
次に、判別関数によって各ピクセルのHarris行列を求めた画像と、Thersholdを使って、コーナーを 画像にプロットする。 1. 閾値を超えるコーナー候補を見つける 2. 候補の座標をとる 3. 候補の値を得る 4. 候補をソートする 5. 許容する点の座標を配列に格納する 6. 最小距離を考慮しながら、最良の点を得る


実装

インポートするライブラリ

from scipy.ndimage import filters # 微分係数を求めるために使用
import numpy as np
from matplotlib import pyplot as plt


判別関数によって出力された値を返す

def compute_harris_response(img, sigma=3):
    """
    グレイスケール画像の各ピクセルについて
    Harrisコーナー検出器の応答関数を定義する
    :param img: グレイスケール画像
    :param sigma:
    :return: Harris画像
    https://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.ndimage.filters.gaussian_filter.html
    """

    # 微分係数
    img_x = np.zeros(img.shape)
    filters.gaussian_filter(img, (sigma, sigma), (0, 1), img_x)
    img_y = np.zeros(img.shape)
    filters.gaussian_filter(img, (sigma, sigma), (0, 1), img_y)
    # Harris行列の成分を計算する
    Wxx = filters.gaussian_filter(img_x * img_x, sigma)
    Wxy = filters.gaussian_filter(img_x * img_y, sigma)
    Wyy = filters.gaussian_filter(img_y * img_y, sigma)
    # 判別式と対角成分(判別関数)を計算する
    Wdet = Wxx * Wyy - Wxy * 2
    Wtr = Wxx + Wyy

    return Wdet / Wtr


Harris応答画像からコーナーを返す

def get_harris_points(harris_img, min_dist=10, threshold=0.1):
    """
    :param harris_img: ハリス画像
    :param min_dist: コーナーや画像今日から分離する最小ピクセル数(値範囲が謎)、おそらく[0,1]
    :param threshold: コーナー候補を絞るための閾値(値範囲が謎)
    :return: 最小距離を考慮した、最良の座標配列
    """
    # 閾値を超えるコーナー候補を見つける
    corner_threshold = harris_img.max() * threshold
    harris_img_t = (harris_img > corner_threshold) * 1
    # 候補の座標をとる
    # ここの演算がよくわからん..
    coords = np.array(harris_img_t.nonzero()).T
    # 候補の値を得る
    candidate_values = [harris_img[c[0], c[1]] for c in coords]
    # 候補をソートする
    index = np.argsort(candidate_values)
    # 許容する点の座標を配列に格納する
    allowed_locations = np.zeros(harris_img.shape)
    allowed_locations[min_dist:-min_dist, min_dist:-min_dist] = 1
    # 最小距離を考慮しながら、最良の点を得る
    filtered_coords = []
    for i in index:
        if allowed_locations[coords[i, 0], coords[i,1]] == 1:
            filtered_coords.append(coords[i])
            allowed_locations[(coords[i,0]-min_dist):(coords[i,0]+min_dist),
                (coords[i,1]-min_dist):(coords[i,1]+min_dist)] = 0

    return filtered_coords


ついでにプロットする関数

def plot_harris_points(image, filtered_coords):
    """
    :param image: グレイスケール画像
    :param filtered_coords: 点の描画
    """
    plt.figure()
    plt.gray()
    plt.imshow(image)
    plt.plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')
    plt.axis('off')
    plt.show()

画像間の対応づけ

ここは後日...

Swiftでやってみる

ここは後日...