コンピュータサイエンス系勉強ノート

計算機科学に限らず日々学んだことを色々まとめていきます

Pythonでテンプレートマッチング実装

Pythonでテンプレートマッチングを実装しました.類似度尺度には,正規化相互相関(NCC)・相互相関係数(ZNCC)・差の二乗和(SSD)・差の絶対和(SAD)の四種類を使用しました.

使用データ

画像は以下の画像を使用.
f:id:clientver2:20151112001032j:plain

マッチング対象画像

f:id:clientver2:20151112001034j:plain

パターン画像

正規化相互相関(NCC)

マッチングをかける画像と,パターン画像の輝度値をベクトルとみなしてコサイン類似度を求める感じ

def NCC(image1, image2):
    vec1, vec2 = image1.reshape(-1), image2.reshape(-1)
    numer = np.dot(vec1, vec2.T)
    denom = np.sqrt(np.sum(vec1 ** 2)) / np.sqrt(np.sum(vec2 ** 2))
    if denom == 0: return 0
    return numer / denom

def matching(image1, image2):
    image = image1.astype(np.double)
    pattern = image2.astype(np.double)
    height1, width1 = image.shape
    height2, width2 = pattern.shape
    output = np.zeros(image.shape)

    for i in range(height2 / 2, height1 - height2 / 2):
        for j in range(width2 / 2, width1 - width2 / 2):
            score = NCC(image[i-height2/2:i+height2/2+1, j-width2/2:j+width2/2+1], pattern)
            output[i,j] = score

    output /= np.max(output)
    maxidx = np.unravel_index(output.argmax(), output.shape)

    result = cv2.cvtColor(image1, cv2.COLOR_GRAY2RGB)
    cv2.rectangle(result, (maxidx[1] - width2 / 2, maxidx[0] - height2 / 2), (maxidx[1] + width2, maxidx[0] + height2), (0,255,0), 1)
    cv2.imshow("matching", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

相互相関係数(ZNCC)

平均値を引いてます.明るさ変化に対して強くなるようです.

def ZNCC(image1, image2):
    vec1, vec2 = image1.reshape(-1), image2.reshape(-1)
    vec1, vec2 = vec1 - np.mean(vec1), vec2 - np.mean(vec2)
    numer = np.dot(vec1, vec2.T)
    denom = np.sqrt(np.sum(vec1 ** 2)) / np.sqrt(np.sum(vec2 ** 2))
    if denom == 0: return 0
    return numer / denom

def matching(image1, image2):
    image = image1.astype(np.double)
    pattern = image2.astype(np.double)
    height1, width1 = image.shape
    height2, width2 = pattern.shape
    output = np.zeros(image.shape)

    for i in range(height2 / 2, height1 - height2 / 2):
        for j in range(width2 / 2, width1 - width2 / 2):
            score = ZNCC(image[i-height2/2:i+height2/2+1, j-width2/2:j+width2/2+1], pattern)
            output[i,j] = score

    output /= np.max(output)
    maxidx = np.unravel_index(output.argmax(), output.shape)

    result = cv2.cvtColor(image1, cv2.COLOR_GRAY2RGB)
    cv2.rectangle(result, (maxidx[1] - width2 / 2, maxidx[0] - height2 / 2), (maxidx[1] + width2, maxidx[0] + height2), (0,255,0), 1)
    cv2.imshow("matching", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

差の二乗和(SSD)

def SSD(image1, image2):
    vec1, vec2 = image1.reshape(-1), image2.reshape(-1)
    return np.sum((vec1 - vec2) ** 2)

def matching(image1, image2):
    image = image1.astype(np.double)
    pattern = image2.astype(np.double)
    height1, width1 = image.shape
    height2, width2 = pattern.shape
    output = np.ones(image.shape) * 10000

    for i in range(height2 / 2, height1 - height2 / 2):
        for j in range(width2 / 2, width1 - width2 / 2):
            score = SSD(image[i-height2/2:i+height2/2+1, j-width2/2:j+width2/2+1], pattern)
            output[i,j] = score

    maxidx = np.unravel_index(output.argmin(), output.shape)

    result = cv2.cvtColor(image1, cv2.COLOR_GRAY2RGB)
    cv2.rectangle(result, (maxidx[1] - width2 / 2, maxidx[0] - height2 / 2), (maxidx[1] + width2, maxidx[0] + height2), (0,255,0), 1)
    cv2.imshow("matching", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

差の絶対和(SAD)

def SAD(image1, image2):
    vec1, vec2 = image1.reshape(-1), image2.reshape(-1)
    return np.sum(np.abs(vec1 - vec2))

def matching(image1, image2):
    image = image1.astype(np.double)
    pattern = image2.astype(np.double)
    height1, width1 = image.shape
    height2, width2 = pattern.shape
    output = np.ones(image.shape) * 10000

    for i in range(height2 / 2, height1 - height2 / 2):
        for j in range(width2 / 2, width1 - width2 / 2):
            score = SAD(image[i-height2/2:i+height2/2+1, j-width2/2:j+width2/2+1], pattern)
            output[i,j] = score

    maxidx = np.unravel_index(output.argmin(), output.shape)

    result = cv2.cvtColor(image1, cv2.COLOR_GRAY2RGB)
    cv2.rectangle(result, (maxidx[1] - width2 / 2, maxidx[0] - height2 / 2), (maxidx[1] + width2, maxidx[0] + height2), (0,255,0), 1)
    cv2.imshow("matching", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

出力結果

4つともこんな感じで出力されます.矩形の位置も同じになりました.どの方法がいいのかはいまいち分からなかったので,また色々試したいと思います.
f:id:clientver2:20151112003802p:plain

参考文献

中京大学 工学部 橋本学 テンプレートマッチングの魅力
http://isl.sist.chukyo-u.ac.jp/Archives/SSII2013TS-Hashimoto.pdf