python - 使用相位相关和对数极坐标变换获得旋转位移

标签 python opencv image-processing computer-vision

我一直在研究一个脚本,该脚本使用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非常清楚和有用,我将在此处给出一个摘要:

  • 计算两个图像的FFT的幅度(首先应用开窗函数,以避免FFT的周期性问题)。
  • 计算频域图像幅度的对数极坐标变换(通常首先应用高通滤波器,但我没有看到它的用处)。
  • 计算两者之间的互相关(实际上是相位相关)。这导致对规模和旋转的了解。
  • 将缩放和旋转应用于原始输入图像之一。
  • 在对缩放和旋转进行校正之后,计算原始输入图像的互相关(实际上是相位相关)。这导致了翻译知识。

  • 之所以有效,是因为:
  • FFT的大小是平移不变的,我们可以只关注缩放和旋转,而不必担心平移。注意,图像的旋转与FFT的旋转相同,并且图像的缩放与FFT的缩放相反。
  • 对数极坐标转换将旋转转换为垂直平移,并将缩放比例转换为水平平移。相位相关使我们能够确定这些转换。将它们转换为旋转和缩放是不平凡的(特别是缩放很难正确,但是一些数学方法可以说明这一点)。

  • 如果上面链接的教程不够清楚,则可以查看the C++ code that comes with itthis 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()
    

    这些是代码显示的四个图像窗口:

    The four images shown by the code above

    关于python - 使用相位相关和对数极坐标变换获得旋转位移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57801071/

    相关文章:

    python - 如何使用 Python 3 将信息从 Tkinter 中的表单发送到 ScrolledText?

    python - 我在终端应用程序中工作(Python+MySQL)

    python - Tkinter 窗口中 cv2 图像上的鼠标事件

    Android + OpenCV + 人脸检测 + 自定义布局

    c - 在 OpenCV 中使用直方图数据跟踪对象

    java - 在 Java 中读取图像文件的方式有什么区别?

    c++ - 调用 cvSet2D() 设置图像的像素值返回值 0

    python - 是否有任何 python 机器学习库可以返回线性 svm 的系数或几何边距?

    python - Django queryset - 从 json 对象转换

    python - OpenCv Python 颜色检测