伪原创对网站的影响,wordpress的代码逻辑,电商网站建设用php,网站建设情况存在问题前言
在前面做换脸的博客中提到了使用仿射变换和透视变换将两张不同的人脸基于关键点进行对齐#xff0c;保证一张人脸贴到另一张人脸时#xff0c;大小完全一致#xff1b;所以有必要理解一下这两个概念的区别#xff0c;由于以实用性为目的#xff0c;所以所有的图像算…前言
在前面做换脸的博客中提到了使用仿射变换和透视变换将两张不同的人脸基于关键点进行对齐保证一张人脸贴到另一张人脸时大小完全一致所以有必要理解一下这两个概念的区别由于以实用性为目的所以所有的图像算法都会以opencv为例去探索其用法。
国际惯例参考博客
opencv中的warpAffine
opencv中的warpPerspective
【opencv实践】仿射变换和透视变换
仿射变换与透视变换区别
图像处理的仿射变换与透视变换
Affine and Projective Transformations
OpenCV Transformationmatrix: affine vs. perspective warping
点乘即投影向量
【TensorFlow-windows】扩展层之STN
理论
在做数据增强的时候图像里面有很多几何变换比如旋转、平移、缩放、拉伸等但是他们的本质还是通过某个矩阵将图像每个像素点的坐标变换到另一个新的位置。这种通过某个矩阵将图像进行变换的方法通常称为线性变换也就是说利用了向量加法和标量乘法。
【注】本文的变换仅仅针对二维矩阵非针对三维矩阵的变换。
仿射变换其实是透视变换的一种特殊形式他俩都可以用下面这个矩阵表示 M[a1a2b1a3a4b2c1c21]M\begin{bmatrix} a_1a_2b_1\\ a_3a_4b_2\\ c_1c_21 \end{bmatrix} M⎣⎡a1a3c1a2a4c2b1b21⎦⎤ 用此矩阵将(x,y)(x,y)(x,y)变换到新的坐标点就是 [x′y′1][a1a2b1a3a4b2c1c21][xy1]\begin{bmatrix} x\\ y\\ 1 \end{bmatrix} \begin{bmatrix} a_1a_2b_1\\ a_3a_4b_2\\ c_1c_21 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ⎣⎡x′y′1⎦⎤⎣⎡a1a3c1a2a4c2b1b21⎦⎤⎣⎡xy1⎦⎤ 学过线性代数就知道这里面
[a1a2a3a4]\begin{bmatrix} a_1a_2\\ a_3a_4 \end{bmatrix}[a1a3a2a4]用来处理旋转和缩放比如有个点是[2,3][2,3][2,3]经过[2002]\begin{bmatrix} 20\\ 02 \end{bmatrix}[2002]矩阵变换后就成了[4,6][4,6][4,6]即被放大了四倍而经过[0110]\begin{bmatrix} 01\\ 10 \end{bmatrix}[0110]就变成了[3,2][3,2][3,2]即从原来的[2,3][2,3][2,3]坐标点旋转到了[3,2][3,2][3,2]坐标点。[b1b2]\begin{bmatrix} b_1\\ b_2 \end{bmatrix}[b1b2]这个就显而易见是平移[c1,c2][c_1,c_2][c1,c2]是投影向量因为点乘就是c1xc2yc_1xc_2yc1xc2y刚好代表一个向量在另一个向量的投影
投影变换(projective transformation)展示的是当观察者视角变化以后观察体的变化情况通常用于产生透视畸变(perspective distortion)有时候称为透视变换(perspective transformation)
仿射变换(affine transformation)用于缩放(scaling)、拉伸(skew)、旋转(rotation)
注意的点
两个变换都是将直线投影到直线两条平行直线通过仿射变换后依旧是两条平行的直线两条平行直线通过透视变换后可以是两条相交的直线 从数学上来讲它俩的区别在变换矩阵的最后一行[c1,c2][c_1,c_2][c1,c2]的值上仿射变换是0值而透视变换通常不是。所以这一点也能说明仿射变换是透视变换的子集。
但是有一个要求变换矩阵一定不能是奇异矩阵因为奇异矩阵会导致AXbAXbAXb有无穷解或者无解也就是说会出现多个点变换到同一个点的情况。
变换公式
根据OpenCV中所述
仿射变换的变换公式为: dst(x,y)src(M11xM12yM13,M21xM22yM23)\texttt{dst} (x,y) \texttt{src} ( \texttt{M} _{11} x \texttt{M} _{12} y \texttt{M} _{13}, \texttt{M} _{21} x \texttt{M} _{22} y \texttt{M} _{23}) dst(x,y)src(M11xM12yM13,M21xM22yM23) 透视变换变换公式为
dst(x,y)src(M11xM12yM13M31xM32yM33,M21xM22yM23M31xM32yM33)\texttt{dst} (x,y) \texttt{src} \left ( \frac{M_{11} x M_{12} y M_{13}}{M_{31} x M_{32} y M_{33}} , \frac{M_{21} x M_{22} y M_{23}}{M_{31} x M_{32} y M_{33}} \right )dst(x,y)src(M31xM32yM33M11xM12yM13,M31xM32yM33M21xM22yM23)
代码实践
使用opencv测试效果
仿射变换
使用warpAffine函数将图片旋转45度同时向右平移300像素向下平移100像素
#仿射变换
degreenp.deg2rad(45)
M1np.array([[np.cos(degree),-np.sin(degree),300],[np.sin(degree),np.cos(degree),100]
])
dst1 cv2.warpAffine(img,M1,(img.shape[1]*2,img.shape[0]*2))plt.figure(figsize(8,8))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(dst1)透视变换
使用warpPerspective函数
如果将透视变换使用上面的仿射变换矩阵补齐第三行可以得到和仿射变换一样的结果
#透视变换
degreenp.deg2rad(45)
M2np.array([[np.cos(degree),-np.sin(degree),300],[np.sin(degree),np.cos(degree),100],[0,0,1]
])
dst2 cv2.warpPerspective(img,M2,(img.shape[1]*2,img.shape[0]*2))plt.figure(figsize(8,8))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(dst2)一旦稍微改变投影向量也就是第三行的值就会发生很大的变化
#透视变换
degreenp.deg2rad(45)
M2np.array([[np.cos(degree),-np.sin(degree),300],[np.sin(degree),np.cos(degree),100],[0,-0.0015,1]
])
dst2 cv2.warpPerspective(img,M2,(img.shape[1]*2,img.shape[0]*2))plt.figure(figsize(8,8))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(dst2)所以我们通常能够通过仿射变换矩阵思考出变换后的样子但是透视变换却很难预测出变换后的样子。
理论扩展
上面说过仿射变换是特殊的透视变换后者变换矩阵的第3行c1,c2c_1,c_2c1,c2为0的时候就变成了前者。
为了让变换可控我们可以预先构建某些点来规定变换矩阵的映射是什么样的依据变换矩阵能看出参数量透视变换的矩阵为8个参数仿射变换矩阵为6个参数。
根据线性代数如果需要
求解仿射变换矩阵6个未知数需要6个方程即需要3组对应点求解透视变换矩阵8个未知数需要8个方程即需要4组对应点
所以比如想把原图变成平行四边形时可以平行四边形上的三个点求解仿射变换
#获取仿射变换矩阵
src_pts np.float32([[0,0],[0,1],[1,1]])
dst_pts np.float32([[0,0],[1,1],[2,1]])
M cv2.getAffineTransform(src_pts,dst_pts)
dst1 cv2.warpAffine(img,M,(img.shape[1]*2,img.shape[0]*2))plt.figure(figsize(8,8))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(dst1)想把原图变成直角梯形时可以使用直角梯形上的四个点求解透视变换
#获取透视变换矩阵
src_pts np.float32([[0,0],[0,300],[400,300],[400,0]])
dst_pts np.float32([[0,0],[0,300],[200,300],[400,0]])
M cv2.getPerspectiveTransform(src_pts,dst_pts)
dst2 cv2.warpPerspective(img,M,(img.shape[1]*2,img.shape[0]*2))plt.figure(figsize(8,8))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(dst2)总结
其实就是对图像处理的一些基本知识补充在之前写过的换脸博客1和博客2中有用到相关理论。
博客和公众号致力于图像、机器学习、运动捕捉方向的理论和代码实践注重基础和实践有兴趣可关注一波代码通常公布在公众号中的github网址