OpenCV学习笔记——图像几何变换

Posted 卡卡南安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV学习笔记——图像几何变换相关的知识,希望对你有一定的参考价值。

1. 缩放

dst = cv2.resize( src, dsize[, fx[, fy[, interpolation]]] )

  • dst 代表输出的目标图像,该图像的类型与src 相同,其大小为dsize(当该值非零时),或者可以通过src.size()、fx、fy 计算得到。
  • src 代表需要缩放的原始图像。
  • dsize 代表输出图像大小。
  • fx 代表水平方向的缩放比例。
  • code 是色彩空间转换码。
  • fy 代表垂直方向的缩放比例。
  • interpolation 代表插值方式,具体如表所示。

在 cv2.resize()函数中,目标图像的大小可以通过“参数dsize”或者“参数fx和fy”二者之一来指定,具体介绍如下。

  • 情况 1:通过参数dsize指定

如果指定参数dsize的值,则无论是否指定了参数fx和fy的值,都由参数dsize来决定目标图像的大小。此时需要注意的是,dsize内第1个参数对应缩放后图像的列数(width,即cols),第2个参数对应缩放后图像的行数(height,即行数rows)

  • 情况 2:通过参数fx和fy指定

如果参数dsize的值是None,那么目标图像的大小通过参数fx(控制列数)和fy(控制行数)来决定。此时,目标图像的大小为:

dsize=Size(round(fx·src.cols),round(fy·src.rows))

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

2. 翻转

dst = cv2.flip( src, flipCode )

  • dst 代表和原始图像具有同样大小、类型的目标图像。
  • src 代表要处理的原始图像。
  • flipCode 代表旋转类型。该参数的意义如表所示。

3. 仿射

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

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

  • dst 代表仿射后的输出图像,该图像的类型和原始图像的类型相同。
  • 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(𝑀11𝑥 + 𝑀12𝑦 + 𝑀13, 𝑀21𝑥 + 𝑀22𝑦 + 𝑀23)
因此,进行何种形式的仿射变换完全取决于转换矩阵M。下面分别介绍通过不同的转换矩阵M实现的不同的仿射变换。

3.1 平移

将原始图像src 向右侧移动100个像素、向下方移动200个像素,则其对应关系为:
dst (x, y) = src (x + 100, y + 200)
将上述表达式补充完整,即:
dst (x, y) = src (1·x + 0·y + 100, 0·x + 1·y + 200)
由此可得转换矩阵M为:

设计程序如下:

import cv2
import numpy as np
img=cv2.imread("lena.bmp")
height,width=img.shape[:2]
x=100
y=200
M = np.float32([[1, 0, x], [0, 1, y]])
move=cv2.warpAffine(img,M,(width,height))
cv2.imshow("original",img)
cv2.imshow("move",move)
cv2.waitKey()
cv2.destroyAllWindows()

3.2 旋转

在使用函数 cv2.warpAffine()对图像进行旋转时,可以通过函数cv2.getRotationMatrix2D()获取转换矩阵。该函数的语法格式为:

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

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

利用函数cv2.getRotationMatrix2D()可以直接生成要使用的转换矩阵M。例如,想要以图像中心为圆点,逆时针旋转45°,并将目标图像缩小为原始图像的0.6 倍:

import cv2
img=cv2.imread("lena.bmp")
height,width=img.shape[:2]
M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)
rotate=cv2.warpAffine(img,M,(width,height))
cv2.imshow("original",img)
cv2.imshow("rotation",rotate)
cv2.waitKey()
cv2.destroyAllWindows()

3.3 更复杂的仿射变换

对于更复杂仿射变换,OpenCV 提供了函数cv2.getAffineTransform()来生成仿射函数cv2.warpAffine()所使用的转换矩阵M。该函数的语法格式为:

retval=cv2.getAffineTransform(src, dst)

  • src 代表输入图像的三个点坐标。
  • dst 代表输出图像的三个点坐标。

在该函数中,其参数值src和dst是包含三个二维数组(x, y)点的数组。上述参数通过函数cv2.getAffineTransform()定义了两个平行四边形。src和dst中的三个点分别对应平行四边形的左上角、右上角、左下角三个点。函数cv2.warpAffine()以函数cv2.getAffineTransform()获取的转换矩阵M 为参数,将src中的点仿射到dst中。函数cv2.getAffineTransform()对所指定的点完成映射后,将所有其他点的映射关系按照指定点的关系计算确定。

