使用透视变换来调整图像

时间:2010-03-15 10:49:41

标签: image image-processing transform computer-vision perspective

我正在尝试对图像执行偏斜,如此处所示

http://i.msdn.microsoft.com/3b575a03.TransformedClimber%28en-us,VS.90%29.png

我有一个代表我的图像的像素数组,我不确定如何处理它们。

3 个答案:

答案 0 :(得分:53)

更好的方法是通过逆映射。

基本上,你想要“扭曲”图像,对吧?这意味着源图像中的每个像素都会转到预定义的点 - 预定义是一个转换矩阵,它告诉您如何旋转,缩放,平移,剪切等图像,这实际上是在您的图像上采用了一些坐标(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告诉您如何通过合成不同的转换矩阵进行旋转,剪切等操作。

转换:

alt text

合成

alt text

最终矩阵可以通过按顺序合成每个矩阵来实现,然后反转以获得逆映射 - 使用此计算源图像中像素的位置并进行插值。 / p>

答案 1 :(得分:3)

如果您不想重新发明轮子,请查看OpenCV库。它实现了许多有用的图像处理功能,包括透视变换。查看我用来完成此任务的cvWarpPerspective非常容易。

答案 2 :(得分:2)

正如KennyTM评论的那样,您只需要一个仿射变换,即通过将每个像素乘以矩阵 M 并将结果添加到平移向量 V 获得的线性映射。这是简单的数学

end_pixel_position = M*start_pixel_position + V

其中 M 是旋转或缩放等简单变换的组合, V 是一个矢量,它通过向每个像素添加固定系数来平移图像的每个点。 / p>

例如,如果要旋转图像,可以将旋转矩阵定义为:

    | cos(a) -sin(a) |
M = |                |
    | sin(a)  cos(a) |

其中a是您想要旋转图像的角度。

缩放时使用以下形式的矩阵:

    | s1   0 |
M = |        |
    | 0   s2 |

其中s1s2是两个轴上的缩放因子。

对于翻译,你只需要矢量 V

    | t1 |
V = |    |
    | t2 |

t1t2添加到像素坐标。

然后将矩阵组合在一个单一的变换中,例如,如果你有缩放,旋转和平移,你最终会得到类似的东西:

| x2 |             | x1 |
|    | = M1 * M2 * |    | + T
| y2 |             | y1 |

其中:

  • x1y1是应用转换前的像素坐标,
  • x2y2是转换后的像素,
  • M1M2是用于缩放和旋转的矩阵(记住:矩阵的组合不可交换!通常是M1 * M2 * Vect != M2 * M1 * Vect),
  • T是用于翻译每个像素的翻译向量。