Products Using Phase-Based Image Matching(ページの下の方に日本語文章)辺りを参考にOpenCVのphaseCorrelateとwarpPolarを使って書いてみた。
縮尺についてはあまり芳しくない。
入力は同一サイズの正方形であること。
def ripoc(a, b, m = None): g_a = np.asarray(cv2.cvtColor(a, cv2.COLOR_BGR2GRAY), 'float') g_b = np.asarray(cv2.cvtColor(b, cv2.COLOR_BGR2GRAY), 'float') h, w = g_a.shape hy = np.hanning(h) hx = np.hanning(w) hw = hy.reshape(h, 1)*hx f_a = np.fft.fftshift(np.log(np.abs(np.fft.fft2(g_a*hw)))) f_b = np.fft.fftshift(np.log(np.abs(np.fft.fft2(g_b*hw)))) if not m: l = np.sqrt(w*w + h*h) m = l/np.log(l) center = (w/2, h/2) flags = cv2.INTER_LANCZOS4 + cv2.WARP_POLAR_LOG p_a = cv2.warpPolar(f_a, (w, h), center, m, flags) p_b = cv2.warpPolar(f_b, (w, h), center, m, flags) (x, y), e = cv2.phaseCorrelate(p_a, p_b, hw) angle = y*360/h scale = (np.e)**(x/m) M = cv2.getRotationMatrix2D(center, angle, scale) t_b = cv2.warpAffine((g_b), M, (w, h)) (x, y), e = cv2.phaseCorrelate(g_a, t_b) return x, y, angle, scale
素材はLena。Mandrill。(2021-10-18変更)
元画像を0.75倍、時計回りに12度回転、右に15ピクセル、下に10ピクセル移動したものと比較した。
img1 = cv2.imread("mandrill.png") img2 = cv2.imread("mandrill-s.png") x, y, angle, scale = ripoc(img1, img2) print(x, y, angle, scale)
23.06948108485352 8.047739170155523 12.017118263688051 1.3187003682512768
h, w, ch = img1.shape M = cv2.getRotationMatrix2D((w/2,h/2), angle, scale) M[0][2] -= x M[1][2] -= y dst = cv2.warpAffine(img2, M, (w, h)) cv2.imwrite("mandrill-t.png", dst)