几何变换
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了几何变换相关的知识,希望对你有一定的参考价值。
参考技术A 几何变换是指将一幅图像映射到另一副图像内的操作,根据映射关系的不同,有缩放、翻转、仿射变换、透视、重映射等。在OpenCV中使用函数cv2.resize()实现对图像的缩放:
cv2.resize(src, dsize[,fx[,fy[, interpolation]]])
src :代表要缩放的原始图像;
dsize : 代表输出图像大小,第一个值为目标图像的宽度,第二个值为目标图像的高度
fx : 代表水平方向的缩放比
fy : 代表垂直方向的缩放比
interpolation: 代表插值方式。插值是指在对图像进行几何处理时,给无法直接通过映射得到值的像素点赋值。当缩小图像时,使用区域插值方式( INTER_AREA)能够得到最好的效果;当放大图像时,使用三次样条插值(INTER_CUBIC)方式和双线性插值(INTER_LINEAR)方式都能得到较好的效果。三次样条插值方式速度较慢,双线性插值方式速度相对较快且效果并不逊色。
【注】:fx、fy只要当dsize=None时才起作用。
import cv2
import numpyas np
img = cv2.imread('wasser_2.jpg')
shape_img = img.shape
print(shape_img)
biger_img = cv2.resize(img,(720,480),interpolation=cv2.INTER_LINEAR)
smaller_img = cv2.resize(img,None,fx=0.8,fy=0.8,interpolation=cv2.INTER_AREA)
cv2.imshow('img',img)
cv2.imshow('biger_img',biger_img)
cv2.imshow('smaller_img',smaller_img)
return_value = cv2.waitKey(0)
cv2.destroyAllWindows()
在OpenCV中,图像的翻转采用函数cv2.flip()实现,该函数能实现水平方向、垂直方向、两个方向同时翻转。
dst = cv2.flip(src, flipCode)
src : 表示要处理的图像;
flipCode : 表示旋转类型,为0时,表示绕X轴旋转;为正数,表示绕y轴旋转;为负数,表示绕x、y轴同时旋转。
dst: 返回和原图像有相同大小和类型的目标图像。
img = cv2.imread('wasser_2.jpg')
shape_img = img.shape
print(shape_img)
x_img = cv2.flip(img,1)
xy_img = cv2.flip(img,-1)
cv2.imshow('img',img)
cv2.imshow('x_img',x_img)
cv2.imshow('xy_img',xy_img)
return_value = cv2.waitKey(0)
cv2.destroyAllWindows()
仿射是指图像可以经过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性(变换前后,直线仍是直线)和平行性(变换前后,平行线仍是平行线)。
OpenCV中的仿射函数是cv2.warpAffine(),其通过一个变换矩阵M实现变换,具体为:
dst = cv2.warpAffine(src,M,dsize[,flags[,borderMode[,borderValue]]])
dst: 表示输出图像,它和原始图像有相同的类型,大小由dsize决定;
src: 表示原始图像;
M: 代表一个2X3的变换矩阵。
dsize: 输出图像的尺寸大小;
flags : 代表插值方法,默认为INTER_LINEAR。当该值是WARP_INVERSE_MAP时,意味着M是逆变换矩阵,实现从目标图像dst到原始图像src的逆变换。
borderModer : 代表边类型,默认为BORDER_CONSTANT.当该值为BORDER_TRANSPARENT时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。
borderValue : 代表边界值,默认是0.
1)平移
平移的矩阵M:
M = [[1,0,x],[0,1,y]]
将图像水平向右移动100像素,垂直向下平移150像素。
import cv2
import numpyas np
img = cv2.imread('wasser_2.jpg')
shape_img = img.shape
print(shape_img)
M = np.float32([[1,0,100],[0,1,150]])
warp_img = cv2.warpAffine(img,M,(shape_img[1],shape_img[0]))
rut_warp_img = cv2.warpAffine(img,M,(shape_img[1],shape_img[0]),borderMode=cv2.BORDER_TRANSPARENT)
cv2.imshow('img',img)
cv2.imshow('warp_img',warp_img)
cv2.imshow('rut_warp_img',rut_warp_img)
return_value = cv2.waitKey(0)
cv2.destroyAllWindows()
2)旋转
在使用wrapAffine()对图像进行旋转时,可以通过函数cv2.getRotationMatrix2D(center,angle,scale)获取转换矩阵。其中:
center为旋转中心;
angle为旋转角度;
scale为变换尺度。
例如:以图像中心点为旋转中心,顺时针旋转45°,图像缩小到原来的0.6倍。
img = cv2.imread('wasser_2.jpg')
height,width = img.shape[:2]
M = cv2.getRotationMatrix2D((width/2,height/2),45,0.6)
rota_img = cv2.warpAffine(img,M,(width,height))
cv2.imshow('img',img)
cv2.imshow('rota_img',rota_img)
3)更复杂的仿射
对于更复杂的仿射变换,Opencv提供了函数cv2.getAffineTransform()来生成仿射函数所需要的转换矩阵M.
cv2.getAffineTransform(src,dst)
src 代表输入图像的三个点坐标
dst 代表输出图像的三个点坐标
该函数定义了两个平行四边形,src和dst中的三个点分别对应平行四边形的左上角、右上角、左下角。它确定了原图像到目标图像的映射关系。
img = cv2.imread('wasser_2.jpg')
height,width = img.shape[:2]
# 确定两个平行四边形
p1 = np.float32([[0,0],[width-1,0],[0,height-1]])
p2 = np.float32([[0,height*0.33],[width*0.85,height*0.25],[height*0.2,height*0.7]])
M = cv2.getRotationMatrix2D((width/2,height/2),45,0.6)
retval = cv2.getAffineTransform(p1,p2)
rota_img = cv2.warpAffine(img,M,(width,height))
dst_img = cv2.warpAffine(img,retval,(width,height))
cv2.imshow('img',img)
cv2.imshow('rota_img',rota_img)
cv2.imshow('dst_img',dst_img)
仿射变换可以将矩形变成任意平行四边形,透视变换可以将矩形映射到任意四边形。
透视变换通过cv2.warpPerspective()实现:
dst = cv2.warpPerspective(src, M, dsize[,flags[,borderMode[,borderValue]]])
dsize :决定输出图像的大小
M :代表一个3X3的变换矩阵
flags: 代表差值方法,默认为INTER_LINEAR。当该值是WARP_INVERSE_MAP时,意味着M是逆变换类型
borderValue :代表边界值,默认是0
与仿射变换一样,同样可以使用一个函数来生成M:
cv2.getPerspectiveTransform(src,dst)
src,dst 都是一个包含四个坐标点的数组。
例如:
img = cv2.imread('wasser_2.jpg')
height,width = img.shape[:2]
# 确定两个平行四边形
p1 = np.float32([[0,0],[100,0],[0,50],[100,50]])
p2 = np.float32([[20,20],[50,30],[30,70],[70,60]])
retval = cv2.getPerspectiveTransform(p1,p2)
dst_img = cv2.warpPerspective(img, retval, (width,height))
cv2.imshow('img',img)
cv2.imshow('dst_img',dst_img)
把一幅图像的像素点放到另一幅图像的指定范围,这个过程称为图映射。OpenCV提供了多种重映射方式,其中dst = cv2.remap(src, map1, map2, interpolation[,borderMode[,borderValue]])
dst 和src有相同的大小和类型。
map1 参数都有两种可能的值:
1)表示(x,y)点的一个映射
2)表示CV_16SC2,CV_32FC1,CV_32FC2类型(x,y)点的x值
map1 参数同样有两种可能的值:
1)当map1表示(x,y)时,该值为空
2)当map1表示(x,y)点的x值时,该值是CV_16UC1,CV_32FC1类型(x,y)点的y值。
Interpolation代表插值方式,这里不支持INTER_AREA方法。
重映射通过修改像素点的位置得到一幅新图像。在构造新图像时,需要确定新图像中每一个像素点在原始图像中的位置,因此映射函数的作用是查找新图像在原始图像中的位置,该过程是将新图像映射到原始图像的过程,因此被称为反向映射。
在函数cv2.remap()中,参数map1和map2用来说明反向映射,map1针对的是坐标x,指代像素所在位置的列号,map2针对的是坐标y,指代像素所在位置的行号。map1和map2的值都是浮点数。因此目标函数可以映射回一个非整数的值,这意味着可以将目标图像“反向映射”到原始图像中两个像素之间的位置(这样的位置是不存在的)。这是采用不同的方法来插值处理。
将map1的值设为对应位置上的x轴坐标值
将map2的值设为对应位置上的y轴坐标值
假如想让图片绕X轴翻转,则图像x坐标不变,y坐标变为总行数-1-当前行号;
如果想让它绕y轴翻转,也同理:总列数-1-当前列号
将x轴的值调整为所在行的行号;将y轴的值调整为所在列的列号
注:如果行数和列数不等,可能出现存在值不能映射的情况。默认情况下,无法完成的值会被处理为0.
将图像缩小为原来的两倍,并居中处理:
结果如下:
OpenCV实现图像的几何变换
参考技术A 几何变换主要包括缩放、平移、旋转、仿射变换、透视变换和图像裁剪等。执行这些几何变换的两个关键函数是cv2.warpAffine()和cv2.warpPerspective()。cv2.warpAffine()函数使用以下2 x 3变换矩阵来变换源图像:
cv2.warpPerspective()函数使用以下3 x 3变换矩阵变换源图像:
接下来,我们将了解最常见的几何变换技术。
缩放图像时,可以直接使用缩放后图像尺寸调用cv2.resize():
除了上述用法外,也可以同时提供缩放因子fx和fy值。例如,如果要将图像缩小 2 倍:
如果要放大图像,最好的方法是使用cv2.INTER_CUBIC插值方法(较耗时)或cv2.INTER_LINEAR。如果要缩小图像,一般的方法是使用cv2.INTER_LINEAR。OpenCV提供的五种插值方法如下表所示:
显示缩放后的图像:
可以通过坐标系观察图片的缩放情况:
为了平移对象,需要使用NumPy数组创建2 x 3变换矩阵,其中提供了x和y方向的平移距离(以像素为单位):
其对应于以下变换矩阵:
创建此矩阵后,调用cv2.warpAffine()函数:
cv2.warpAffine()函数使用提供的 M 矩阵转换源图像。第三个参数 (width, height) 用于确定输出图像的大小。
例如,如果图片要在 x 方向平移 200 个像素,在 y 方向移动 30 像素:
平移也可以为负值,此时为反方向移动:
显示图片如下:
为了旋转图像,需要首先使用cv.getRotationMatrix2D()函数来构建2 x 3变换矩阵。该矩阵以所需的角度(以度为单位)旋转图像,其中正值表示逆时针旋转。旋转中心 (center) 和比例因子 (scale) 也可以调整,使用这些元素,以下方式计算变换矩阵:
其中:
以下示例构建 M 变换矩阵以相对于图像中心旋转 180 度,缩放因子为 1(不缩放)。之后,将这个 M 矩阵应用于图像,如下所示:
接下来使用不同的旋转中心进行旋转:
显示旋转后的图像:
在仿射变换中,首先需要使用cv2.getAffineTransform()函数来构建2 x 3变换矩阵,该矩阵将从输入图像和变换图像中的相应坐标中获得。最后,将 M 矩阵传递给cv2.warpAffine():
仿射变换是保留点、直线和平面的变换。此外,平行线在此变换后将保持平行。但是,仿射变换不会同时保留像素点之间的距离和角度。
可以通过以下图像观察仿射变换的结果:
为了进行透视变换,首先需要使用cv2.getPerspectiveTransform()函数创建3 x 3变换矩阵。该函数需要四对点(源图像和输出图像中四边形的坐标),函数会根据这些点计算透视变换矩阵。然后,将 M 矩阵传递给cv2.warpPerspective():
透视变换效果如下所示:
可以使用NumPy切片裁剪图像:
裁剪结果如下所示:
链接:https://juejin.cn/post/7035931986191450119
以上是关于几何变换的主要内容,如果未能解决你的问题,请参考以下文章