图像几何变换 分为 缩放、平移、旋转、仿射变换、透视变换 等;
其思路大致相同:在 原图像上 找几个点的坐标,然后设定 变换后 这些点对应的 坐标,根据两组坐标 计算出一个 转换矩阵,把原图像所有点 按这个转换矩阵进行转换即可
缩放
缩放只是调整图像的大小;
其转换矩阵为
def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None): 放大和缩小图像 参数: src: 输入图像对象 dsize:输出矩阵/图像的大小,为0时计算方式如下:dsize = Size(round(fx*src.cols),round(fy*src.rows)) fx: 水平轴的缩放因子,为0时计算方式: (double)dsize.width/src.cols fy: 垂直轴的缩放因子,为0时计算方式: (double)dsize.heigh/src.rows interpolation:插值算法 cv2.INTER_NEAREST : 最近邻插值法 cv2.INTER_LINEAR 默认值,双线性插值法 cv2.INTER_AREA 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。 cv2.INTER_CUBIC 基于4x4像素邻域的3次插值法 cv2.INTER_LANCZOS4 基于8x8像素邻域的Lanczos插值 cv2.INTER_AREA 适合于图像缩小, cv2.INTER_CUBIC (slow) & cv2.INTER_LINEAR 适合于图像放大
既可指定缩放比例,也可指定缩放后的大小
示例
img = cv.imread('imgs/2.png') cv.imshow('org', img) res = cv.resize(img, None, fx=3, fy=2, interpolation=cv.INTER_CUBIC) # 3倍比例 cv.imshow('bili', res) # 或者 res = cv.resize(img, (100, 200), interpolation=cv.INTER_CUBIC) # 指定尺寸 cv.imshow('hw', res) cv.waitKey(0)
平移
平移只是位置的移动;
假设在 x轴 y轴 上移动距离为 (tx, ty),则转换矩阵为
转换后的坐标为 (x+tx, y+ty)
示例
img = cv.imread('imgs/2.png', 0) cv.imshow('org', img) rows, cols = img.shape print(rows, cols) # 408 388 M = np.float32([[1, 0, 100],[0, 1, 50]]) # 平移向量 print(M) # [[ 1. 0. 100.] # [ 0. 1. 50.]] dst = cv.warpAffine(img, M, (cols, rows)) # 第三个参数是输出图像的大小,其形式应为(width,height)。记住width =列数,height =行数。 cv.imshow('img', dst) cv.waitKey(0) cv.destroyAllWindows()
warpAffine 用法见下文
效果图
旋转
假设图像旋转角度为θ,则转换矩阵为
转换后的坐标为 x1 = xcosθ-ysinθ, y1 =xsinθ+ycosθ;
opencv将其进行了扩展,任意点center为中心进行顺时针旋转θ,放大scale倍的,转换矩阵如下:
为了找到此转换矩阵,OpenCV提供了一个函数 cv.getRotationMatrix2D。
cv2.getRotationMatrix2D() 返回2*3的转变矩阵(浮点型) 参数: center:旋转的中心点坐标 angle:旋转角度,单位为度数,证书表示逆时针旋转 scale:同方向的放大倍数
示例
img = cv.imread('imgs/2.png', 0) rows, cols = img.shape # cols-1 和 rows-1 是坐标限制 M = cv.getRotationMatrix2D(((cols - 1) / 2.0, (rows - 1) / 2.0), 90, 1) # 旋转矩阵 print(M) # [[ 6.123234e-17 1.000000e+00 -1.000000e+01] # [-1.000000e+00 6.123234e-17 3.970000e+02]] dst = cv.warpAffine(img, M, (cols, rows)) cv.imshow('img', dst) cv.waitKey(0) cv.destroyAllWindows()
warpAffine 用法见下文
效果图
仿射变换
仿射变换其实是 缩放、平移、旋转 的组合,其 变换矩阵 可 由 上述变换矩阵 相乘得到;
opencv提供了函数getAffineTransform()来计算变换矩阵
cv2.getAffineTransform() 返回2*3的转变矩阵 参数: src:原图像中的三组坐标,如np.float32([[50,50],[200,50],[50,200]]) dst: 转换后的对应三组坐标,如np.float32([[10,100],[200,50],[100,250]])
示例
img = cv.imread('imgs/2.png') rows, cols, ch = img.shape pts1 = np.float32([[50, 50], [200, 50], [50, 200]]) pts2 = np.float32([[10, 100], [200, 50], [100, 250]]) M = cv.getAffineTransform(pts1, pts2) print(M) # 2x3 # [[ 1.26666667 0.6 -83.33333333] # [ -0.33333333 1. 66.66666667]] dst = cv.warpAffine(img, M, (cols, rows)) plt.subplot(121); plt.imshow(img); plt.title('Input') plt.subplot(122); plt.imshow(dst); plt.title('Output') plt.show()
效果图
warpAffine 用法
cv2.warpAffine() 仿射变换(从二维坐标到二维坐标之间的线性变换,且保持二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的原子变换的复合来实现,包括平移,缩放,翻转,旋转和剪切) 参数: img: 图像对象 M:2*3 transformation matrix (转变矩阵) dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows flags:可选,插值算法标识符,有默认值INTER_LINEAR, 如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11*x+M12*y+M13,M21*x+M22*y+M23) borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT borderValue:可选,边界取值,有默认值Scalar()即0
常见插值算法
透视变换(投影变换)
仿射变换是在二维空间的变换,透视变换是在三维空间的变换;
故 仿射变换 需要 3个点,2x3 的转换矩阵,透视变换 需要 4个点,3x3 的转换矩阵;
opencv提供了函数getPerspectiveTransform()来计算转变矩阵,cv2.warpPerspective()函数来进行透视变换。其对应参数如下:
cv2.getPerspectiveTransform() 返回3*3的转变矩阵 参数: src:原图像中的四组坐标,如 np.float32([[56,65],[368,52],[28,387],[389,390]]) dst: 转换后的对应四组坐标,如np.float32([[0,0],[300,0],[0,300],[300,300]]) cv2.warpPerspective() 参数: src: 图像对象 M:3*3 transformation matrix (转变矩阵) dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows flags:可选,插值算法标识符,有默认值INTER_LINEAR, 如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11*x+M12*y+M13,M21*x+M22*y+M23) borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT borderValue:可选,边界取值,有默认值Scalar()即0
示例
img = cv.imread('imgs/2.png') rows, cols, ch = img.shape pts1 = np.float32([[56, 65], [368, 52], [28, 387], [353, 381]]) # 输入图像的四个点 pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]]) # 输出图像对应的四个点 M = cv.getPerspectiveTransform(pts1, pts2) print(M) # 3x3 # [[ 1.00021368e+00 8.69751023e-02 -6.16653475e+01] # [ 4.11810169e-02 9.88344406e-01 -6.65485233e+01] # [ 7.90614186e-05 1.41513474e-04 1.00000000e+00]] dst = cv.warpPerspective(img, M, (300, 300)) plt.subplot(121); plt.imshow(img); plt.title('Input') plt.subplot(122); plt.imshow(dst); plt.title('Output') plt.show()
效果图
上图找到原图的4个顶点,将其转换到新图的4个顶点,能将 歪斜 的 ROI 转正并放大,
这在 书籍、名片等拍照上传后进行识别时,是个很好的预处理方法;
opencv中还提供了一个函数 perspctiveTransform() 来对坐标点进行透视变换,对于原图像上的一点,通过 perspctiveTransform() 能计算出透视变换后图片上该点的坐标,其对应参数如下:
cv2.perspectiveTransform(src, matrix) 参数: src:坐标点矩阵,注意其格式. 如src=np.array([[589, 91],[1355, 91],[1355, 219],[589, 219]], np.float32).reshape(-1, 1, 2), 表示四个坐标点,size为(4, -1, 2) matrix:getPerspectiveTransform()得到的透视变换矩阵
返回值:变换后的坐标点,格式和src相同
参考资料:
https://www.cnblogs.com/silence-cho/p/10926248.html OpenCV-Python学习—基础知识