美文网首页Python_图像处理
Python OpenCV 图像的几何变换,先说不平凡的 res

Python OpenCV 图像的几何变换,先说不平凡的 res

作者: 梦想橡皮擦 | 来源:发表于2021-12-08 08:45 被阅读0次

    Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧。本篇博客是这个系列的第 41 篇。
    该系列文章导航参考:https://blog.csdn.net/hihell/category_10688961.html

    @[toc](Python OpenCV)

    基础知识铺垫

    在 OpenCV 中常见的几何变换有缩放,仿射,透视变换,之前的内容中已经学习过缩放函数了,今天一边复习旧知识,一边学习新知识。

    先看一下三个几何变换对应的函数原型是:

    dst = cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
    dst = cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
    dst = cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
    

    先从缩放说起,函数名为 cv2.resize(),非空参数有 2 个,分别是 srcdsize,含义为源图像与缩放后图像的尺寸。

    import cv2 as cv
    
    src = cv.imread("./t1.jpg")
    cv.imshow("src", src)
    dst = cv.resize(src, (200, 200))
    cv.imshow("dst", dst)
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    上述为最简单的代码,运行效果如下,实现了一个简单的变化


    20210215234303681[1].png

    该案例会出现一个常见的错误,缩放的数值提供的是浮点类型,错误提示为

    TypeError: integer argument expected, got float
    

    还有需要注意的是,元组 dsize 的两个值说明如下,顺序不要记错。

    # dsize = (cols,rows) 中文,(宽度,高度)
    dst = cv.resize(src, (400, 200))
    

    这个地方深究下去,其实需要记忆的细节很多,例如在笛卡尔坐标系里面,记录一个坐标点都是先 x 轴,后 y 轴,但是在计算机中,图像是以矩阵的形式保存的,先行后列,所以 宽x高x通道 的图片会保存在 高x宽x通道的三位数组中,在图像处理的时候,都是按照 高x宽x通道记忆,例如通过 shape 获取形状。

    src = cv.imread("./t1.jpg")
    print(src.shape)
    

    输出的结果就是 (高,宽,通道),但是这一点 resize 函数没有遵守,它依旧采用的是 (宽,高) 设置。

    fxfy为图像x,y方向的缩放比例,使用该参数,需要提前将 dsize 设置为 (0,0),测试代码如下:

    import cv2 as cv
    
    src = cv.imread("./t1.jpg")
    print(src.shape)
    cv.imshow("src", src)
    # dsize = (cols,rows) 中文,(宽度,高度)
    dst = cv.resize(src, (0, 0),fx=0.5,fy=0.5)
    cv.imshow("dst", dst)
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    测试结果为,如果不提前设置 dsize(0,0),那 fxfy 不会生效。注意 dsize=(0,0),如果数据类型不对,会出现如下错误:

    SystemError: new style getargs format but argument is not a tuple
    
    Python OpenCV 图像的几何变换,先说不平凡的 resize 函数

    interplolation 缩放时的插值方式

    interplolation 为缩放时的插值方式,有以下几种方式,这些是今天要探索的重点内容。

    • cv.INTER_NEAREST:最近邻插值;
    • cv.INTER_LINEAR:双线形插值(默认设置);
    • cv.INTER_CUBIC:4x4 像素邻域的双三次插值;
    • cv2.INTER_AREA:基于局部像素的重采样。它可能是图像抽取的首选方法,因为它会产生无云纹理的结果。 但是当图像缩放时,它类似于 INTER_NEAREST 方法。

    最近邻插值

    这部分比较吃精力,所以今天这一个小时,我们争取搞定一个插值算法,即最近邻插值就好。

    这个算法的思想是,通过已经像素值去获取目标像素值。我在学习的时候找到最通俗的解释,接下来由我说明给你。

    假设有一个 3x3 的灰度图,需要通过最近邻插值算法,得到一个 4x4 的灰度图。


    20210216002124631[1].png

    先通过坐标系去了解像素在缩放的时候的变化。


    20210216003107627[1].png

    上图中最后可以到的结论是:

    • 目标像素的 x 值 = 原像素的 x 值 * 倍数;
    • 目标像素的 y 值 = 原像素的 y 值 * 倍数;

    本案例的倍数是多少呢?很容易计算,原来的图像是 3x3,现在是 4x4,那倍数在 x,y 上都是 4/3 = 0.75

    先看一下运算之后得到的结果如下所示:


    20210216004733486[1].png

    这里列举两个点的像素值计算,拿目标图像 4x4灰度图 中的 (3,0)(3,3) 两个点进行说明。

    • (3x0) 点的值等于 (3 x 0.75 ≈ 2,0 x 0.75 = 0),原图像 (2,0) 点的颜色为 222
    • (3x3) 点的值等于 (3 x 0.75 ≈ 2,3 x 0.75 ≈ 2),原图像 (2,2) 点的颜色为 45

    掌握了原理之后,就可以自己实现这个算法了,首先看一下 OpenCV 内置的函数实现结果。

    import cv2 as cv
    import numpy as np
    
    #  最近邻插值算法,来源梦想橡皮擦 https://dream.blog.csdn.net/
    def nearest_demo(src, multiple_x, multiple_y):
        src_y, src_x, src_c = src.shape
        tar_x, tar_y, tar_c = src_x*multiple_x, src_y*multiple_y, src_c
        # 生成一个黑色的目标图像
        tar_img = np.zeros((tar_y, tar_x, tar_c), dtype=np.uint8)
        print(tar_img.shape)
        # 渲染像素点的值
        # 注意 y 是高度,x 是宽度
        for y in range(tar_y-1):
            for x in range(tar_x-1):
                # 计算新坐标 (x,y) 坐标在旧图中是哪个值
                old_y = round(y/multiple_y)
                old_x = round(x/multiple_x)
                tar_img[y, x] = src[old_y, old_x]
    
        return tar_img
    
    src = cv.imread("./t2.jpeg")
    print(src.shape)
    cv.imshow("src", src)
    # dsize = (cols,rows) 中文,(宽度,高度)
    dst = cv.resize(src, (0, 0), fx=2, fy=2, interpolation=cv.INTER_NEAREST)
    cv.imshow("dst", dst)
    
    new_dst = nearest_demo(src, 2, 2)
    cv.imshow("new_dst", new_dst)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    运行之后发现确实官方的算法更优一些。

    橡皮擦的小节

    希望今天的 1 个小时你有所收获,我们下篇博客见~

    相关阅读


    技术专栏

    1. Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
    2. Python 爬虫小课,精彩 9 讲

    相关文章

      网友评论

        本文标题:Python OpenCV 图像的几何变换,先说不平凡的 res

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