Python OpenCV Huモーメント不変量で画像マッチング


Python + Opencv3.1 で Huモーメント不変量から類似画像のマッチングを試してみました。

OpenCV での類似画像比較は、この cv2.matchShapes でも簡単に比較できるので、まずはこれで試してみました。


def matchshapes2(img1, img2):
    # 二値化
    ret, img_dst1 = cv2.threshold(img1, thresh, max_pixel, 0)
    ret, img_dst2 = cv2.threshold(img2, thresh, max_pixel, 0)
    im,contours,hierarchy = cv2.findContours(img_dst1,2,1)
    cnt1 = contours[0]
    im,contours,hierarchy = cv2.findContours(img_dst2,2,1)
    cnt2 = contours[0]
    return cv2.matchShapes(cnt1,cnt2,1,0.0)

しかしこの方法だと比較する画像が輪郭以外に特徴がないシルエット画像だったせいか、なんとなく精度が今ひとつでした。

そこで、こちら (http://d.hatena.ne.jp/m-a-o/20131104/p2) を参考にして、マッチング部分を自前で書いてみました。
このコードは、マッチング以外に前処理として輪郭を検出した画像の輪郭線の内側を塗りつぶしてしまう処理も含まれています。


def matchshapes(img1, img2, method = 1):

    # 比較元画像の輪郭を取って塗りつぶし
    height, width = img2.shape[:2]
    checkImage = np.zeros((height, width, 1), np.uint8)
    checkImage = 255 - checkImage
    ret, th = cv2.threshold(img2, thresh, max_pixel, cv2.THRESH_BINARY_INV)
    im, contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    checkImage = cv2.drawContours(checkImage, contours, -1, (0,0,0), -1)
    checkImage = 255 - checkImage

    # Hu
    m1 = cv2.moments(img1)
    hua = cv2.HuMoments(m1)
    m2 = cv2.moments(checkImage)
    hub = cv2.HuMoments(m2)

    def h2m(x):
        if x==0:
           return 0.0
        elif x>0:
           return 1.0/log(x)
        else:
           return -1.0/log(-x)

    s = []
    for (x1,x2) in zip(hua.T[0],hub.T[0]):
        s.append(abs(h2m(x1)-h2m(x2)))

    d = sum(s)
    return d

これだとたまに変な結果が返って来ることもありますが cv2.matchShapes のときよりはだいぶいい感じで検出できるようになったので、これをベースにもっと精度を上げる方法を探していきたいと思います。