电子商务中的网站开发,招聘网站设计师要求,如何将网站提交给谷歌,网站整套模板OpenCV与图像处理学习四——图像几何变换#xff1a;平移、缩放、旋转、仿射变换与透视变换二、图像的几何变换2.1 图像平移2.2 图像缩放#xff08;上采样与下采样#xff09;2.3 图像旋转2.4 仿射变换2.5 透视变化2.6 几何变化小结续上次的笔记#xff1a;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 图像平移
将图像中所有的点按照指定的平移量水平或者垂直移动。
变换公式
设x0y0为原图像上的一点图像水平平移量为Tx垂直平移量为Ty则平移后的点坐标x1y1变为
x1 x0 Tx y1 y0 Ty
图像平移其实属于仿射变换的一种因为使用的很多所以将其单独拿出来作为一个知识点它所用到的函数就是仿射变换的函数
dst cv2.warpAffine( src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] )参数
src输入图像。M2×3的变换矩阵一般反映平移或旋转的关系。dsize输出图像大小。flags插值方法的组合int类型默认为cv2.INTER_LINEAR线性插值其他插值见OpenCV的 InterpolationFlags borderMode边界像素模式int类型。borderValue边界像素填充值默认为0黑色。
注意这些参数中M 这个变换矩阵对于不了解仿射变换的同学来说可能比较陌生因为这里重点介绍OpenCV对图像操作的使用原理部分不过多赘述大家可以先看一下这篇文章对仿射变换以及变换矩阵有很形象的解释仿射变换及其变换矩阵的理解。
我这边直接引用一下这篇文章里的图 上面这张图介绍了不同的仿射变换其变换矩阵应该怎么写其中平移的变换矩阵的形式为 有了变换矩阵的知识可以来看个例子
import cv2
import numpy as np
img cv2.imread(img2.png)
# 构造移动矩阵H
# 在x轴方向移动多少距离在y轴方向移动多少距离
H np.float32([[1, 0, 50], [0, 1, 25]])
rows, cols img.shape[:2]
print(img.shape)
print(rows, cols)# 注意这里rows和cols需要反置即先列后行
res cv2.warpAffine(img, H, (2*cols, 2*rows))
cv2.imshow(origin_picture, img)
cv2.imshow(new_picture, res)
cv2.waitKey(0)
cv2.destroyAllWindows()这里就不再解释变换矩阵这样写为什么可以x轴方向移动50y轴方向移动25了。
注意dsize这个参数是规定输出图像的尺寸它是先列后行的。 这里将输出尺寸扩大了4倍默认的边界像素为0所以外围都是黑色。
看一下结果 如果我们将输出尺寸改为和输入一样那么将会有部分图像丢失如下所示
res cv2.warpAffine(img, H, (cols, rows))2.2 图像缩放上采样与下采样
缩小图像称为下采样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 npimg cv2.imread(img2.png)
# 方法一通过设置缩放比例来对图像进行放大或缩小
res1 cv2.resize(img, None, fx2, fy2, interpolationcv2.INTER_CUBIC)
height, width img.shape[:2]
# 方法二直接设置图像的大小不需要缩放因子
#cv2.INTER_NEAREST最近邻插值 cv2.INTER_AREA 区域插值 cv2.INTER_CUBIC三次样条插值 cv2.INTER_LANCZOS4Lanczos插值res2 cv2.resize(img, (int(0.8*width), int(0.8*height)),interpolationcv2.INTER_LANCZOS4)
cv2.imshow(origin_picture, img)
cv2.imshow(res1, res1)
# cv2.imshow(res2, res2)
cv2.waitKey(0)
cv2.destroyAllWindows()结果如下所示
方法一是用的缩放因子长宽均扩大两倍 方法二是用的输出尺寸注意这里因为×了0.8可能会出现小数所以要将它变成int型
2.3 图像旋转
以图像的中心为原点旋转一定的角度也就是将图像上的所有像素都旋转一个相同的角度。旋转后图像的大小一般会改变即可以把转出显示区域的图像截去或者扩大图像范围来显示图像的所有部分。
图像的旋转变换也可以用矩阵变换来表示
设点(x0, y0)逆时针旋转θ角后的对应点x, y那么旋转后的点x, y的坐标为 所以旋转操作对应的变换矩阵M的形式为 但是OpenCV提供了具有可调旋转中心的缩放旋转因此可以在任何位置旋转和缩放。修正的变换矩阵由 其中 旋转也是仿射变换的一种所以操作的函数还是cv2.warpAffine但是它的变换矩阵一般不像平移那样简单所以OpenCV提供了一个专门求图像旋转变换矩阵的函数
retval cv2.getRotationMatrix2D(center, angle, scale)参数
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)# 0xFF27 ESCif cv2.waitKey(1) 0xFF 27:break
cv2.destroyAllWindows()结果如下所示 将scale改为-1即可进行顺时针旋转
M cv2.getRotationMatrix2D((cols/2, rows/2), 45, -1)2.4 仿射变换
仿射变换包括平移、旋转、放缩、剪切和反射等上面的几种变换其实都可以算是仿射变换推荐看一下这篇文章仿射变换及其变换矩阵的理解。 那除了平移的变换矩阵是比较好确定的其他变换的M矩阵很难直接写出来所以OpenCV提供了一个求仿射变换矩阵的函数
retval cv2.getAffineTransform( src, dst )参数
src原图像中三个点的坐标。dst目标图像中对应的三个点的坐标变换后。
这两个参数分别需要提供三个点对通过这三个点对来计算变换矩阵M通过这个矩阵M求得最终目标图像中所有点的位置 看个例子
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片
src cv2.imread(bird.png)
# 获取图像大小
rows, cols src.shape[:2]
# 设置图像仿射变换矩阵
pos1 np.float32([[50, 50], [200, 50], [50, 200]])
pos2 np.float32([[10, 100], [200, 50], [100, 250]])
M cv2.getAffineTransform(pos1, pos2)
print(M)
# 图像仿射变换
result cv2.warpAffine(src, M, (2*cols, 2*rows))
# 显示图像
cv2.imshow(original, src)cv2.imshow(result, result)
# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()代码中给出了原图中的三个点对 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.39029035e00 -3.43634713e02][-2.44501950e00 5.71605909e00 -1.89984623e02][ 9.77952650e-04 3.74089089e-03 1.00000000e00]]输出的结果图像
2.6 几何变化小结
图像扩增一般图像方面的预处理会用到
# 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, fx1.1, fy1.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()结果如下图所示 以上就是图像常用的几何变化操作下次笔记学习图像的滤波与增强以及图像形态学的知识。