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]]]]	)

参数:

  1. src:输入图像。
  2. M:2×3的变换矩阵,一般反映平移或旋转的关系。
  3. dsize:输出图像大小。
  4. flags:插值方法的组合(int类型),默认为:cv2.INTER_LINEAR(线性插值),其他插值见OpenCV的 InterpolationFlags在这里插入图片描述
  5. borderMode:边界像素模式(int类型)。
  6. 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轴方向移动50,y轴方向移动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]]]]	)

参数:

  1. src:输入图像。
  2. dsize:输出图像的尺寸,与下面的比例因子二选一。
  3. fx:沿水平轴的比例因子。
  4. fy:沿垂直轴的比例因子。
  5. interpolation:插值方法,默认的为cv2.INTER_NEAREST(最近邻插值),其他的还有:在这里插入图片描述

插值缩放的原理是基于目标分辨率中的点,将其按照缩放关系对应到源图像中,寻找源图像中的点(不一定是整像素点),然后通过源图像中的相关点插值得到目标点,所以插值方法是最关键的不同之处。

简单的理解插值操作:图像的尺寸变了,那么我们该如何填充或删去一些像素值,这就需要用到插值方法,具体插值方法的原理部分我想以后如果接触到的话写一个比较完整的文章,这里初学OpenCV的话可以不用在乎这些细节。

来看个例子:

import cv2
import numpy as npimg = 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型:
在这里插入图片描述

2.3 图像旋转

以图像的中心为原点,旋转一定的角度,也就是将图像上的所有像素都旋转一个相同的角度。旋转后图像的大小一般会改变,即可以把转出显示区域的图像截去,或者扩大图像范围来显示图像的所有部分。

图像的旋转变换也可以用矩阵变换来表示:

设点(x0, y0)逆时针旋转θ角后的对应点(x, y),那么旋转后的点(x, y)的坐标为:
在这里插入图片描述
所以旋转操作对应的变换矩阵M的形式为:
在这里插入图片描述
但是OpenCV提供了具有可调旋转中心的缩放旋转,因此可以在任何位置旋转和缩放。修正的变换矩阵由
在这里插入图片描述
其中:
在这里插入图片描述
旋转也是仿射变换的一种,所以操作的函数还是cv2.warpAffine,但是它的变换矩阵一般不像平移那样简单,所以OpenCV提供了一个专门求图像旋转变换矩阵的函数:

retval = cv2.getRotationMatrix2D(center, angle, scale)

参数:

  1. center:图片的旋转中心。
  2. angle:旋转角度。
  3. 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  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 )

参数:

  1. src:原图像中三个点的坐标。
  2. 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] )

参数:

  1. src:表示透视变换前的4个点的位置。
  2. dst:表示透视变换后的4个对应点的位置。

ps:与仿射变换不同的是,这里需要四个点来确定M矩阵。

函数cv2.warpPerspective

dst	= cv2.warpPerspective( src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] )

参数:

  1. src:原始图像。
  2. M:透视变换矩阵。
  3. dsize:输出图像的尺寸。
  4. 其他同上。

看个例子:

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]]

输出的结果图像:
在这里插入图片描述

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, 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()

结果如下图所示:
在这里插入图片描述
以上就是图像常用的几何变化操作,下次笔记学习图像的滤波与增强以及图像形态学的知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

课后作业和动手动脑

一,运行TestInherits.java 通过super调用基类构造方法,必是子类构造方法中的第一个语句。 二.为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来? 构造函数的主要作用…

OpenCV与图像处理学习五——图像滤波与增强:线性、非线性滤波、直方图均衡化与Gamma变换

OpenCV与图像处理学习五——图像滤波与增强:线性、非线性滤波、直方图均衡化与Gamma变换三、图像滤波与增强3.1 线性滤波3.1.1 方框滤波3.1.2 均值滤波3.1.3 高斯滤波3.1.4 一般卷积滤波3.2 非线性滤波3.2.1 中值滤波3.2.2 双边滤波3.3 图像直方图均衡化3.3.1 单通道…

张钹院士:人工智能技术已进入第三代

来源:经济观察报近日,中科院院士、清华大学人工智能研究院院长张钹教授接受记者采访时认为,目前基于深度学习的人工智能在技术上已经触及天花板。从长远来看,必须得走人类智能这条路,最终要发展人机协同,人…

软件工程作业

典型用户1 名字老陈性别,年龄男,40岁职业教师收入两万/年知识层次和能力本科,熟练计算机操作生活、工作情况教书,辅导孩子完成作业动机,目的,困难希望节省辅导孩子的时间,用于自己的业务工作用户…

numpy.ndarray索引/切片方式

注意:获得多维数组的前三个子数组不能用array[0,1,2],应该用 array[0:3],如下例子: a np.random.random([85, 7794, 64]) b a[0:3] print(np.shape(b)) # (3, 7794, 64)

