一、目的
- 这两个知识点平时还是比较常见
- 它可以顺带的理解一下图像的缩放、平移等等
- 对3x3矩阵的妙用希望略懂皮毛
二、公式推导
2.1 平面矩阵
这儿只定义平面的操作。
就拿平移矩阵为例,这个表示什么意思呢?
可以看到,公式里面只有坐标x,y;但是我们要的是像素值啊!!
这个矩阵表示的是平移前像素位置,平移后应该在哪个位置。看代码应该一目了然了。
move_mat = np.array([[1, 0, a], [0 , 1, b], [0 , 0 , 1]])
image = cv2.imread("img.png")
new_img = np.zeros(image.shape)
for i in range(img.shape[0]):
for j in range(img.shape[1])):
tem_xy = [[i],[j],[1]]
new_tem_xy = np.matmul(move_mat, tem_xy)
if new_tem_xy[0][0] <= image.shape[1] & new_tem_xy[1][0] <= image.shape[0] /
& new_tem_xy[0][0]>=0 &new_tem_xy[1][0] >= 0:
new_img[new_tem_xy[1][0]][new_tem_xy[0][0]] = image[i][j]
可以看到,它是求出映射后 的x,y的值,然后把原来x,y处的像素值赋值给这个位置。
2.2 错切
如下图,矩形关于y方向的错切:
数学表达式为
那么x轴上的错切也是同理:
x轴和y轴合起来,就可以由如下表示:
2.3 仿射变换
仿射变换是由平移+ 旋转 + 缩放 + 错切之后得到的。
2.4 仿射变换和透视变换的区别
仿射变换(下):是矩形变成了平行四边形(即变换前后各边依旧平行)。
而透视变换(上):变换后是任意不规则的四边形。
仿射变换是线性变换。而透视变换不是,可以说仿射变换是透视变换的一种特例。
3 仿射变换
3.1 API
void cv::warpAffine ( InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar()
)
参数解释
- src: 输入图像
- dst: 输出图像,尺寸由dsize指定,图像类型与原图像一致
- M: 2X3的变换矩阵 ,需要注意的opencv集成的M矩阵是把最后的那一行删掉的哈,留下的是2x3的矩阵。
- dsize: 指定图像输出尺寸
- flags: 插值算法标识符,有默认值INTER_LINEAR,如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转换
其中,M是最重要的。Opencv也提供了M矩阵的计算API。
getAffineTransform(
const Point2f* src(),
const Point2f* dst(),
需要有三对变换前和变换后的点,就可以求到M矩阵了,具体的示例在我的每周练习01里面就有提到。
具体的使用,比如说:我们有斜着的书啊,证件啊啥的,我们想把它转正,怎么办?
转正后的三个角点我们是先验已知的,就是图像的三个边的点。转正前的就可以通过各种手段去标记这个点在当前位置的坐标,之后就可以得到M矩阵,然后通过仿射变换API就可以得到正向的书了。
如这本斜置的书,我们认为的用鼠标找到书的四个角的像素点位置,然后去映射到正向图像的(0,0);(0,w);(h, 0 );(h,w),只需要三点求出M矩阵就行了。
4、透视变换 perspective-transfrom
透视变换同样是一个3x3的矩阵,不过第三行的矩阵现在有变换了。
上面矩阵的未知量比仿射变换的矩阵多了一个透视变换矩阵T3(两个未知量),因此需要比求解仿射变换多一个位置。也就是说现在要图像的四个点才能求出透视变换的M矩阵。
透视变换API:warpPerspective()
void warpPerspective(
InputArray src, 输入图像
OutputArray dst, 输出图像
InputArray ,M M矩阵
Size dsize,指定图像输出尺寸
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar() )
计算透视变换的M矩阵也有一个单独的API:getPerspectiveTransform()
Mat getPerspectiveTransform(
const Point2f src[], 输入图像点集
const Point2f dst[],输出图像点集)