我正在尝试对图像执行倾斜,就像这里显示的那样
(来源:microsoft.com)
。
我有一组代表我的图像的像素,我不确定如何处理它们。
一个更好的方法是通过逆映射。
本质上,您想“扭曲”图像,对吗?这意味着源图像中的每个像素都会到达一个预定义的点——预定义是一个变换矩阵,它告诉你如何旋转、缩放、平移、剪切等。图像本质上是(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)
- 这称为双线性插值。
但这是另一个问题,假设您的转换不是简单的缩放并且是仿射的(就像您发布的示例图像) - 然后(1,1)
会变成这样(2.34,4.21)
,然后您必须在输出图像中将它们四舍五入(2,4)
,然后您d 必须对新图像进行双线性插值以填充孔或更复杂的插值 - 很乱吧?
现在,没有办法摆脱插值,但我们可以只做一次双线性插值。如何?简单的逆映射。
不要将其视为将源图像转到新图像,而应考虑新图像的数据将来自源图像中的何处!所以,(1,1)
在新的图像中会来自源图像中的一些反向映射,比如说,(3.4, 2.1)
然后对源图像做双线性插值,找出对应的值!
好的,那么如何为仿射变换定义变换矩阵呢?这个网站告诉你如何通过组合不同的变换矩阵来实现旋转、剪切等。
最终矩阵可以通过按顺序合成每个矩阵来实现,然后将其反转以获得逆映射 - 使用它计算源图像中像素的位置并进行插值。
如果您不想重新发明轮子,请查看 OpenCV 库。它实现了许多有用的图像处理功能,包括透视变换。查看我用来轻松完成此任务的cvWarpPerspective 。
正如 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
是用于平移每个像素的平移向量。