OpenCV与图像处理学习六——图像形态学操作:腐蚀、膨胀、开、闭运算、形态学梯度、顶帽和黑帽

OpenCV与图像处理学习六——图像形态学操作:腐蚀、膨胀、开、闭运算、形态学梯度、顶帽和黑帽四、图像形态学操作4.1 腐蚀和膨胀4.1.1 图像腐蚀4.1.2 图像膨胀4.2 开运算与闭运算4.2.1 开运算4.2.2 闭运算4.3 形态学梯度(Gradient)4.4顶帽和黑…

解密硅谷大骗局

来源:硅谷封面企鹅号、腾讯科技在许多为人称道的科技创业故事中,总不乏硅谷的名字。从英特尔、IBM到微软、苹果,从雅虎、谷歌到Twitter、Facebook,这里诞生了很多知名科技企业。对于全球的创业者来说,硅谷就是梦想中的…

OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)

OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)一、固定阈值图像分割1.1 直方图双峰法1.2 OpenCV中的固定阈值分割二、自动阈值图像分割2.1 自适应阈值法2.2 迭代法阈值分割2.3 Otsu大津阈值法前面的笔记介绍了一些Op…

Foxmail 绑定企业邮箱

转载于:https://www.cnblogs.com/wu628/p/4955017.html

边缘计算将吞掉云计算!

来源:CSDN以下为译文:边缘计算已成为物联网的重要趋势。高德纳咨询公司认为边缘计算是2019年的一项技术趋势。各个物联网公司发现在将数据发送到云之前,通过边缘计算处理数据有很大的好处。最近Micron/Forrester的调查证实了这一趋势&#xf…

OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)

OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)一、图像梯度1.1 梯度1.2 图像梯度二、梯度图与梯度算子2.1模板卷积2.2 梯度图2.3 梯度算子2.3.1 Roberts交叉算子2.3.2 Prewitt算子2.3.3 Sobel算子三、Canny边缘检测算法(代码实现&a…

面向人工智能的计算机体系结构

来源:计算机研究与发展前 言近几年来人工智能技术的飞速发展使得其应用迅猛扩大,而传统的计算机体系结构对于面向人工智能的应用在处理速度、能耗、使用的方便性等方面有着诸多不足。随着人工智能应用的发展,面向人工智能的体系结构成为体系结…

OpenCV与图像处理学习九——连通区域分析算法(含代码)

OpenCV与图像处理学习九——连通区域分析算法(含代码)一、连通区域概要二、Two-Pass算法三、代码实现一、连通区域概要 连通区域(Connected Component)一般是指图像中具有相同像素值且位置相邻的前景像素点组成的图像区域&#x…

(180页PPT)|清华大学孙富春教授深度讲解: 人工智能技术与产业发展

来源:精智工厂[导读】本文是清华大学孙富春教授在机械工业出版社讲座交流PPT,孙教授从背景与历史、深度学习、脑认知、产业(装备)发展、发展趋势等五个方面详细解读了人工智能技术与产业发展。未来智能实验室是人工智能学家与科学…

OpenCV与图像处理学习十——区域生长算法(含代码)

OpenCV与图像处理学习十——区域生长算法(含代码)一、区域生长算法概要二、区域生长算法原理三、代码应用一、区域生长算法概要 区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入…

FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated

使用scipy模块时出现警告:FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use arr[tuple(seq)] instead of arr[seq]. In the future this will be interpreted as an array index, arr[np.array(seq)], which will resu…

一文看懂中国MEMS传感器产业链

来源:通信产业网物联网对促进我国经济发展、优化产业结构具有重大的战略意义。而在整个物联网生态中,MEMS传感器扮演着越来越重要的角色,在即将到来的智能物联网时代中将起到核心作用,为新科技产品提供更智能、更敏锐的感知能力。…

OpenCV与图像处理学习十一——分水岭算法(含代码)

OpenCV与图像处理学习十一——分水岭算法(含代码)一、分水岭算法概要二、分水岭算法步骤三、代码应用一、分水岭算法概要 任意的灰度图像可以被看做是地质学表面,高亮度的地方是山峰,低亮度的地方是山谷。 给每个孤立的山谷&…

10件5G能实现但4G不能做的事情

来源:雷锋网 5G的一些最佳用途可能还没有被发现,但下面是我们已经知道的十个令人兴奋的用途。雷锋网按;2019年6月6日,工信部正式向中国电信、中国移动、中国联通、中国广电发放5G商用牌照,这表明中国正式进入了5G商用的…

OpenCV与图像处理学习十二——图像形状特征之HOG特征

OpenCV与图像处理学习十二——图像形状特征之HOG特征一、图像特征理解1.1 颜色特征1.2 纹理特征1.3 形状特征1.4 空间关系特征二、形状特征描述2.1 HOG特征2.1.1 基本概念2.1.2 HOG实现过程2.1.3 代码实现前面介绍了图像的基础知识、基本处理方法以及传统图像分割的应用&#x…