【发布时间】:2011-01-27 15:18:47
【问题描述】:
【问题讨论】:
-
为了你的图像的效果,你不需要透视变换。仿射变换就足够了。
标签: image image-processing transform computer-vision perspective
【问题讨论】:
标签: image image-processing transform computer-vision perspective
如果您不想重新发明轮子,请查看 OpenCV 库。它实现了许多有用的图像处理功能,包括透视变换。查看cvWarpPerspective,我用它很容易完成这项任务。
【讨论】:
一个更好的方法是通过逆映射。
本质上,您想“扭曲”图像,对吗?这意味着源图像中的每个像素都会到达一个预定义的点 - 预定义是一个变换矩阵,它告诉您如何旋转、缩放、平移、剪切等。图像本质上是在您的图像上获取一些坐标 (x,y) 和说,“好的,这个像素的新位置是(f(x),g(y))。
这基本上就是“变形”的作用。
现在,考虑将图像缩放……比如说,缩放到十倍。这意味着(1,1) 处的像素变为(10,10) 处的像素 - 然后下一个像素(1,2) 变为新图像中的(10,20) 像素。但是如果你继续这样做,你将没有像素值,(13,13) 因为,(1.3,1.3) 没有在你的原始图像中定义,你的新图像中会有一堆洞——你必须插值在新图像中使用它周围的四个像素来获取该值,即(10,10) , (10,20), (20,10), (200,2) - 这称为bilinear interpolation。
但这是另一个问题,假设您的转换不是简单的缩放并且是仿射的(就像您发布的示例图像)- 然后 (1,1) 将变成类似 (2.34,4.21) 的东西,然后您必须将它们四舍五入在输出图像中到(2,4) 和然后你必须对新图像进行双线性插值以填充孔或更复杂的插值 - 很乱吧?
现在,没有办法摆脱插值,但我们可以摆脱双线性插值,只需一次。如何?简单的逆映射。
不要将其视为将源图像转到新图像,而应考虑新图像的数据将来自源图像中的何处!所以,新图像中的(1,1)将来自源图像中的一些反向映射,比如(3.4, 2.1),然后对源图像进行双线性插值,找出对应的值!
好的,那么如何为仿射变换定义变换矩阵? This website 告诉你如何通过组合不同的变换矩阵来实现旋转、剪切等。
最终矩阵可以通过按顺序合成每个矩阵来实现,然后您反转它以获得逆映射 - 使用它计算源图像中像素的位置并进行插值。
【讨论】:
正如 KennyTM 所说,您只需要一个仿射变换,它是通过将每个像素乘以矩阵 M 并将结果添加到平移向量 V 获得的线性映射.数学很简单
end_pixel_position = M*start_pixel_position + V
其中 M 是简单变换(如旋转或缩放)的组合,V 是一个向量,它通过向每个像素添加固定系数来转换图像的每个点。
例如,如果要旋转图像,可以将旋转矩阵定义为:
| cos(a) -sin(a) |
M = | |
| sin(a) cos(a) |
其中a 是您要旋转图像的角度。
而缩放使用以下形式的矩阵:
| s1 0 |
M = | |
| 0 s2 |
其中s1 和s2 是两个轴上的比例因子。
对于翻译,你只需要向量 V:
| t1 |
V = | |
| t2 |
将t1 和t2 添加到像素坐标。
然后您将矩阵组合在一个单一的转换中,例如,如果您有缩放、旋转和平移,您最终会得到类似的结果:
| x2 | | x1 |
| | = M1 * M2 * | | + T
| y2 | | y1 |
地点:
x1 和 y1 是应用变换之前的像素坐标,x2 和 y2 是变换后的像素,M1 和 M2 是用于缩放和旋转的矩阵(记住:矩阵的组合不是可交换的!通常是M1 * M2 * Vect != M2 * M1 * Vect),T 是一个平移向量,用于平移每个像素。【讨论】: