使用python和互相关进行图像配准

fei*_*ann 10 python image cross-correlation

我得到了两张图片,显示了相同的内容:2D高斯形斑点.我把这两个16位的png文件称为"left.png"和"right.png".但是,通过稍微不同的光学设置获得它们,相应的斑点(物理上相同)出现在略微不同的位置.意味着右边以非线性方式略微拉伸,扭曲或左右.因此,我希望从左到右进行转换.

因此,对于左侧的每个像素,其x和y坐标,我想要一个函数,给出位移矢量的分量,指向右侧的相应像素.

在前一种方法中,我试图获得相应斑点的位置以获得相对距离deltaX和deltaY.然后我将这些距离拟合到taylor扩展到T(x,y)的二阶,给出了左边每个像素(x,y)的位移矢量的x和y分量,指向相应的像素(x',y')在右边.

为了得到更一般的结果,我想使用归一化的互相关.为此,我将左边的每个像素值与右边的相应像素值相乘,并将这些乘积相加.我正在寻找的转换应该连接最大化总和的像素.因此,当总和最大化时,我知道我将相应的像素相乘.

我真的尝试了很多,但没有管理.我的问题是,如果你们中的某个人有想法或做过类似的事情.

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()
Run Code Online (Sandbox Code Playgroud)

如果我能更清楚地说明这个问题,请告诉我.我仍然需要查看如何使用乳胶发布问题.

非常感谢您的投入.

剩下 对

[left.png] http://i.stack.imgur.com/oSTER.png [right.png] http://i.stack.imgur.com/Njahj.png

我担心,在大多数情况下,16位图像看起来只是黑色(至少在我使用的系统上):(但当然有数据存在.

更新1

我试着澄清我的问题.我正在寻找一个矢量场,其位移矢量从left.png中的每个像素指向right.png中的相应像素.我的问题是,我不确定我的约束.

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()
Run Code Online (Sandbox Code Playgroud)

其中向量r(分量x和y)指向left.png中的像素,向量r-prime(分量x-prime和y-prime)指向right.png中的对应像素.每个r都有一个位移矢量.

我之前做的是,我发现了矢量场d的手动组件并将它们拟合到第二度的多项式:

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()
Run Code Online (Sandbox Code Playgroud)

所以我装:

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()
Run Code Online (Sandbox Code Playgroud)

import numpy as np
import Image

left = np.array(Image.open('left.png'))
right = np.array(Image.open('right.png'))

# for normalization (http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation)    
left = (left - left.mean()) / left.std()
right = (right - right.mean()) / right.std()
Run Code Online (Sandbox Code Playgroud)

你能理解这个吗?是否有可能得到所有delta-x(x,y)和delta-y(x,y)的互相关?如果相应的像素通过位移矢量连接在一起,那么互相关应该最大化,对吗?

更新2

所以我想到的算法如下:

  1. Deform right.png
  2. 获得互相关的价值
  3. 进一步变形right.png
  4. 获取互相关的值并与之前的值进行比较
  5. 如果它更大,那么良好的变形,如果没有,重做变形并做其他事情
  6. 在最大化互相关值后,知道有什么变形:)

关于变形:可以首先沿x和y方向移动以最大化互相关,然后在第二步中拉伸或压缩x和y依赖性并且在第三步骤中变形二次x和y依赖性和重复这个过程iterativ ?? 使用整数坐标我真的有问题.你认为我必须插值图片以获得连续分布?我必须再考虑一下:(感谢大家参与:)

PiQ*_*uer 2

OpenCV(以及它的 python Opencv 绑定)有一个实现此算法的StarDetector类。

作为替代方案,您可以查看 OpenCV SIFT类,它代表尺度不变特征变换。

更新

关于您的评论,我知道“正确”的变换将最大化图像之间的互相关性,但我不明白您如何选择要最大化的变换集。也许如果您知道三个匹配点的坐标(通过一些启发式方法或手动选择它们),并且如果您期望相似性,则可以使用cv2.getAffineTransform之类的东西为最大化过程提供良好的初始转换。从那里,您可以使用小的附加转换来获得最大化的集合。但在我看来,这种方法就像是重新发明了 SIFT 可以处理的东西。

要实际转换测试图像,您可以使用cv2.warpAffine,它也可以处理边框值(例如用 0 填充)。要计算互相关,您可以使用scipy.signal.correlate2d

更新

您的最新更新确实为我澄清了一些要点。但我认为位移矢量场并不是最自然的寻找方式,这也是误解的根源。我更多地沿着全局变换 T的思路思考,它应用于左侧图像的任何点 (x,y),在右侧给出 (x',y')=T(x,y),但 T 有每个像素的分析形式相同。例如,这可以是位移、旋转、缩放、也许是某种透视变换的组合。我不能说希望找到这样的变换是否现实,这取决于您的设置,但如果场景两侧物理上相同,我会说期待一些仿射变换是合理的。这就是我建议cv2.getAffineTransform的原因。从这样的 T 计算位移矢量场当然很简单,因为这只是 T(x,y)-(x,y)。

最大的优点是你的变换只有很少的自由度,而不是位移矢量场中的 2N 个自由度,其中 N 是亮点的数量。

如果它确实是仿射变换,我会建议一些像这样的算法:

  • 识别左侧三个明亮且孤立的点
  • 对于这三个点中的每一个,定义一个边界框,以便您可以在右侧图像中识别出其中对应的点
  • 找到相应点的坐标,例如使用cv2.matchTemplate中实现的一些相关方法,或者也只是找到边界框内的最亮点。
  • 一旦有了三对匹配的坐标,就可以使用cv2.getAffineTransform计算将一组坐标转换为另一组的仿射变换。
  • 将此仿射变换应用于左图像,作为检查是否找到了正确的图像,您可以计算整体归一化互相关是否高于某个阈值,或者如果相对于另一图像替换一个图像,则整体归一化互相关是否会显着下降。
  • 如果您愿意并且仍然需要它,请根据变换 T 轻松计算位移矢量场。

更新

看来cv2.getAffineTransform需要一个尴尬的输入数据类型“float32”。假设源坐标是 ,(sxi,syi)目的地坐标(dxi,dyi)i=0,1,2,那么你需要的是

src = np.array( ((sx0,sy0),(sx1,sy1),(sx2,sy2)), dtype='float32' )
dst = np.array( ((dx0,dy0),(dx1,dy1),(dx2,dy2)), dtype='float32' )

result = cv2.getAffineTransform(src,dst)
Run Code Online (Sandbox Code Playgroud)