OpenCV轻松入门_面向python(第五章几何变换)

几何变换 是指将一幅图像映射到另外一幅图像内的操作。
OpenCv中常用映射: 缩放、翻转、仿射变换、透视、重映射等。

5.1缩放

函数cv2.resize()实现对图像的缩放,具体形式:
dst = cv2.resize( src, dsize[, fx[, fy[, interpolation]]] )

  • dst 代表输出的目标图像,该图像的类型与 src 相同,其大小为 dsize(当该值非零时),或者可以通过 src.size()、fx、fy 计算得到。
  • src 代表需要缩放的原始图像。
  • dsize 代表输出图像大小。
  • fx 代表水平方向的缩放比例。
  • fy 代表垂直方向的缩放比例。
  • interpolation 代表插值方式。
类型 说明
cv2.INTER_NEAREST 最临近插值
cv2.INTER_LINEAR 双线性插值(默认方式)
cv2.INTER_CUBIC 三次样条插值 。 首先对源图像邻近的 4×44 \times 44×4 区域进行三次样条拟合,然后将目标像素对应的三次样条条件作为目标图像对应像素的值
cv2.INTER_AREA 区域插值。 根据当前像素点周边区域的像素采样来计算像素的采样。该方法类似临近插值方式
cv2.INTER_LANCZOS4 一种使用 8×88 \times 88×8 邻域的 Lanczos 插值方法
cv2.INTER_LINEAR_EXACT 位精确双线性插值
cv2.INTER_MAX 插值编码掩码
cv2.WARP_FILL_OUTLIERS 标志,填补目标图像中的所有像素。 如果它们中的一些对应源图像中的奇异点(离群值),则将它们设置为零
cv2.WARP_INVERSE_MAP 标志:逆变换 。 例如,极坐标变换: • 如果 flag 未被设置,则进行转换:dst(φ,ρ)=src(x,y)dst(\varphi,\rho) = src(x,y)dst(φ,ρ)=src(x,y) • 如果 flag 被设置,则进行转换:dst(x,y)=src(φ,ρ)dst(x,y) = src(\varphi,\rho)dst(x,y)=src(φ,ρ)

在 cv2.resize()函数中,目标图像的大小可以通过"参数 dsize"或者"参数 fx 和 fy"二者之一来指定

  • 通过参数dsize指定
    如果指定参数 dsize 的值,则无论是否指定了参数 fx 和 fy 的值,都由参数 dsize 来决定目
    标图像的大小。
    dsize 内第 1 个参数对应缩放后图像的宽度(width,即列数 cols,与参数 fx 相关),第 2 个参数对应缩放后图像的高度(height,即行数 rows,与参数 fy 相关)。
    在 dsize 参数中,第 1 个值对应的是列数 ,第 2 个值对应的是行数
  • 通过参数fx和参数fy指定
    如果参数 dsize 的值是 None,那么目标图像的大小通过参数 fx 和 fy 来决定。此时,目标
    图像的大小为:
    dsize=Size(round(fx*src.cols),round(fy*src.rows))

插值 是指在对图像进行几何处理时,给无法直接通过映射得到值的像素点赋值。

当缩小图像时,使用区域插值方式(INTER_AREA) 能够得到最好的效果;当放大图像时,使用三次样条插值(INTER_CUBIC) 方式和双线性插值(INTER_LINEAR) 方式都能够取得较好的效果。三次样条插值方式速度较慢,双线性插值方式速度相对较快且效果并不逊色。

使用函数 cv2.resize()对一个数组进行简单缩放。

python 复制代码
import cv2  
import numpy as np  
img = np.ones([2,4,3],dtype=np.uint8)  
size = img.shape[:2]  
rst = cv2.resize(img,size)  
print("img.shape=\n",img.shape)  
print("img=\n",img)  
print("rst.shape=\n",rst.shape)  
print("rst=\n",rst)
#在 shape 属性中,第 1 个值对应的是行数,第 2 个值对应的是列数。
#在 dsize 参数中,第 1 个值对应的是列数,第 2 个值对应的是行数。

使用函数 cv2.resize()完成一个简单的图像缩放。

python 复制代码
import cv2  
import numpy as np  
img = cv2.imread("lena.jpg")  
row,cols=img.shape[:2]  
size=(int(cols*0.9),int(row*0.5))  
rst=cv2.resize(img,size)  
print("img.shape=\n",img.shape)  
print("rst.shape=\n",rst.shape)

控制函数 cv2.resize()的 fx 参数、fy 参数,完成图像缩放。

python 复制代码
import cv2  
img = cv2.imread("lena.jpg")  
rst=cv2.resize(img,None,fx=2,fy=0.5)  
print("img.shape=",img.shape)  
print("rst.shape=",rst.shape)

5.2翻转

在 OpenCV 中,图像的翻转采用函数 cv2.flip()实现,该函数能够实现图像在水平方向翻转垂直方向翻转两个方向同时翻转,其语法结构为:

dst = cv2.flip( src, flipCode )

  • dst 代表和原始图像具有同样大小、类型的目标图像。
  • src 代表要处理的原始图像。
  • flipCode 代表旋转类型。
    • 参数值=0 绕着x轴翻转
    • 参数值>0 绕着y轴翻转
    • 参数值<0 围绕x轴、y轴翻转
python 复制代码
import cv2  
img = cv2.imread("lena.jpg")  
x=cv2.flip(img,0)  
y=cv2.flip(img,1)  
xy=cv2.flip(img,-1)  
cv2.imshow("img",img)  
cv2.imshow("x",x)  
cv2.imshow("y",y)  
cv2.imshow("xy",xy)  
cv2.waitKey()  
cv2.destroyAllWindows()

5.3仿射

仿射变换 是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性和平行性。

OpenCV 中的仿射函数为 cv2.warpAffine(),其通过一个变换矩阵(映射矩阵)M 实现变换

用仿射函数 cv2.warpAffine()实现对图像的旋转,该函数的语法格式如下:
dst = cv2.warpAffine( src, M, dsize[, flags[, borderMode[, borderValue]]] )

  • dst 代表仿射后的输出图像,该图像的类型和原始图像的类型相同。dsize 决定输出图像
  • src代表要仿射的原始图像。
  • M 代表一个 2×3 的变换矩阵。使用不同的变换矩阵,就可以实现不同的仿射变换。
  • dsize 代表输出图像的尺寸大小。
  • flags 代表插值方法,默认为 INTER_LINEAR。当该值为 WARP_INVERSE_MAP 时,意味着 M 是逆变换类型,实现从目标图像 dst 到原始图像 src 的逆变换。的实际大小。
  • borderMode 代表边类型, 默认为 BORDER_CONSTANT 。当该值为 BORDER_TRANSPARENT 时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。
  • borderValue 代表边界值,默认是 0。
    通过转换矩阵 M 将原始图像 src 转换为目标图像 dst:
    dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23) dst(x,y)=src(M_{11}x+M_{12}y+M_{13},M_{21}x+M_{22}y+M_{23}) dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23)

平移

可以理解为 :每个像素点的坐标单独做矩阵乘法 以达到整个图像的像素点平移

如果将原始图像 src 向右侧移动 100 个像素、向下方移动 200 个像素,则其对应关系为:
dst(x,y)=src(x+100,y+200)dst (x, y) = src (x + 100, y + 200)dst(x,y)=src(x+100,y+200)

即:
dst(x,y)=src(1⋅x+0⋅y+100,0⋅x+1⋅y+200)dst (x, y) = src (1·x + 0·y + 100, 0·x + 1·y + 200)dst(x,y)=src(1⋅x+0⋅y+100,0⋅x+1⋅y+200)

转换矩阵MMM为:
M=[1010001200] M = \begin{bmatrix} 1 & 0 & 100 \\ 0 & 1 & 200 \end{bmatrix} M=[1001100200]

利用自定义转换矩阵完成图像平移。

python 复制代码
import cv2  
import numpy as np  
img = cv2.imread("lena.jpg")  
heigh,width =img.shape[:2]  
x=100  
y=200  
M = np.float32([[1,0,x],  
                [0,1,y]])  
move=cv2.warpAffine(img,M,(width,heigh))  
cv2.imshow("original",img)  
cv2.imshow("move",move)  
cv2.waitKey()  
cv2.destroyAllWindows()

旋转

在使用函数 cv2.warpAffine()对图像进行旋转时,可以通过函数 cv2.getRotationMatrix2D()

获取转换矩阵M 。该函数的语法格式为:
M=cv2.getRotationMatrix2D(center, angle, scale)

  • center为旋转的中心点
  • angle为旋转角度,正数 表示 时针旋转,负数 表示时针旋转。
  • scale为变化尺度(缩放大小)。

图像旋转

python 复制代码
import cv2  
import numpy as np  
img = cv2.imread("D:\openCV\lena.jpg")  
heigh,width = img.shape[:2]  
M = cv2.getRotationMatrix2D((heigh/2,width/2),45,0.6)  
rotate = cv2.warpAffine(img,M,(width,heigh))  
cv2.imshow("original",img)  
cv2.imshow("rotate",rotate)  
cv2.waitKey()  
cv2.destroyAllWindows()

更复杂的仿射变换

函数 cv2.getAffineTransform()来生成仿射函数 cv2.warpAffine()所使用的转换矩阵 M

语法格式:
M=cv2.getAffineTransform(src, dst)

  • src代表输入图像三个点坐标
  • dst代表输出图像三个点坐标
    参数通过函数cv2.getAffineTransform()定义了两个平行四边形。src 和 dst 中的三个点分别对应平行四边形的左上角、右上角、左下角三个点。
python 复制代码
import cv2  
import numpy as np  
img = cv2.imread("lena.jpg")  
rows,cols,ch=img.shape  
p1=np.float32([[0,0],  
               [cols-1,0],  
               [0,rows-1]])  
p2=np.float32([[0,rows*0.33],  
               [cols*0.85,rows*0.25],  
               [cols*0.15,rows*0.7]])  
M = cv2.getAffineTransform(p1,p2)  
dst = cv2.warpAffine(img,M,(cols,rows))  
cv2.imshow("original",img)  
cv2.imshow("dst",dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

5.4透视

仿射变换可以将矩形映射为任意平行四边形 ,透视变换则可以将矩形映射为任意四边形

透视变换通过函数 cv2.warpPerspective()实现,该函数的语法是:
dst = cv2.warpPerspective( src, M, dsize[, flags[, borderMode[, borderValue]]] )

  • dst 代表透视处理后的输出图像,该图像和原始图像具有相同的类型。dsize 决定输出图像的实际大小。
  • src 代表要透视的图像。
  • M 代表一个 3×3 的变换矩阵。
  • dsize 代表输出图像的尺寸大小。
  • flags 代表插值方法,默认为 INTER_LINEAR。当该值为 WARP_INVERSE_MAP 时,意味着 M 是逆变换类型,能实现从目标图像 dst 到原始图像 src 的逆变换。
  • borderMode 代表边类型, 默认为 BORDER_CONSTANT 。当该值为 BORDER_TRANSPARENT 时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。
    使用函数cv2.warpPerspective()生成转换矩阵M
    M = cv2.getPerspectiveTransform( src, dst )
  • src 代表输入图像的四个顶点的坐标。
  • dst 代表输出图像的四个顶点的坐标。

5.5重映射

重映射: 把一幅图像内的像素点放置到另外一幅图像内的指定位置,通过修改像素点的位置得到一幅新图像

的重映射函数cv2.remap()

语法格式:
dst = cv2.remap( src, map1, map2, interpolation[, borderMode[, borderValue]] )

  • dst 代表目标图像,它和 src 具有相同的大小和类型。
  • src 代表原始图像。
  • map1 参数有两种可能的值:
    • 表示(x,y)点的一个映射。
    • 表示 CV_16SC2 , CV_32FC1, CV_32FC2 类型(x,y)点的 x 值。
  • map2 参数同样有两种可能的值:
    • 当 map1 表示(x,y)时,该值为空。
    • 当 map1 表示(x,y)点的 x 值时,该值是 CV_16UC1, CV_32FC1 类型(x,y)点的 y 值。
  • Interpolation 代表插值方式,这里不支持 INTER_AREA 方法。
  • borderMode 代表边界模式。当该值为 BORDER_TRANSPARENT 时,表示目标图像内的对应源图像内奇异点(outliers)的像素不会被修改。
  • borderValue 代表边界值,该值默认为 0。

映射参数的理解

映射函数的作用是查找新图像像素在原始图像内的位置。将新图像像素映射到原始图像的过程被称为反向映射

需要注意的是,函数 cv2.remap()中参数 map1 指代的是像素点所在位置的列号,参数 map2指代的是像素点所在位置的行号。

使用 cv2.remap()完成数组映射

python 复制代码
import cv2  
import numpy as np  
img = np.random.randint(0,256,size = [4,5],dtype=np.uint8)  
rows,cols = img.shape[0:2]  
mapx = np.ones(img.shape,np.float32)*3  
mapy = np.ones(img.shape,np.float32)*0  
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
print("img=\n",img)  
print("mapx=\n",mapx)  
print("mapy=\n",mapy)  
print("rst=\n",rst)

复制

用函数 cv2.remap()实现数组复制

相当与img[mapy,mapx]赋值给了rst

pyhton 复制代码
import cv2  
import numpy as np  
img = np.random.randint(0,256,size=[4,5],dtype=np.uint8)  
rows,cols=img.shape[0:2]  
mapx = np.zeros(img.shape,np.float32)  
mapy = np.zeros(img.shape,np.float32)  
for i in range(rows):  
    for j in range(cols):  
        mapx[i,j]=j  
        mapy[i,j]=i  
rst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
print("img=\n",img)  
print("mapx=\n",mapx)  
print("mapy=\n",mapy)  
print("rst=\n",rst)

绕x轴翻转

让图像绕着 x 轴翻转,意味着在映射过程中:

  • x 坐标轴的值保持不变。
  • y 坐标轴的值以 x 轴为对称轴进行交换。
    用函数 cv2.remap()实现数组绕 x 轴翻转
python 复制代码
import cv2  
import numpy as np  
img = np.random.randint(0,256,size=[4,5],dtype=np.uint8)  
rows,cols=img.shape[0:2]  
mapx = np.zeros(img.shape,np.float32)  
mapy = np.zeros(img.shape,np.float32)  
for i in range(rows):  
    for j in range(cols):  
        mapx[i,j]=j  
        mapy[i,j]=rows-i-1  
rst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
print("img=\n",img)  
print("mapx=\n",mapx)  
print("mapy=\n",mapy)  
print("rst=\n",rst)

使用函数 cv2.remap()实现图像绕 x 轴的翻转

python 复制代码
import cv2  
import numpy as np  
img = cv2.imread("lena.jpg")  
rows,cols = img.shape[0:2]  
mapx = np.zeros(img.shape[:2],np.float32)  
mapy = np.zeros(img.shape[:2],np.float32)  
for i in range(rows):  
    for j in range(cols):  
        mapx[i,j]=j  
        mapy[i,j]=rows-1-i  
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
cv2.imshow("original",img)  
cv2.imshow("result",rst)  
cv2.waitKey()  
cv2.destroyAllWindows()

绕y轴翻转

让图像绕着 y 轴翻转,意味着在映射过程中:

  • y 坐标轴的值保持不变。
  • x 坐标轴的值以 y 轴为对称轴进行交换。

用函数 cv2.remap()实现数组绕 y 轴翻转。

python 复制代码
import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)
rows,cols=img.shape
mapx = np.zeros(img.shape,np.float32)
mapy = np.zeros(img.shape,np.float32)
for i in range(rows):
	for j in range(cols):
		mapx[i,j]=cols-1-j
		mapy[i,j]=i
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print("img=\n",img)
print("mapx=\n",mapx)
print("mapy=\n",mapy)
print("rst=\n",rst)

使用函数 cv2.remap()实现图像绕 y 轴的翻转

python 复制代码
import cv2
import numpy as np
img=cv2.imread("lena.bmp")
rows,cols=img.shape[:2]
mapx = np.zeros(img.shape[:2],np.float32)
mapy = np.zeros(img.shape[:2],np.float32)
for i in range(rows):
	for j in range(cols):
		mapx[i,j]=cols-1-j
		mapy[i,j]=i
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()

绕x轴、y轴翻转

让图像绕着 x 轴、y 轴翻转,意味着在映射过程中:

  • x 坐标轴的值以 y 轴为对称轴进行交换。
  • y 坐标轴的值以 x 轴为对称轴进行交换。

用函数 cv2.remap()实现数组绕 x 轴、y 轴翻转

python 复制代码
import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)
rows,cols=img.shape
mapx = np.zeros(img.shape,np.float32)
mapy = np.zeros(img.shape,np.float32)
for i in range(rows):
	for j in range(cols):
		mapx[i,j]=cols-1-j
		mapy[i,j]=rows-1-i

rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print("img=\n",img)
print("mapx=\n",mapx)
print("mapy=\n",mapy)
print("rst=\n",rst)

用函数 cv2.remap()实现图像绕 x 轴、y 轴翻转

python 复制代码
import cv2
import numpy as np
img=cv2.imread("lena.jpg")
rows,cols=img.shape[:2]
mapx = np.zeros(img.shape[:2],np.float32)
mapy = np.zeros(img.shape[:2],np.float32)
for i in range(rows):
	for j in range(cols):
		mapx[i,j]=cols-1-j
		mapy[i,j]=rows-1-i
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()

x轴、y轴互换

让图像的 x 轴、y 轴互换,意味着在映射过程中,对于任意一点,都需要将其 x 轴、y 轴坐标互换。

  • mapx 的值调整为所在行的行号。
  • mapy 的值调整为所在列的列号。

用函数 cv2.remap()实现数组的 x 轴、y 轴互换

类似于矩阵的转置,但出现行、列不同时会自动补0

使用函数 cv2.remap()实现数组的 x 轴、y 轴互换

python 复制代码
import cv2  
import numpy as np  
img=np.random.randint(0,256,size=[4,6],dtype=np.uint8)  
rows,cols=img.shape[0:2]  
mapx = np.zeros(img.shape,np.float32)  
mapy = np.zeros(img.shape,np.float32)  
for i in range(rows):  
    for j in range(cols):  
        mapx[i,j]=i  
        mapy[i,j]=j  
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
print("img=\n",img)  
print("mapx=\n",mapx)  
print("mapy=\n",mapy)  
print("rst=\n",rst)

使用函数 cv2.remap()实现图像的 x 轴、y 轴互换

python 复制代码
import cv2  
import numpy as np  
img=cv2.imread("lena.jpg")  
rows,cols=img.shape[:2]  
mapx = np.zeros(img.shape[:2],np.float32)  
mapy = np.zeros(img.shape[:2],np.float32)  
for i in range(rows):  
    for j in range(cols):  
        mapx[i,j]=i  
        mapy[i,j]=j  
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  
cv2.imshow("original",img)  
cv2.imshow("result",rst)  
cv2.waitKey()  
cv2.destroyAllWindows()

图像缩放

python 复制代码
import cv2  
import numpy as np  
img=cv2.imread("lena.jpg")  
rows,cols=img.shape[:2]  
mapx = np.zeros(img.shape[:2],np.float32)  
mapy = np.zeros(img.shape[:2],np.float32)  
for i in range(rows):  
    for j in range(cols):  
        if 0.25*cols<i<0.75*cols and 0.25*rows<j<0.75*rows:  
            mapx[i,j]=2*(j-cols*0.25)+0.5  
            mapy[i,j]=2*(i-rows*0.25)+0.5  
        else:  
            mapx[i,j]=0  
            mapy[i,j]=0  
rst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)  
cv2.imshow("original",img)  
cv2.imshow("result",rst)  
cv2.waitKey()  
cv2.destroyAllWindows()

疑问: OpenCv中明明有专门进行翻转、缩放的函数,为什么还要使用重映射函数进行翻转、缩放呢?

操作对象的抽象层级不同

函数 关注层级 原理
cv2.flip / cv2.resize 整幅图像或整体规则 内部写死了某种几何变换(翻转、缩放),直接调用即可
cv2.remap 像素级别 你要自己告诉 OpenCV:目标图像里的每个像素,该去源图像的哪个位置采样
  • cv2.flipcv2.resizecv2.warpAffinecv2.warpPerspective
    👉 只能做 固定的线性或简单几何变换
  • cv2.remap
    👉 可以做 任意非线性映射
相关推荐
阿里云大数据AI技术2 小时前
云上AI推理平台全掌握(6):大规模EP专家并行
人工智能
电商软件开发 小银2 小时前
wo店模式兴起旧模式式微:本地生活服务市场的深度变革
大数据·人工智能·商业模式·本地生活·数字化生活·实体店转型·wo店模式
泰迪智能科技2 小时前
泰迪智能科技分享数据挖掘定义、主要方法、预处理、应用领域
人工智能·科技·数据挖掘
Q_Q19632884752 小时前
python+django/flask+springboot个性化旅游推荐系统(数据可视化) 景点推荐 路线匹配 用户画像建模 智能搜索筛选 图文展示系统
spring boot·python·django·flask·node.js
爱隐身的官人2 小时前
Tomcat 相关漏洞扫描器(一)
python·web安全·tomcat
GIS好难学3 小时前
【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(2):智慧城市西安与一带一路
人工智能·信息可视化·智慧城市·webgis
jerryinwuhan3 小时前
数据挖掘清洗实战项目目录
人工智能·数据挖掘
debug 小菜鸟3 小时前
Python + Flask + API Gateway + Lambda + EKS 实战
python·flask·gateway
sunnyday04263 小时前
Spring Boot中Bean Validation的groups属性深度解析
spring boot·后端·python