当前位置 博文首页 > OpenCV+Python几何变换的实现示例

    OpenCV+Python几何变换的实现示例

    作者:雨吹桐 时间:2021-05-09 18:19

    几何变换

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

    1 缩放

    使用cv2.resize()函数实现对图像的缩放,但要注意cv2.resize()函数内的dsize参数与原图像的行列属性是相反的,也就是:目标图像的行数是原始图像的列数,目标图像的列数是原始图像的行数。

    下面举例说明cv2.resize()函数的用法:

    import cv2
    img=cv2.imread('E:/python_opencv/tupian.jpg')
    rows,cols=img.shape[0:2]  #行数和列数等于img的长度和宽度
    size=(int(cols*0.9),int(rows*0.5))  #比例:列变为原来0.9倍,行变为0.5倍
    rst=cv2.resize(img,size)  #将img按size比例缩放
    print('img.shape=',img.shape)
    print('rst.shape=',rst.shape)

    运行程序的结果如下:

    img.shape=(600,60,3)
    rst.shape=(300,54,3)

    可以看出,行数变为原来的0.5倍,列数变为原来的0.9倍。代码中size的行列位置发生了交换。

    2 翻转

    使用cv2.flip()函数对图像翻转,能够实现水平方向翻转、垂直方向翻转、两个方向同时翻转。

    下面举例说明cv2.flip()函数的用法:

    import cv2
    img=cv2.imread('E:/python_opencv/tupian.jpg')
    x=cv2.flip(img,0)   #图x对原图像绕x轴翻转
    y=cv2.flip(img,1)   #图y对原图像绕y轴翻转
    xy=cv2.flip(img,-1)  #图xy对原图像绕x轴y轴同时翻转
    cv2.imshow('img',img)
    cv2.imshow('x',x)
    cv2.imshow('y',y)
    cv2.imshow('xy',xy)
    cv2.waitKey()
    cv2.destroyAllWindows()

    程序运行结果如下四幅图,第一幅是原图,第二幅是绕x轴翻转,第三幅是绕y轴翻转,第四幅是绕x轴y轴同时翻转。

    3 仿射

    仿射变换是指图像实现平移、旋转等操作。

    先设置一个变换矩阵M,然后使用cv2.warpAffine()函数对原图像和变换矩阵M进行仿射操作。

    (一)平移

    要实现图像的平移,我们先自定义一个转换矩阵,再进行仿射平移变换。例程如下:

    import cv2
    import numpy as np
    img=cv2.imread('E:\python_opencv/tupian.jpg')
    height,width=img.shape[:2]     #读取原图像的长和宽
    x=100                      #自定义转换矩阵M的x轴移动值
    y=200                      #自定义转换矩阵M的y轴移动值
    M=np.float32([[1,0,x],[0,1,y]])    #构造转换矩阵M
    move=cv2.warpAffine(img,M,(width,height))  #平移映射
    cv2.imshow('orginal',img)
    cv2.imshow('move',move)
    cv2.waitKey()
    cv2.destroyAllWindows()

    程序运行结果如下图所示,左为原图,右为平移后的图。

    (二)旋转

    使用函数cv2.getRotationMatrix2D()获得转移矩阵M,然后使用函数cv2.warpAffine()进行仿射旋转变换。例程如下:

    import cv2
    img=cv2.imread('E:\python_opencv/tupian.jpg')
    height,width=img.shape[:2]  #读取原图像的长和宽
    M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)  #以中心为原点,逆时针旋转45°,且缩小为原图的0.6倍,获得转移矩阵M
    rotate=cv2.warpAffine(img,M,(width,height))  #旋转映射
    cv2.imshow('original',img)
    cv2.imshow('rotation',rotate)
    cv2.waitKey()
    cv2.destroyAllWindows()

    程序运行结果如下图所示,左为原图,右为旋转后的图。

    4 透视

    透视变换是指将矩阵图形投影到另一个视平面,可以映射为任意四边形,所以透视变换也被称为投影映射(ProjectionMapping),并不是字面意义上的“透视”。透视与上节的仿射不同,仿射可以将矩阵映射为任意平行四边形。

    使用cv2.warpPerspective()函数实现透视变换。例程如下:

    #完成图像透视
    import cv2
    import numpy as np
    img=cv2.imread('E:/python_opencv/tupian.jpg')
    rows,cols=img.shape[:2]   #读取原图像的长和宽
    print(rows,cols)
    #生成旋转矩阵M
    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)
    #使用函数cv2.warpPerspective()进行透视变换
    dst=cv2.warpPerspective(img,M,(cols,rows))
    cv2.imshow('img',img)
    cv2.imshow('dst',dst)
    cv2.waitKey()
    cv2.destroyAllWindows()

    程序运行结果如下图所示,左为原图,右为透视变换的图。

    我们可以看到,原图片经过透视映射后,变成另一个视角下的任意四边形了。

    5 重映射

    重映射是修改了像素点的位置,从而生成一幅新的图像,包括:复制、绕x轴y轴翻转,x轴y轴互换,图像缩放等。

    均使用cv2.remap()重映射函数进行操作。

    需要注意cv2.remap()中的两个参数mapx、mapy。mapx表示对应位置上x轴坐标值,mapy表示对应位置上y轴坐标值。

    (一)复制

    使用cv2.remap()函数完成图像复制,需先定义mapx,mapy的值,然后循环映射每个像素点到对应的位置上。

    代码如下:

    import cv2
    import numpy as np
    img=cv2.imread('E:/python_opencv/tupian.jpg')
    rows,cols=img.shape[:2]         #读取行列数
    mapx=np.zeros(img.shape[:2],np.float32) #mapx参数设定为对应位置上的x轴坐标值
    mapy=np.zeros(img.shape[:2],np.float32) #mapy参数设定为对应位置上的y轴坐标值
    for i in range(rows):          #对每个元素复制映射
      for j in range(cols):
        mapx.itemset((i,j),j)
        mapy.itemset((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轴翻转

    重映射法对图像绕x轴翻转,表明mapx的值保持不变,mapy的值调整为总行数-1-当前行号,其余部分代码不变,所以循环体内代码变为:

     for i in range(rows):
       for j in range(cols):
         mapx.itemset((i,j),j)      #mapx的值保持不变
         mapy.itemset((i,j),rows-1-i)  #mapy的值调整为总行数-1-当前行号

    (三)绕y轴翻转

    重映射法对图像绕y轴翻转,表明mapx的值调整为总行数-1-当前列号,mapy的值保持不变,所以循环体内代码变为:

    for i in range(rows):
      for j in range(cols): 
         mapx.itemset((i,j),cols-1-j)  #mapx的值调整为总列数-1-当前列号
         mapy.itemset((i,j),i)      #mapy的值保持不变

    (四)绕x轴y轴翻转

    重映射也能实现图像绕x轴和y轴的同时翻转,只需将前两个部分合并,使mapx的值调整为总行数-1-当前列号,mapy的值调整为总行数-1-当前行号。例程如下:

    import cv2
    import numpy as np
    img=cv2.imread('E:\python_opencv/tupian.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.itemset((i,j),cols-1-j)  #mapx的值调整为总列数-1-当前列号
        mapy.itemset((i,j),rows-1-i)  #mapy的值调整为总行数-1-当前行号
    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的值变为所在列的列号。

    但当行数和列数不一致时,行或列无法完成映射的部分就被处理为0。示例代码如下:

    #使用函数cv2.remap()实现图像绕x轴和y轴的互换
    import cv2
    import numpy as np
    img=cv2.imread('E:\python_opencv/tupian.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.itemset((i,j),i)  #mapx的值变为所在行的行号
        mapy.itemset((i,j),j)  #mapy的值变为所在列的列号
    rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
    cv2.imshow('original',img)
    cv2.imshow('result',rst)
    cv2.waitKey()
    cv2.destroyAllWindows()

    结果如图:

    可以看到,列数多于行数的部分被置为0(黑色)。

    (六)图像的缩放

    重映射提供了cv2.remap()函数能够实现图像的放大或缩小。处理图像后,可以将图像固定在围绕其中心的某个区域。

    下面例程中,x轴和y轴均缩小为原来的0.25-0.75倍之间。

    import cv2
    import numpy as np
    img=cv2.imread('E:\python_opencv/tupian.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 < i < 0.75*rows:
          #在目标图像的x轴(0.25-0.75)倍之内生成缩小图像
          mapx.itemset((i,j),2*(j-0.25*cols)+0.5)
          #在目标图像的y轴(0.25-0.75)倍之内生成缩小图像
          mapy.itemset((i,j),2*(i-rows*0.25)+0.5)
        else:
          #不在上述区域的点都取(0,0)坐标点的值
          mapx.itemset((i,j),0)
          mapy.itemset((i,j),0)
    rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  #图像缩放重映射
    cv2.imshow('original',img)
    cv2.imshow('result',rst)
    cv2.waitKey()
    cv2.destroyAllWindows()

    js
    下一篇:没有了