OpenCV与图像处理学习四 |
您所在的位置:网站首页 › 数学函数图像变换 › OpenCV与图像处理学习四 |
OpenCV与图像处理学习四——图像几何变换:平移、缩放、旋转、仿射变换与透视变换
二、图像的几何变换2.1 图像平移2.2 图像缩放(上采样与下采样)2.3 图像旋转2.4 仿射变换2.5 透视变化2.6 几何变化小结
续上次的笔记:OpenCV与图像处理学习三——图像基本操作(1) 这次笔记主要的内容是图像的几何变换:包括平移、缩放、旋转、仿射变换和透视变换。 对应的OpenCV官方python文档为:https://docs.opencv.org/4.1.2/da/d6e/tutorial_py_geometric_transformations.html 二、图像的几何变换 2.1 图像平移将图像中所有的点按照指定的平移量水平或者垂直移动。 变换公式: 设(x0,y0)为原图像上的一点,图像水平平移量为Tx,垂直平移量为Ty,则平移后的点坐标(x1,y1)变为: x1 = x0 + Tx; y1 = y0 + Ty; 图像平移其实属于仿射变换的一种,因为使用的很多所以将其单独拿出来作为一个知识点,它所用到的函数就是仿射变换的函数: dst = cv2.warpAffine( src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] )参数: src:输入图像。M:2×3的变换矩阵,一般反映平移或旋转的关系。dsize:输出图像大小。flags:插值方法的组合(int类型),默认为:cv2.INTER_LINEAR(线性插值),其他插值见OpenCV的 InterpolationFlags :![]() 注意:这些参数中,M 这个变换矩阵对于不了解仿射变换的同学来说可能比较陌生,因为这里重点介绍OpenCV对图像操作的使用,原理部分不过多赘述,大家可以先看一下这篇文章,对仿射变换以及变换矩阵有很形象的解释:仿射变换及其变换矩阵的理解。 我这边直接引用一下这篇文章里的图: 这里就不再解释变换矩阵这样写为什么可以x轴方向移动50,y轴方向移动25了。 注意:dsize这个参数是规定输出图像的尺寸,它是先列后行的。 这里将输出尺寸扩大了4倍,默认的边界像素为0,所以外围都是黑色。 看一下结果: 缩小图像称为下采样(subsampled)或降采样(downsampled);放大图像称为上采样(upsampled),主要目的是得到更高分辨率的图像。 图像缩放是指图像大小按指定的比例进行放大或缩小。 函数: dst = cv2.resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] )参数: src:输入图像。dsize:输出图像的尺寸,与下面的比例因子二选一。fx:沿水平轴的比例因子。fy:沿垂直轴的比例因子。interpolation:插值方法,默认的为cv2.INTER_NEAREST(最近邻插值),其他的还有:![]() 插值缩放的原理是基于目标分辨率中的点,将其按照缩放关系对应到源图像中,寻找源图像中的点(不一定是整像素点),然后通过源图像中的相关点插值得到目标点,所以插值方法是最关键的不同之处。 简单的理解插值操作:图像的尺寸变了,那么我们该如何填充或删去一些像素值,这就需要用到插值方法,具体插值方法的原理部分我想以后如果接触到的话写一个比较完整的文章,这里初学OpenCV的话可以不用在乎这些细节。 来看个例子: import cv2 import numpy as np img = cv2.imread('img2.png') # 方法一:通过设置缩放比例,来对图像进行放大或缩小 res1 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC) height, width = img.shape[:2] # 方法二:直接设置图像的大小,不需要缩放因子 #cv2.INTER_NEAREST(最近邻插值) cv2.INTER_AREA (区域插值) cv2.INTER_CUBIC(三次样条插值) cv2.INTER_LANCZOS4(Lanczos插值) res2 = cv2.resize(img, (int(0.8*width), int(0.8*height)),interpolation=cv2.INTER_LANCZOS4) cv2.imshow('origin_picture', img) cv2.imshow('res1', res1) # cv2.imshow('res2', res2) cv2.waitKey(0) cv2.destroyAllWindows()结果如下所示: 方法一是用的缩放因子,长宽均扩大两倍: 方法二是用的输出尺寸,注意这里因为×了0.8,可能会出现小数,所以要将它变成int型: 以图像的中心为原点,旋转一定的角度,也就是将图像上的所有像素都旋转一个相同的角度。旋转后图像的大小一般会改变,即可以把转出显示区域的图像截去,或者扩大图像范围来显示图像的所有部分。 图像的旋转变换也可以用矩阵变换来表示: 设点(x0, y0)逆时针旋转θ角后的对应点(x, y),那么旋转后的点(x, y)的坐标为: 参数: center:图片的旋转中心。angle:旋转角度。scale:缩放比例,0.5表示缩小为原来的一半,这个参数还能表示旋转方向,正数表示逆时针,负数表示顺时针旋转。这样我们就不用求复杂的变换矩阵,直接给定想要的中心,角度和缩放比例的值即可,通过这个函数自动求出变换矩阵,然后将这个矩阵作为仿射变换函数的M参数,即可进行旋转操作,下面来看一个例子: import cv2 import numpy as np img = cv2.imread('img2.png', 1) rows, cols = img.shape[:2] # 参数1:旋转中心,参数2:旋转角度,参数3:缩放因子 # 参数3正为逆时针,负值为正时针 M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1) print(M) # 第三个参数是输出图像的尺寸中心 # dst = cv2.warpAffine(img, M, (cols, rows)) dst = cv2.warpAffine(img, M, (cols,rows), borderValue=(255,255,255)) while(1): cv2.imshow('img', img) cv2.imshow('img1', dst) # 0xFF==27 ESC if cv2.waitKey(1) & 0xFF == 27: break cv2.destroyAllWindows()结果如下所示: 仿射变换包括平移、旋转、放缩、剪切和反射等,上面的几种变换其实都可以算是仿射变换,推荐看一下这篇文章:仿射变换及其变换矩阵的理解。 那除了平移的变换矩阵是比较好确定的,其他变换的M矩阵很难直接写出来,所以OpenCV提供了一个求仿射变换矩阵的函数: retval = cv2.getAffineTransform( src, dst )参数: src:原图像中三个点的坐标。dst:目标图像中对应的三个点的坐标(变换后)。这两个参数分别需要提供三个点对,通过这三个点对来计算变换矩阵M,通过这个矩阵M求得最终目标图像中所有点的位置: 代码中给出了原图中的三个点对 pos1 = np.float32([[50, 50], [200, 50], [50, 200]]),其中[50, 50]对应目标图像中的位置为[10, 100],[200, 50]对应目标图像中的位置为[200, 50],[50, 200]对应目标图像中的位置为[100, 250],这就是pos2的意思。 看一下输出矩阵: [[ 1.26666667 0.6 -83.33333333] [ -0.33333333 1. 66.66666667]]图像输出结果为: ps:用这种点对应点的方式来求变换矩阵感觉用的不多,主要还是单独使用平移、旋转、缩放、反射等操作,这种方法图像不知道咋变的,比如上图就有部分图像丢失。 2.5 透视变化透视变换本质是将图像投影到一个新的视平面。与仿射变换类似,OpenCV提供了一个求透视变换矩阵的函数 cv2.getPerspectiveTransform,以及进行透视变换操作的函数 cv2.warpPerspective。 函数 cv2.getPerspectiveTransform: retval = cv2.getPerspectiveTransform( src, dst[, solveMethod] )参数: src:表示透视变换前的4个点的位置。dst:表示透视变换后的4个对应点的位置。ps:与仿射变换不同的是,这里需要四个点来确定M矩阵。 函数cv2.warpPerspective: dst = cv2.warpPerspective( src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] )参数: src:原始图像。M:透视变换矩阵。dsize:输出图像的尺寸。其他同上。看个例子: import cv2 import numpy as np import matplotlib.pyplot as plt # 读取图片 src = cv2.imread('bird.png') # 获取图像大小 rows, cols = src.shape[:2] # 设置图像透视变换矩阵 pos1 = np.float32([[114, 82], [287, 156], [8, 100], [143, 177]]) pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]]) M = cv2.getPerspectiveTransform(pos1, pos2) print(M) # 图像透视变换 result = cv2.warpPerspective(src, M, (2*cols,2*rows)) # 显示图像 cv2.imshow("original", src) cv2.imshow("result", result) # 等待显示 cv2.waitKey(0) cv2.destroyAllWindows()输出的变换矩阵: [[ 5.75709683e-01 3.39029035e+00 -3.43634713e+02] [-2.44501950e+00 5.71605909e+00 -1.89984623e+02] [ 9.77952650e-04 3.74089089e-03 1.00000000e+00]]输出的结果图像: 图像扩增,一般图像方面的预处理会用到: # encoding:utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt # 读取图片 img = cv2.imread('test2.png') image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 图像平移矩阵 M = np.float32([[1, 0, 80], [0, 1, 30]]) rows, cols = image.shape[:2] img1 = cv2.warpAffine(image, M, (cols, rows)) # 图像缩小 img2 = cv2.resize(image, (200, 100)) # 图像放大 img3 = cv2.resize(image, None, fx=1.1, fy=1.1) # 绕图像的中心旋转 # 源图像的高、宽 以及通道数 rows, cols, channel = image.shape # 函数参数:旋转中心 旋转度数 scale M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 30, 1) # 函数参数:原始图像 旋转参数 元素图像宽高 img4 = cv2.warpAffine(image, M, (cols, rows)) # 图像翻转 img5 = cv2.flip(image, 0) # 参数=0以X轴为对称轴翻转 img6 = cv2.flip(image, 1) # 参数>0以Y轴为对称轴翻转 # 图像的仿射 pts1 = np.float32([[50, 50], [200, 50], [50, 200]]) pts2 = np.float32([[10, 100], [200, 50], [100, 250]]) M = cv2.getAffineTransform(pts1, pts2) img7 = cv2.warpAffine(image, M, (rows, cols)) # 图像的透射 pts1 = np.float32([[56, 65], [238, 52], [28, 237], [239, 240]]) pts2 = np.float32([[0, 0], [200, 0], [0, 200], [200, 200]]) M = cv2.getPerspectiveTransform(pts1, pts2) img8 = cv2.warpPerspective(image, M, (200, 200)) # 循环显示图形 titles = ['source', 'shift', 'reduction', 'enlarge', 'rotation', 'flipX', 'flipY', 'affine', 'transmission'] images = [image, img1, img2, img3, img4, img5, img6, img7, img8] for i in range(9): plt.subplot(3, 3, i + 1), plt.imshow(images[i], 'gray') plt.title(titles[i]) plt.xticks([]), plt.yticks([]) plt.show()结果如下图所示: |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |