目录
旋转矩阵,平移矩阵讲解:
仿射变换Python例子
编辑坐标点的仿射变换:
图像的几何变换主要包括:平移、旋转、缩放、剪切、仿射、透视等。
图像的几何变换主要分为:刚性变换、相似变换、仿射变换和透视变换(也称为投影变换)。
刚性变换:平移、旋转;
相似变换:缩放、剪切;
仿射变换:从一个二维坐标系变换到另一个二维坐标系的过程,属于线性变换。通过已知3对坐标点便可求取变换矩阵。
透视变换:从二维坐标系变换到三维坐标系,在从三维坐标系投影到二维平面,属于非线性变换。通过已知4对坐标点便可求取变换矩阵。
仿射变换
仿射变换是把一个二维坐标系转换到另一个二维坐标系的过程,在转换过程中坐标点的相对位置和属性不发生变换,属于线性变换。在该变换过程中只发生平移和旋转,因此一个菱形在发生仿射变换后还是一个菱形。
也可以说,仿射变换是指在向量空间中进行一次线性变换(乘以线性矩阵)和一次平移(加上一个向量),变换到另一个向量空间的过程。
仿射变换代表的是两幅图像之间的映射关系,仿射变换矩阵为2X3的矩阵,
总的来说,仿射=平移+旋转。
旋转矩阵,平移矩阵讲解:
线性代数导学(八): 那些常见且特殊的矩阵与其目的 - 知乎
仿射变换Python例子
import cv2
import numpy as np
img = np.zeros((400,400,3),dtype=np.uint8)
img[50:100,50:100]=255
height, width = img.shape[:2]
# 在原图上和目标图像上各选三个点
mat_src = np.float32([[0, 15], [0, height - 20], [width - 1, 0]])
mat_dst = np.float32([[0, 15], [100, height - 100], [width - 100, 100]])
# 获得变换矩阵
mat_trans = cv2.getAffineTransform(mat_src, mat_dst)
# 进行仿射变换
dst = cv2.warpAffine(img, mat_trans, (width, height))
# 显示
imgs = np.hstack([img, dst])
cv2.namedWindow("imgs", cv2.WINDOW_NORMAL)
cv2.imshow("imgs", imgs)
cv2.waitKey(0)
坐标点的仿射变换:
import cv2
import numpy as np
def get_transform(mat_src,mat_dst):
img = np.zeros((600, 600, 3), dtype=np.uint8)
img[50:100, 50:100] = 255
img[350:400, 350:400] = 255
height, width = img.shape[:2]
x1 = int((mat_src[0,0]+mat_src[1,0])*0.5)
y1 = int((mat_src[0,1]+mat_src[1,1])*0.5)
cv2.circle(img, (int(x1), int(y1)), 3, (0, 0, 255), -1)
cv2.line(img, (0, 50), (50, 100), (0, 255, 0), 1) # 绿色,3个像素宽度
cv2.line(img, (300, 50), (50, 100), (0, 255, 0), 1) # 绿色,3个像素宽度
mat_trans = cv2.getAffineTransform(mat_src, mat_dst)
dst = cv2.warpAffine(img, mat_trans, (width, height))
return mat_trans,dst,img
def transform_point(mat_trans,point):# point x y
data = np.dot(mat_trans, np.asarray([point[0], point[1], 1]))
return data
if __name__ == '__main__':
mat_src = np.float32([[0, 50], [50, 100], [600, 50]])
mat_dst = np.float32([[0, 0], [100, 100], [100, 200]])
mat_trans,dst,img=get_transform(mat_src,mat_dst)
x1 = 25
y1 = 75
data=transform_point(mat_trans,[x1,y1])
x2 = data[0]
y2 = data[1]
print(x2, y2)
cv2.circle(dst, (int(x2), int(y2)), 2, (0, 0, 255), -1)
# 显示
imgs = np.hstack([img, dst])
# imgs = np.hstack([img, dst])
# cv2.namedWindow("imgs", cv2.WINDOW_NORMAL)
cv2.imshow("img_o", img)
cv2.imshow("dst", dst)
# cv2.imshow("imgs", imgs)
cv2.waitKey(0)
总结,仿射变换需要的3个点是因为3个点组成一个平面,只能对在平面内的点进行变换,如果点不在这个平面内,则变换失效,那就需要投影变换。
透视变换
透视变换是将一个图像投影到新的视平面,该过程包括:1.将二维坐标系转换为三维坐标系;2.将三维坐标系投影到新的二维坐标系。该过程属于非线性变换过程,一个菱形在经过非线性变换后得到一个四边形,但是不在平行。
透视变换又可以称为投影变换,仿射变换属于透视变换的特例。透视变换能够保持“直线性”,即原图中的直线,在经透视变换后仍为直线。
透视变换示意图
透视变换矩阵变换公式为:
其中透视变换矩阵为:
要移动的点,即源目标点:
定点,即移动到的目标点:
从二维空间变换到三维空间,因为图像在二维平面,故除以Z,(X‘,Y’,Z‘)表示图像上的点。
另a33=1,展开上面的公式,可得到一个点为:
四个点,即可得到8个方程,便可求解出透视变换矩阵A。
透视变换代码:
def PerspectImage():
img = cv2.imread("C:/Users/player/Documents/3DPrinter/StitchImage/shizi.png")
height, width = img.shape[:2]
# 变换前的四个点
srcArr = np.float32([[0, 0], [0, 1080], [1920, 1080], [1920, 0]])
# 变换后的四个点
dstArr = np.float32([[1, 12], [6, 1060], [1915, 1075], [1918, 3]])
# 获取变换矩阵
MM = cv2.getPerspectiveTransform(srcArr, dstArr)
dst = cv2.warpPerspective(img, MM, (width, height))
cv2.imwrite("C:/Users/player/Documents/3DPrinter/StitchImage/pe.png", dst)
变换结果
原图
透视变换后的效果图————