import cv2
import numpy as np
img=cv2.imread('lena.bmp')
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("origianl",img)
cv2.imshow("result",dst)
cv2.waitKey()
cv2.destroyAllWindows()

在本例中,首先构造了两个三分量的点集合p1和p2,分别用来指代原始图像和目标图像内平行四边形的三个顶点(左上角、右上角、左下角)。然后使用M=cv2.getAffineTransform(p1,p2)获取转换矩阵M。接下来,dst=cv2.warpAffine(img,M,(cols,rows))完成了从原始图像到目标图像的仿射。

4. 透视

第三节所讲的仿射变换可以将矩形映射为任意平行四边形,透视变换则可以将矩形映射为任意四边形。

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

  • dst 代表透视处理后的输出图像,该图像和原始图像具有相同的类型。
  • src 代表要透视的图像。
  • M 代表一个3×3的变换矩阵。
  • dsize 代表输出图像的尺寸大小。
  • flags 代表插值方法,默认为INTER_LINEAR。当该值为WARP_INVERSE_MAP 时,意味着M 是逆变换类型,能实现从目标图像dst 到原始图像src 的逆变换。
  • borderMode 代表边类型, 默认为BORDER_CONSTANT 。当该值为BORDER_TRANSPARENT 时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值。
  • borderValue 代表边界值,默认是0。

与仿射变换一样,同样可以使用一个函数来生成函数cv2.warpPerspective()所使用的转换矩阵。该函数是cv2.getPerspectiveTransform(),其语法格式为:

retval = cv2.getPerspectiveTransform( src, dst )

  • src 代表输入图像的四个顶点的坐标。
  • dst 代表输出图像的四个顶点的坐标。

需 要 注 意 的 是 , src参数和dst参数是包含四个点的数组, 与仿射变换函数cv2.getAffineTransform()中的三个点是不同的。实际使用中,我们可以根据需要控制src 中的四
个点映射到dst 中的四个点。

import cv2
import numpy as np
img=cv2.imread('demo.bmp')
rows,cols=img.shape[:2]
print(rows,cols)
pts1 = np.float32([[150,50],[400,50],[60,450],[310,450]])
pts2 = np.float32([[50,50],[rows-50,50],[50,cols-50],[rows-50,cols-50]])
M=cv2.getPerspectiveTransform(pts1,pts2)
dst=cv2.warpPerspective(img,M,(cols,rows))
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.waitKey()
cv2.destroyAllWindows()

在本例中,指定原始图像中平行四边形的四个顶点pts1,指定目标图像中矩形的四个顶点pts2,使用M=cv2.getPerspectiveTransform(pts1,pts2)生成转换矩阵M。接下来,使用语句dst=cv2.warpPerspective(img,M,(cols,rows))完成从平行四边形到矩形的转换。

5. 重映射

把一幅图像内的像素点放置到另外一幅图像内的指定位置,这个过程称为重映射。OpenCV提供了多种重映射方式,但是我们有时会希望使用自定义的方式来完成重映射。

dst = cv2.remap( src, map1, map2, interpolation[, borderMode[, borderValue]] )

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

#例:设计程序,使用cv2.remap()完成数组映射,将目标数组内的所有像素点都映射为原始图像内第0 行第3 列上的像素点。
import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)
rows,cols=img.shape
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)

运行程序,出现如下结果:
img=
[[120 183 101 252 219]
[ 51 106 168 221 118]
[147 16 3 14 159]
[219 67 254 16 62]]
mapx=
[[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]
[3. 3. 3. 3. 3.]]
mapy=
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
rst=
[[252 252 252 252 252]
[252 252 252 252 252]
[252 252 252 252 252]
[252 252 252 252 252]]

以上是关于OpenCV学习笔记——图像几何变换的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV学习笔记4基础:几何变换-改变大小

OpenCV学习笔记4基础:几何变换-改变大小

OpenCV学习笔记4基础:几何变换-改变大小

OpenCV学习笔记4基础:几何变换-改变大小

OpenCV学习笔记4基础:几何变换-改变大小

Python 大白从零开始 OpenCV 学习课-5. 图像的几何变换