透视变换和图像拼接/重叠 (C++)

7

我正在使用典型的检测器-描述符-匹配器组合来检测和匹配一对图像的特征,然后使用findHomography生成变换矩阵。

在此之后,我希望将两个图像重叠(第二个图像 (imgTrain) 在第一个图像 (imgQuery) 上),因此我使用变换矩阵对第二个图像进行了变形:

cv::Mat imgQuery, imgTrain;
...    
TRANSFORMATION_MATRIX = cv::findHomography(...)
...
cv::Mat imgTrainWarped;
cv::warpPerspective(imgTrain, imgTrainWarped, TRANSFORMATION_MATRIX, imgTrain.size());

从这里开始,我不知道如何制作一个包含原始imgQuery和变形的imgTrainWarped的图像。考虑两种情况: 1)最终图像的大小与imgQuery的大小相同。 2)最终图像的大小足够大,可以容纳imgQueryimgTrainWarped,因为它们只有部分重叠,而不是完全重叠。我理解第二种情况可能会在图像周围出现黑色/空白区域。
4个回答

5

在此之后,您应该将目标矩阵的维度与imgQuery相同。之后,遍历整个变形图像并将像素复制到第一张图像中,但只有在变形图像实际持有变形像素时才能这样做。最简单的方法是通过变形附加掩模来完成。请尝试以下操作:

cv::Mat imgMask = cv::Mat(imgTrain.size(), CV_8UC1, cv::Scalar(255));
cv::Mat imgMaskWarped;
cv::warpPerspective(imgMask , imgMaskWarped, TRANSFORMATION_MATRIX, imgQuery.size());

cv::Mat imgTrainWarped;
cv::warpPerspective(imgTrain, imgTrainWarped, TRANSFORMATION_MATRIX, imgQuery.size());

// now copy only masked pixel:
imgTrainWarped.copyTo(imgQuery, imgMaskWarped);

请尝试并告诉我这是否可行并解决了方案1的问题。对于方案2,您需要测试图像在变形之前必须有多大,并将两个图像复制到足够大的目标图像中。


嗯...我有点困惑。我是你写的代码,但我得到了这个:http://j.mp/warp001。(可以在此处查看具有匹配项的两个图像:http://j.mp/warp002)。你觉得呢? - user4688547
请问您能否在变形后立即使用cv::imwrite函数将imgTrainWarpedimgQuery保存并分享给我吗? - Micka
包装后:imgQuery为http://j.mp/imgQuery,imgMaskWarped为http://j.mp/imgMaskWarped,imgTrainWarped为http://j.mp/imgTrainWarped。 - user4688547
我原本也是这么想的,不过我对中间的Mask步骤并不是很熟悉,所以我无法得到正确的结果。这是原始图片:http://j.mp/imgQuery_original,这是第二张图片:http://j.mp/imgTrain。非常感谢您的时间! - user4688547
但这是否意味着您扭曲了imgQuery而不是imgTrain?因为在扭曲图像(复制之前),imgQuery的部分是可见的?!我的意思是,您发布的imgTrainWarped看起来像您发布的imgQuery向上平移。相反,它应该看起来像imgTrain向上平移... - Micka
显示剩余7条评论

1

您是否试图从同一视角不同方向拍摄的两张重叠图片中创建全景图像?如果是这样,我对“第二张覆盖在第一张上”的部分表示关注。将全景图拼接在一起的正确方法是沿着重叠部分的中心线(对称轴)剪切两个图像,并不是将一个图像的一部分添加到(整个)另一个图像上。


1
我所说的重叠是指其中一张图片保持不变,而另一张则被"覆盖"在其上。先前步骤是否削去第一张图片重叠的部分并不影响最终结果,这是我的假设,因此两种过程都可以。我可能误解了你的意思... - user4688547
首先,这些图像是如何拍摄的?如果相机平行移动,比如在水平飞行中不同时间点拍摄的航空照片,则请忽略我的评论。但如果相机放置在一个固定点,并在第一张和第二张照片之间轻微旋转,则重叠部分将不会完全匹配,除非在重叠部分的对称轴上。 - Strangled

1

对于OpenCV 4中的INTER_LINEAR和BORDER_TRANSPARENT, 您可以使用cv::InterpolationFlags::INTER_LINEAR,cv::BorderTypes::BORDER_TRANSPARENT来解决,例如:

cv::warpPerspective(imgTrain, imgQuery, TRANSFORMATION_MATRIX, imgQuery.size(), cv::InterpolationFlags::INTER_LINEAR, cv::BorderTypes::BORDER_TRANSPARENT);

你能解释一下你发布的代码与2年前coyer的回答(https://dev59.com/yY7ea4cB1Zd3GeqPCo2a#51446320)中的代码有什么*显著*不同吗? - Adrian Mole

0

已接受的答案可行,但使用BORDER_TRANSPARENT会更容易:

cv::warpPerspective(imgTrain, imgQuery, TRANSFORMATION_MATRIX, imgQuery.size(), INTER_LINEAR, BORDER_TRANSPARENT);

当使用 BORDER_TRANSPARENT 时,imgQuery 的源像素保持不变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接