Opencv中几何变换

作者: 陨星落云 | 来源:发表于2019-07-13 20:08 被阅读1次

    几何变换

    OpenCV 提供了两个变换函数,cv2.warpAffine 和 cv2.warpPerspective,使用这两个函数你可以实现所有类型的变换。cv2.warpAffine 接收的参数是2 x 3 的变换矩阵,而 cv2.warpPerspective 接收的参数是 3 x 3 的变换矩阵。

    1.尺度变换

    尺度变换(缩放,拉伸)是调整图像大小,使其变大或变小。但实际操作时要比想象的复杂一些,因为调整大小带来了像素如何插值(放大)或合并(减少)的问题。

    cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
    

    作用:根据设置调整图像为指定大小,其中有两种指定方式:① 绝对尺寸:通过dsize直接设置;② 相对尺寸:dsize设置为None,然后将fx和fy设置为我们想要的比例因子即可。

    插值方法

    插值 含义
    cv2.INTER_LINEAR 双线性插值法
    cv2.INTER_NEAREST 最近邻插值
    cv2.INTER_AREA 像素区域重采样(默认)
    cv2.INTER_CUBIC 双三次插值
    cv2.INTER_LANCZ0S4 插值(超过8×8个邻域)

    例子

    img1 = cv2.imread("beautiful-beauty-brunette-2147192.jpg")
    
    # 绝对尺寸
    height,width = img1.shape[:2]
    res = cv2.resize(img1,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
    
    # 相对尺寸
    res1 = cv2.resize(img1,None,fx=0.5,fy=0.5)
    
    # 图像显示
    plt.figure(figsize=(10,8),dpi=100)
    plt.subplot(231)
    img_show('原图',img1)
    plt.subplot(232)
    img_show('绝对尺度(放大)',res)
    plt.subplot(233)
    img_show('相对尺度(缩小)',res1)
    
    尺度变换.png

    2.平移变换

    平移就是将对象换一个位置。如果你要沿(x,y)方向移动,移动的距离是(t_{x}, t_{y}),你可以以下面的方式构建移动矩阵:
    M=\left[\begin{array}{lll}{1} & {0} & {t_{x}} \\ {0} & {1} & {t_{y}}\end{array}\right]

    cv2.warpAffine(src, M, dsize)
    
    • src:输入图像
    • M:移动矩阵
    • dsize:输出图像大小

    注意:第三个参数的是输出图像的大小,它的格式应该是图像的(宽,高)。应该记住的是图像的宽对应的是列数,高对应的是行数。

    img1 = cv2.imread("beautiful-beauty-brunette-2147192.jpg")
    tx = 500
    ty = 1000
    
    M = np.float32([[1,0,tx],[0,1,ty]])
    dst = cv2.warpAffine(img1,M,(img1.shape[1]+tx,img1.shape[0]+ty))
    
    tx = 500
    ty = 200
    M = np.float32([[1,0,tx],[0,1,ty]])
    dst1 = cv2.warpAffine(img1,M,(3000,4000))
    
    plt.figure(figsize=(10,8),dpi=100)
    plt.subplot(231)
    img_show('原图',img1)
    plt.subplot(232)
    img_show('平移(右移500,下移1000)',dst)
    plt.subplot(233)
    img_show('平移(右移500,下移200)',dst1)
    
    平移变换.png

    例子

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    def cv_show(name,img):
        """图像显示函数
        name:字符串,窗口名称
        img:numpy.ndarray,图像
        """
        cv2.namedWindow(name,cv2.WINDOW_NORMAL)
        cv2.imshow(name,img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
        
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("attractive-beautiful-beauty-2267088.jpg")
        
        
        tx = 100
        ty = 150
         
        M = np.float32([[1,0,tx],[0,1,ty]])
         
        dst = cv2.warpAffine(img1,M,(img1.shape[0],img1.shape[1]))
           
        cv_show('translation',dst)
    
    平移.jpg

    3.旋转变换

    对一个图像旋转角度 θ, 需要使用到下面形式的旋转矩阵。
    M=\left[\begin{array}{cc}{\cos \theta} & {-\sin \theta} \\ {\sin \theta} & {\cos \theta}\end{array}\right]
    但是 OpenCV 允许你在任意地方进行旋转,但是旋转矩阵的形式应该修改为
    M=\left[\begin{array}{ccc}{\alpha} & {\beta} & {(1-\alpha) \cdot \text { center } x-\beta \cdot \text { centery }} \\ {-\beta} & {\alpha} & {\beta \cdot \text { centerx }+(1-\alpha) \cdot \text { centerx }}\end{array}\right]
    其中:
    \begin{aligned} \alpha &=s c a l e \cdot \cos \theta \\ \beta &=s c a l e \cdot \sin \theta \end{aligned}
    为了构建这个旋转矩阵,OpenCV 提供了一个函数:cv2.getRotationMatrix2D。

    cv2.getRotationMatrix2D(center, angle, scale)
    cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
    

    参数说明:

    • getRotationMatrix2D:
    • center–表示旋转的中心点
    • angle–表示旋转的角度degrees
    • scale–图像缩放因子

    warpAffine:

    • src – 输入的图像
    • M – 2 X 3 的变换矩阵.
    • dsize – 输出的图像的size大小
    • dst – 输出的图像
    • flags – 输出图像的插值方法(参考尺度变换)
    • borderMode – 图像边界的处理方式

    旋转任意角度的步骤
    1.读取图像

    2.使用getRotationMatrix2D函数求取旋转矩阵M,使用warpAffine函数对图像进行旋转

    3.显示图像

    例子:在不缩放的情况下将图像旋转 90 度。

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    def cv_show(name,img):
        """图像显示函数
        name:字符串,窗口名称
        img:numpy.ndarray,图像
        """
        cv2.namedWindow(name,cv2.WINDOW_NORMAL)
        cv2.imshow(name,img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
    
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("cute-dog.jpg")
        
        rows,cols = img1.shape[:2]
        
        # 这里的第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
        # 可以通过设置旋转中心,缩放因子,以及窗口大小来防止旋转后超出边界的问题
        M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
       
        dst = cv2.warpAffine(img1,M,(cols,rows))
           
        cv_show('translation',dst)
    
    旋转90度.jpg

    例子

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    def img_show(name,img):
        """matplotlib图像显示函数
        name:字符串,图像标题
        img:numpy.ndarray,图像
        """
        if len(img.shape) == 3:
            img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        plt.imshow(img,'gray')
        #plt.xticks([])
        #plt.yticks([])
        plt.xlabel(name,fontproperties='FangSong',fontsize=12)
        
    
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("cute-dog.jpg")
        
        rows,cols = img1.shape[:2]
        
        #将图像放到图像大小的两倍画布中,将图像移动的画布中心
        maxBorder =int(max(cols*2, rows*2))
        tx = (maxBorder-cols)/2
        ty = (maxBorder-rows)/2 
        M = np.float32([[1,0,tx],[0,1,ty]])
        img2 = cv2.warpAffine(img1,M,(maxBorder,maxBorder))
        
        # 这里的第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
        # 可以通过设置旋转中心,缩放因子,以及窗口大小来防止旋转后超出边界的问题
        M = cv2.getRotationMatrix2D((maxBorder/2,maxBorder/2),45,1)
        dst = cv2.warpAffine(img2,M,(maxBorder,maxBorder))
        
        
        plt.figure(figsize=(10,8),dpi=80)
        plt.subplot(231)
        img_show('原图',img1)
        plt.subplot(232)
        img_show('平移到画布中心',img2)
        plt.subplot(233)
        img_show('旋转45度',dst)
    
    x.png

    4.翻转

    翻转通过函数flip实现:

    函数说明:

    cv2.flip(src, flipCode[, dst]) → dst1
    

    参数说明:

    • src – 输入的图像

    • dst – 输出的图像

    • flipCode – 翻转模式:

      flipCode==0垂直翻转(沿X轴翻转)

      flipCode>0水平翻转(沿Y轴翻转)

      flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)

    例子

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    def img_show(name,img):
        """matplotlib图像显示函数
        name:字符串,图像标题
        img:numpy.ndarray,图像
        """
        if len(img.shape) == 3:
            img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        plt.imshow(img,'gray')
        plt.xticks([])
        plt.yticks([])
        plt.xlabel(name,fontproperties='FangSong',fontsize=12)
        
    
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("cute-dog.jpg")
        
        # 水平翻转
        flip_horiz_img = cv2.flip(img1, 1)
        # 垂直翻转
        flip_verti_img = cv2.flip(img1, 0)
        # 水平垂直翻转
        flip_horandver_img = cv2.flip(img1, -1)
    
        plt.figure(figsize=(8,12),dpi=80)
        plt.subplot(221)
        img_show('原图',img1)
        plt.subplot(222)
        img_show('水平翻转',flip_horiz_img)
        plt.subplot(223)
        img_show('垂直翻转',flip_verti_img)
        plt.subplot(224)
        img_show('水平垂直翻转',flip_horandver_img)
    
    翻转.png

    5.仿射变换

    图像的仿射变换涉及到图像的形状位置角度的变化,是深度学习预处理中常到的功能,在此简单回顾一下。仿射变换具体到图像中的应用,主要是对图像的缩放scale,旋转rotate,剪切shear,翻转flip和平移translate的组合。在OpenCV中,仿射变换的矩阵是一个2×3的矩阵,其中左边的2×2子矩阵是线性变换矩阵,右边的2×1的两项是平移项:
    \begin{array}{l}{A=\left[\begin{array}{ll}{a_{00}} & {a_{01}} \\ {a_{10}} & {a_{11}}\end{array}\right], B=\left[\begin{array}{l}{b_{0}} \\ {b_{1}}\end{array}\right]} \\ {M=\left[\begin{array}{ll}{A} & {B}\end{array}\right]=\left[\begin{array}{lll}{a_{00}} & {a_{01}} & {b_{0}} \\ {a_{10}} & {a_{11}} & {b_{1}}\end{array}\right]}\end{array}
    对于图像上的任一位置(x,y),仿射变换执行的是如下的操作:
    T_{a f f i n e}=A\left[\begin{array}{l}{x} \\ {y}\end{array}\right]+B=M\left[\begin{array}{l}{x} \\ {y} \\ {1}\end{array}\right]
    需要注意的是,对于图像而言,宽度方向是x,高度方向是y,坐标的顺序和图像像素对应下标一致。所以原点的位置不是左下角而是右上角,y的方向也不是向上,而是向下。

    在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建这个矩阵我们需要从原图像中找到三个点以及他们在输出图像中的位置。然后cv2.getAffineTransform 会创建一个 2x3 的矩阵,最后这个矩阵会被传给函数 cv2.warpAffine。

    例子

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    def img_show(name,img):
        """matplotlib图像显示函数
        name:字符串,图像标题
        img:numpy.ndarray,图像
        """
        if len(img.shape) == 3:
            img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        plt.imshow(img,'gray')
        plt.xticks([])
        plt.yticks([])
        plt.xlabel(name,fontproperties='FangSong',fontsize=12)
        
    
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("cute-dog.jpg")
        rows,cols = img1.shape[:2]
        
        pts1 = np.float32([[500,500],[2000,500],[500,2000]])
        pts2 = np.float32([[100,1000],[2000,500],[1000,2500]])
        M = cv2.getAffineTransform(pts1,pts2)
        img2 = cv2.warpAffine(img1,M,(rows,cols))
        
        plt.figure(figsize=(10,8),dpi=80)
        plt.subplot(221)
        img_show('原图',img1)
        plt.subplot(222)
        img_show('仿射变换',img2)
    
    仿射变换.png

    6.透视变换

    对于视角变换,我们需要一个 3x3 变换矩阵。在变换前后直线还是直线。要构建这个变换矩阵,你需要在输入图像上找 4 个点,以及他们在输出图像上对应的位置。这四个点中的任意三个都不能共线。这个变换矩阵可以有
    函数 cv2.getPerspectiveTransform() 构建。然后把这个矩阵传给函数cv2.warpPerspective。

    例子

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    def img_show(name,img):
        """matplotlib图像显示函数
        name:字符串,图像标题
        img:numpy.ndarray,图像
        """
        if len(img.shape) == 3:
            img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        plt.imshow(img,'gray')
        plt.xticks([])
        plt.yticks([])
        plt.xlabel(name,fontproperties='FangSong',fontsize=12)
        
    
    if __name__=="__main__":
    
        #img1 = cv2.imread("lenaNoise.png")
        img1 = cv2.imread("cute-dog.jpg")
        
    
    
        rows,cols = img1.shape[:2]
        
        pts1 = np.float32([[200,200],[200,3000],[4800,200],[4800,3000]])
        pts2 = np.float32([[200,200],[200,3000],[4800,600],[4800,2000]])
        M = cv2.getPerspectiveTransform(pts1,pts2)
        dst=cv2.warpPerspective(img1,M,(cols,rows),0.6)
            
        plt.figure(figsize=(10,8),dpi=80)
        plt.subplot(121)
        img_show('原图',img1)
        plt.subplot(122)
        img_show('透视变换',dst)
    
    透视变换.png

    参考资料
    网址:https://blog.csdn.net/zh_jessica/article/details/77946346
    书籍:《数字图像处理》《OpenCV-Python-Toturial-中文版》

    相关文章

      网友评论

        本文标题:Opencv中几何变换

        本文链接:https://www.haomeiwen.com/subject/uunmkctx.html