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

2024-05-05

我一直在编写一个脚本,它使用 cv2 计算两个图像之间的旋转位移phaseCorrelate method.

我有两张图像,第二张是第一张图像的 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. 斯里尼瓦萨·雷迪 (B. Srinivasa Reddy) 和 B.N. Chatterji,“基于 FFT 的平移、旋转和比例不变图像配准技术”,IEEE 传输。关于图像处理。5(8):1266-1271, 1996

使用 FFT 和对数极坐标变换来获得一幅图像的平移、旋转和缩放以匹配另一幅图像。我发现本教程 https://sthoduka.github.io/imreg_fmt/为了非常清晰和翔实,我将在这里进行总结:

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

这是有效的,因为:

  1. FFT 的幅度是平移不变的,我们可以只关注缩放和旋转,而不用担心平移。请注意,图像的旋转与 FFT 的旋转相同,并且图像的缩放与 FFT 的缩放相反。

  2. 对数极坐标变换将旋转转换为垂直平移,并将缩放转换为水平平移。相位相关性使我们能够确定这些平移。将它们转换为旋转和缩放并非易事(尤其是缩放很难正确,但一些数学可以说明方法)。

如果上面链接的教程不够清楚,可以看一下附带的C++代码 https://github.com/sthoduka/imreg_fmt/, or at 其他 Python 代码 https://www.lfd.uci.edu/~gohlke/code/imreg.py.html.


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()

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用相位相关和对数极坐标变换获得旋转位移 的相关文章

随机推荐

  • 为什么 Dart 中的原生包装函数与非常轻量级的“DEFINE NATIVE ENTRY”函数相比如此重量级?

    我不明白 为什么要这样保证 这是自定义本机函数的包装器dart runtime vm native entry cc 它适用于想要编写的 Dart 程序员native extensions void NativeEntry NativeCa
  • Android 在连接 Socket 时出现错误

    在阅读了一些express io文档并成功连接到之后 我尝试使用nodejs和express io编写简单的应用程序http chat socket io在命令行中运行下面的代码并打开后 我找到了使用 nodejs 和express io
  • 将区间映射到更小的区间的算法

    我尝试搜索 但由于问题的性质 我无法找到满意的内容 我的问题如下 我试图将 0 到 2000 范围内的数字 尽管理想情况下上限是可调的 映射到 10 到 100 范围内的更小的区间 上限将映射 2000 gt 100 和下限也是如此 除此之
  • WPF 图像控件源绑定

    我是 WPF 和 C 的新手 我尝试实现以下功能 但在多次尝试后失败了 谁能帮我吗 我有一个图像控件
  • Amazon EC2 - Apache 服务器重启问题

    当我运行这个命令时 sudo etc init d httpd restart 它给出以下错误 停止 httpd 失败 启动 httpd 98 地址已在使用中 make sock 无法绑定到地址 80 98 地址已在使用 make sock
  • MVC 4 使用 Bootstrap 编辑模态表单

    我正在使用 MVC 4 和实体框架来开发 Intranet Web 应用程序 我有一个可以通过编辑操作进行修改的人员列表 我想通过使用模态表单使我的应用程序更加动态 所以我尝试将我的编辑视图放入我的 Bootstrap 模式中 我有两个问题
  • 将 nHibernate 3.x 与 Jet 驱动程序结合使用 (Microsoft Access)

    我正在开发一个 nHibernate 项目 该项目使用 Access 数据库作为数据源 不幸的是 我在运行时遇到问题 因为我找不到支持 nHibernate 3 x 的 Jet 驱动程序 我已经从 trunk 下载了源代码并编译了它 但事实
  • JAGS 中的柯西先验

    我正在使用 rJAGS 构建多级贝叶斯模型 并且我想为我的几个参数指定柯西先验 有没有办法在 JAGS 中做到这一点 或者我需要切换到 STAN 吗 我的 JAGS 模型如下 我想更换dnorm柯西分布 但 JAGS 找不到标准R柯西分布
  • 按属性值选择 XML 节点

  • Haxe 摘要 - 使用 @:from 时可以隐式转换数组吗?

    我试图将一种类型的数组视为另一种 抽象 类型的数组 当我使用抽象的基础类型时 它工作得很好 但是当我尝试使用另一种类型 使用定义的 from关键字 我构建失败 如果我使用显式的 它会起作用cast 但我想知道 有什么办法可以解决这个问题 我
  • 以编程方式创建 UILabel

    我通过代码执行了以下操作 UILabel label UILabel alloc initWithFrame CGRectMake 40 70 300 50 label backgroundColor UIColor clearColor
  • 比较周期性数据的快速方法

    假设我有任意类型的数据集 A B C D 并且我想将其与另一个数据集进行比较 我希望 A B C D B C D A C D A B 和 D A B C 的比较成立 但是不适用于 A C B D 或任何其他未类似排序的集合 有什么快速方法可
  • 在 Drupal 8 中如何在保存节点之前操作值?

    我有一个编辑节点表单 当用户输入新值并单击提交来编辑节点时 我首先想取回旧节点 操作该值 然后保存 更新节点 以下是我的解决方案 但它不起作用 function custom module form node form alter form
  • C 中有数组大小/长度的快捷方式吗?

    有什么方法可以加快 C 中获取数组大小的速度吗 打字sizeof array sizeof int 每次都会变老 有没有 C 库有类似的东西 length或者有什么方法我可以定义sizeof array sizeof int 作为某种较短的
  • Visual Studio 模板 - 添加其他预先存在的项目

    我正在开发一个 Visual Studio 模板 其中生成的项目依赖于许多引用 这些引用恰好是源代码控制下的其他项目 问题是如何在我的 ProjectGroup 模板中进行设置 例如 如果我在 C Stuff MyUtilityProjec
  • Javascript .includes 函数无法与对象数组一起正常工作[重复]

    这个问题在这里已经有答案了 我有一个正在使用的对象数组 includes 功能 我正在使用数组中的对象搜索该数组 对象是相同的 但似乎没有匹配项 我已将问题复制到这把小提琴 https jsfiddle net 6dua0u0n 代码也在下
  • Sympy autowrap (cython):为 sympy.Max、sympy.Heaviside 定义“助手”

    我有一个 sympy Matrix 称为 J sym 我想自动包装它 最好使用 cython 后端 相应的符号存储在列表list args中 然而 我遇到的问题是显然不支持某些 sympy 函数 在我的例子中特别是 sympy Max 和
  • 尝试在 jQuery show() 周围的事件之前和之后触发

    我正在尝试在某些第 3 方代码出现模式对话框后运行我们的 JavaScript 片段 我看见劫持 jQuery show 函数的一个非常巧妙的想法 https stackoverflow com a 1225238 135968 但不幸的是
  • 在 Scala 中将 Map[String, String] 转换为 Map[String, Int]

    我有一个 Map 其中键是 String 值是 Int 但表示为 String scala gt val m Map a gt 1 b gt 2 c gt 3 m scala collection immutable Map String
  • 使用相位相关和对数极坐标变换获得旋转位移

    我一直在编写一个脚本 它使用 cv2 计算两个图像之间的旋转位移phaseCorrelate method 我有两张图像 第二张是第一张图像的 90 度旋转版本 加载图像后 我将它们转换为对数极坐标 然后将它们传递到phaseCorrela