我一直在研究一个脚本,该脚本使用cv2的phaseCorrelate
方法计算两个图像之间的旋转偏移。
我有两个图像,第二个是第一个图像的90度旋转版本。加载图像后,我将它们转换为对数极性,然后再将它们传递给phaseCorrelate
函数。
根据我的阅读,我相信这应该会在两个图像之间产生旋转移位。
下面的代码描述了实现。
#bitwise right binary shift function
def rshift(val, n): return (val % 0x100000000)
base_img = cv2.imread('img1.jpg')
cur_img = cv2.imread('dataa//t_sv_1.jpg')
curr_img = rotateImage(cur_img, 90)
rows,cols,chan = base_img.shape
x, y, c = curr_img.shape
#convert images to valid type
ref32 = np.float32(cv2.cvtColor(base_img, cv2.COLOR_BGR2GRAY))
curr32 = np.float32(cv2.cvtColor(curr_img, cv2.COLOR_BGR2GRAY))
value = np.sqrt(((rows/2.0)**2.0)+((cols/2.0)**2.0))
value2 = np.sqrt(((x/2.0)**2.0)+((y/2.0)**2.0))
polar_image = cv2.linearPolar(ref32,(rows/2, cols/2), value, cv2.WARP_FILL_OUTLIERS)
log_img = cv2.linearPolar(curr32,(x/2, y/2), value2, cv2.WARP_FILL_OUTLIERS)
shift = cv2.phaseCorrelate(polar_image, log_img)
sx = shift[0][0]
sy = shift[0][1]
sf = shift[1]
polar_image = polar_image.astype(np.uint8)
log_img = log_img.astype(np.uint8)
cv2.imshow("Polar Image", polar_image)
cv2.imshow('polar', log_img)
#get rotation from shift along y axis
rotation = sy * 180 / (rshift(y, 1));
print(rotation)
cv2.waitKey(0)
cv2.destroyAllWindows()
我不确定如何解释此功能的结果。预期的结果是一个类似于90度的值,但是,我得到了下面的值。
Output: -0.00717516014538333
如何使输出正确?
最佳答案
一种方法,通常称为傅里叶梅林变换的,并且发布为:
B.Srinivasa Reddy和B.N. Chatterji,“基于FFT的平移,旋转和比例不变图像配准技术”,IEEE Trans。在Image Proc。 5(8):1266-1271,1996
使用FFT和对数极坐标变换来获得一个图像的平移,旋转和缩放以匹配另一个图像。我发现this tutorial非常清楚和有用,我将在此处给出一个摘要:
之所以有效,是因为:
如果上面链接的教程不够清楚,则可以查看the C++ code that comes with it或this other Python code。
OP仅对上述方法的旋转方面感兴趣。如果我们可以假设平移为0(这意味着我们知道旋转是围绕哪个点进行的,如果我们不知道原点,则需要将其估计为平移),那么我们就不需要计算幅度FFT(请记住,它用于使问题平移不变),我们可以将对数极坐标变换直接应用于图像。 但请注意,我们需要使用旋转中心作为对数极坐标变换的原点。如果我们另外假设缩放比例为1,则可以通过进行线性极性变换来进一步简化事情。也就是说,半径轴的对数缩放仅是估计缩放所必需的。
我认为OP或多或少正确地做到了这一点。 OP的代码出错的地方是极坐标变换中的半径轴范围。通过一直到图像的两个极端,OpenCV需要用零填充转换后的图像的某些部分。这些部分是由图像的形状决定的,而不是由图像的内容决定的。也就是说,两个极性图像在图像内容和填充的零之间都包含完全相同的尖锐,高对比度的曲线。相位相关使这些曲线对齐,导致旋转估计为0度。图像内容或多或少被忽略了,因为其对比度要低得多。
取而代之的是,使半径轴的范围完全适合图像内的最大圆。这样,输出的任何部分都不需要填充零,并且相位相关可以集中在实际的图像内容上。此外,考虑到两个图像是彼此旋转的版本,图像角落中的数据很可能不匹配,因此根本无需考虑!
这是我根据OP的代码快速实现的代码。我读了Lena,将图像旋转了38度,计算了原始图像和旋转图像的线性极性变换,然后计算了两者之间的相位相关性,然后根据垂直平移确定了旋转角度。结果是37.99560,足够接近38。
import cv2
import numpy as np
base_img = cv2.imread('lena512color.tif')
base_img = np.float32(cv2.cvtColor(base_img, cv2.COLOR_BGR2GRAY)) / 255.0
(h, w) = base_img.shape
(cX, cY) = (w // 2, h // 2)
angle = 38
M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0)
curr_img = cv2.warpAffine(base_img, M, (w, h))
cv2.imshow("base_img", base_img)
cv2.imshow("curr_img", curr_img)
base_polar = cv2.linearPolar(base_img,(cX, cY), min(cX, cY), 0)
curr_polar = cv2.linearPolar(curr_img,(cX, cY), min(cX, cY), 0)
cv2.imshow("base_polar", base_polar)
cv2.imshow("curr_polar", curr_polar)
(sx, sy), sf = cv2.phaseCorrelate(base_polar, curr_polar)
rotation = -sy / h * 360;
print(rotation)
cv2.waitKey(0)
cv2.destroyAllWindows()
这些是代码显示的四个图像窗口:
关于python - 使用相位相关和对数极坐标变换获得旋转位移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57801071/