• opencv4.2.0.34+python3.8.2+(获取图片视频并打开、numpy、色彩空间、数值与逻辑计算、图像的切割合并填充、floodFill、卷积模糊处理、高斯噪声处理高斯模糊、ERF)


    (有的运行结果没弄上去,但文中代码本人亲测均通过;至于有人因版本问题出现个别错误,我相信对于大家应该没什么问题,文档就是很好的辅助学习资料)

    一、openCV和openGL的区别

    OpenCV是 Open Source Computer Vision Library
    OpenGL是 Open Graphics Library
    OpenCV主要是提供图像处理和视频处理的基础算法库,还涉及一些机器学习的算法。比如你想实现视频的降噪、运动物体的跟踪、目标(比如人脸)的识别这些都是CV的领域
    OpenGL则专注在Graphics,3D绘图。
    其实两者的区别就是Computer Vision和Computer Graphics这两个学科之间的区别,前者专注于从采集到的视觉图像中获取信息,是用机器来理解图像;后者是用机器绘制合适的视觉图像给人看。

    二、opencv的安装和测试(win10环境下)

    一般opencv有四个模块:
    opencv-python: 只包含opencv库的主要模块. 一般不推荐安装.
    opencv-contrib-python: 包含主要模块和contrib模块, 功能基本完整, 推荐安装.
    opencv-python-headless: 和opencv-python一样, 但是没有GUI功能, 无外设系统可用.
    opencv-contrib-python-headless: 和opencv-contrib-python一样但是没有GUI功能. 无外设系统可用.
    因此一般来说都会选择安装opencv-contrib-python
    window环境下安装命令:pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
    (当然pip命令有可能也需要安装更新之类的,网上查找更新命令即可,如果可以运行当我没说;如果直接使用安装命令pip install opencv-contrib-python会比较慢,所以我使用了国内资源)
    不要同时安装opencv-python和opencv-contrib-python
    1.可以在window终端下进行简单的测试(当然我写的时候按python代码块处理了,所以出现下面情况)

    >>>import cv2
    >>>cv2.__version__
    '4.2.0'
    

    2.在pycharm中的测试(pycharm的安装和破解网上很多,我这里不进行解释;还有在pycharm中进行测试的时候,虽然cv2模块已经下载好,但是pycharm中并没有导入,可参考下面网址,将下载好的模块导入到pycharm中【https://blog.csdn.net/ShadowFox_/article/details/82871575】)
    输出图片
    如果可以输出图片,并且在关闭后输出Hi,Python!那么表示安装成功(第三行代码处图片路径最好是英文;代码中注意W是大写,如果不是同样会输出图片,但关闭图片之后不会输出Hi,Python!)

    三、opencv的模块

    opencv模块
    下面的五个横框表示基础模块。右边是扩展的模块,也就是opencv-contrib-python中的contrib,下载该模块之后才可以使用。上面的11个模块是基于下面五个基础模块的。

    四、读取显示图片及其信息

    import cv2 as cv
    import numpy as np
    
    
    # 输出图片属性
    def get_image_info(image):
        """
        查看图片的属性
        :param image: 要输出的图片
        """
        # 显示图片类型 numpy类型的数组
        print(type(image))
        # 图像矩阵的shape属性表示图像的大小,shape会返回tuple元组,第一个元素表示矩阵行数,第二个元组表示矩阵列数,第三个元素是3,表示像素值由光的三原色组成
        print(image.shape)
        # 图像大小
        print(image.size)
        # 图像类型
        print(image.dtype)
        # 将图片作为矩阵进行输出
        pixel_data = np.array(image)
        print(type(pixel_data))
        print(pixel_data)
    
    
    # 读取图片
    src = cv.imread("D:/image/dingxia.jpg")
    # 创建窗口,不写也可show出来,第一个参数是窗口名字,第二个参数为窗口显示方式
    # 为0或cv.WINDOW_NORMAL:可以改变窗口大小
    # 不写或cv.WINDOW_AUTOSIZE则不可改变大小
    cv.namedWindow("Hello opencv!",cv.WINDOW_AUTOSIZE)
    # 显示图片窗口,第一个参数是窗口名称,第二个参数是要显示的图片
    cv.imshow("Hello opencv!",src)
    # 调用函数
    get_image_info(src)
    # 对图片另存,不要存C盘,要用权限
    cv.imwrite("D:/image/1.png",src)
    # 窗口显示时间waitKey(k),k<=0,窗口一直显示,按下数字键消失,k>0,表示显示多少毫秒
    cv.waitKey(0)
    # 删除建立的全部窗口,释放资源
    cv.destroyAllWindows()
    
    print("Hi,Python!")
    

    五、获取摄像头并打开

    import cv2 as cv
    
    
    def video_demo():
        """
        打开摄像头或视频文件
        """
        # 打开摄像头,0代表的是设备id,如果有多个摄像头,可以设置其他数值
        # 第二个参数是因为采用默认的API控制出错,所以加上cv.CAP_DSHOW
        capture = cv.VideoCapture(0, cv.CAP_DSHOW)
        while True:
            # 读取摄像头,它能返回两个参数,第一个参数是bool型的ret,其值为True或False,代表有没有读到图片;第二个参数是frame,是当前截取一帧的图片
            ret, frame = capture.read()
            # 翻转 0:上下颠倒 大于0:水平颠倒   小于0:180旋转
            frame = cv.flip(frame, 1)
            cv.imshow("video", frame)
            # esc对应的ascii值为27,使用esc关闭窗口
            c = cv.waitKey(50)
            if c == 27:
                break
    
    
    video_demo()
    cv.destroyAllWindows()
    
    
    

    特别注意第10行代码处,参数cv.CAP_DSHOW一开始我没有写,在关闭摄像头时出现下列报错,所以我加上该参数,这是由于采用默认的API控制出错
    [ WARN:0] global C:projectsopencv-pythonopencvmodulesvideoiosrccap_msmf.cpp (674) SourceReaderCB::~SourceReaderCB terminating async callback

    六、numpy操作数组输出图片

    (1)读取一张图片,修改颜色通道后输出

    # -*- coding=GBK -*-
    import cv2 as cv
    import numpy as np
    
    
    # numpy数组操作
    def access_pixels(image):
        print(image.shape)
        height = image.shape[0]
        width = image.shape[1]
        channel = image.shape[2]
        print("width : %s, height : %s, channel : %s" % (width, height, channel))
        for row in range(height):
            for col in range(width):
                for c in range(channel):
                    # 得到行数,列数,通道数的矩阵
                    pv = image[row, col, c]
                    # 对矩阵进行操作可改变图像像素,为什么255减去原因暂时不知,后续知道会进行更改
                    image[row, col, c] = 255 - pv
        cv.imshow("later", image)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    # cv.namedWindow("原来", cv.WINDOW_NORMAL) 可以不写
    cv.imshow("start", src)
    t1 = cv.getTickCount()  # 毫秒级别的计时函数,记录了系统启动以来的时间毫秒
    access_pixels(src)
    t2 = cv.getTickCount()
    time = (t2 - t1) * 1000 / cv.getTickFrequency()  # getTickFrequency用于返回CPU的频率,就是每秒的计时周期数
    print("time: %s" % time)  # 输出运行的时间
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    (2)多通道函数:zeros和ones

    import cv2 as cv
    import numpy as np
    
    # 自定义多通道图片1
    def create_image_zeros():
        # zeros:double类零矩阵  创建400*400 3个通道的矩阵图像 参数时classname为uint8
        img = np.zeros([400, 400, 3], np.uint8)
        # ones([400, 400])是创建一个400*400的全1矩阵,*255即是全255矩阵 *后面数字可以自由变换 并将这个矩阵的值赋给img的第一维
        img[:, :, 0] = np.ones([400, 400]) * 0
        img[:, :, 1] = np.ones([400, 400]) * 0
        img[:, :, 2] = np.ones([400, 400]) * 0
        # 输出一张400*400的白色图片(255 255 255):蓝(B)、绿(G)、红(R),bgr顺序不能乱,和常说的rgb反过来了
        cv.imshow("自制图片1", img)
    
    # 自定义多通道图片2
    def create_image_ones():
        img = np.ones([400, 400, 3], np.uint8)
        img[:, :, 0] = img[:, :, 0] * 255
        img[:, :, 1] = img[:, :, 1] * 255
        img[:, :, 2] = img[:, :, 2] * 255
        cv.imshow("自制图片2", img)
    
    create_image_zeros()
    create_image_ones()
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    

    区别:
    zeros:生成全0的矩阵
    ones:生成全1的矩阵

    (3)单通道函数:zeros和ones

    # -*- coding=GBK -*-
    import cv2 as cv
    import numpy as np
    
    
    def create_image_zeros():
        img = np.zeros([400, 400, 1], np.uint8)
        # img[:, :, 0] = 127, 下面代码也可以这样写,直接赋值127,效果相同
        img[:, :, 0] = np.ones([400, 400]) * 127
        cv.imshow("自制图片1", img)
    
    
    def create_image_ones():
        img = np.zeros([400, 400, 1], np.uint8)
        # zeros是全0矩阵,所以需要用到ones全1矩阵乘像素值;img[:, :, 0] = 127,下面代码也可以这样写,直接赋值127,效果相同
        img[:, :, 0] = np.ones([400, 400]) * 127
        # 下面代码直接使用ones全1矩阵,所以可以直接使用该行代码 img = img * 127
        # img = np.ones([400, 400, 1], np.uint8)
        # img = img * 127
        cv.imshow("自制图片2", img)
    
    
    create_image_zeros()
    create_image_ones()
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    对于单通道,像素在0-255之间变化,图像在黑与白之间变化;而对于多通道,三种通道bgr的出现,使图像出现彩色。
    对于zeros和ones来说都可以处理多通道和单通道,唯一区别就是一个全0,一个全1,所以zeros还是需要用到ones函数进行像素的设置,全0进行乘法*的运算永远是全0,这样是达不到效果的

    (4)像素取反

    # -*- coding=GBK -*-
    import cv2 as cv
    import numpy as np
    
    
    # 像素取反
    def inverse(image):
        dst = cv.bitwise_not(image)
        cv.imshow("inverse", dst)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    cv.namedWindow("start", cv.WINDOW_NORMAL)
    cv.imshow("start", src)
    t1 = cv.getTickCount()
    inverse(src)
    t2 = cv.getTickCount()
    time = (t2 - t1) * 1000 / cv.getTickFrequency()
    print("time: %s" % time)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    

    (5)矩阵填充和重塑矩阵

    # -*- coding=GBK -*-
    import cv2 as cv
    import numpy as np
    
    
    def create_image():
        # 生成一个3*3维的单通道矩阵
        m1 = np.ones([3, 3], np.uint8)
        # 向矩阵中填充值,可以是int,float,complex,有时候注意np.uint8是整型,如果fill填充的是float型可能涉及到溢出,12222.388就是特殊案例,注意上下对应即可
        m1.fill(12222.388)
        print(m1)
        # 对矩阵进行重塑,改变矩阵样式
        m2 = m1.reshape([1, 9])
        print(m2)
    
        # array需要将数组内容一一列出,而ones只需给出大小进行填充即可
        m3 = np.array([[2, 3, 4], [4, 5, 6], [6, 7, 8]], np.uint32)
        # m3.fill(9)
        print(m3)
    
    
    create_image()
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    七、色彩空间

    (1)通过inRange函数进行色彩捕捉

    这个模型中颜色的参数分别是:色调Hue(H),饱和度Saturation(S),明度Value(V)。

    import cv2 as cv
    import numpy as np
    
    
    def extract_object_demo():
        """
        inRange函数色彩捕捉
        """
        video = cv.VideoCapture("D:/image/white.mp4")
        while True:
            ret, frame = video.read()
            if not ret:
                break
            # 通过inrange函数进行色彩捕捉,对白色进行捕捉,这个看自己视频中要捕捉颜色,然后根据下方表确定范围
            hsv = cv.cvtColor(frame, cv.COLOR_RGB2HSV)
            lower_hsv = np.array([0, 0, 221])
            upper_hsv = np.array([180, 30, 255])
            mask = cv.inRange(hsv, lowerb=lower_hsv, upperb=upper_hsv)
            cv.imshow("mask", mask)
            # 逻辑与运算,后面几节出现,对与运算加上mask也可以出现图像,mask是可选参数,具体参数含义可查看opencv官方文档
            dst = cv.bitwise_and(frame, frame, mask=mask)
            cv.imshow("dst", dst)
    
            cv.imshow("video", frame)
            c = cv.waitKey(40)
            if c == 27:
                break
    
    
    def color_space_demo(image):
        # 色彩空间转换API,当然还有很多,rgb,gray,hsv,yuv,ycrcb比较常见,尤其rgb到hsv和yuv的转换记牢
        gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
        cv.imshow("gray", gray)
        hsv = cv.cvtColor(image, cv.COLOR_RGB2HSV)
        cv.imshow("hsv", hsv)
        yuv = cv.cvtColor(image, cv.COLOR_RGB2YUV)
        cv.imshow("yuv", yuv)
        ycrcb = cv.cvtColor(image, cv.COLOR_RGB2YCrCb)
        cv.imshow("ycrcb", ycrcb)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    # cv.namedWindow("start", cv.WINDOW_AUTOSIZE)
    # cv.imshow("start", src)
    extract_object_demo()
    # color_space_demo(src)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    
    

    hsv图像转换

    (2)通道合并

    # -*- coding=GBK -*-
    import cv2 as cv
    import numpy as np
    
    
    def merge_channel(image):
        # 使用split将图片切分为三个通道
        b, g, r = cv.split(image)
        cv.imshow("blue", b)
        cv.imshow("green", g)
        cv.imshow("red", r)
    
        # 使用merge进行通道的合并
        img = cv.merge([b, g, r])
        cv.imshow("merge", img)
    
        # 修改某个单通道的值
        img[:, :, 2] = 100
        cv.imshow("单通道", img)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    cv.namedWindow("start", cv.WINDOW_AUTOSIZE)
    cv.imshow("start", src)
    merge_channel(src)
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    

    八、图片色素的数值运算(加减乘除)和逻辑运算(与或非异或)

    (1)数值运算

    opencv自带图片色素的处理函数:

    相加:add()

    相减:subtract()

    相乘:multiply()

    相除:divide()

    原理就是:通过获取两张(一次只能是两张)个图片的同一个位置的色素值来实现运算。

    运算的要求:两张图片的shape要一样。

    例图:(自己保存为图片格式即可)
    linux
    window

    import cv2 as cv
    import numpy as np
    
    
    def add_pixels(m1, m2):
        dst = cv.add(m1, m2)
        cv.imshow("add", dst)
    
    
    def subtract_pixels(m1, m2):
        dst = cv.subtract(m1, m2)
        cv.imshow("subtract", dst)
        # cv.imwrite("D:/image/linux_window.jpg", dst) linux-window还是比较好看就保存了
    
    
    def multiply_pixels(m1, m2):
        dst = cv.multiply(m1, m2)
        cv.imshow("multiply", dst)
    
    
    def divide_pixels(m1, m2):
        dst = cv.divide(m1, m2)
        cv.imshow("divide", dst)
    
    
    # 均值和方差 mean表示均值,meanStdDev可返回均值和方差
    def others(m1, m2):
        M1, dev1 = cv.meanStdDev(m1)
        M2, dev2 = cv.meanStdDev(m2)
        # 取和图像m1相同的高宽,【:2】涉及切片,左实右虚,取shape前两个
        h, w = m1.shape[:2]
    
        print(M1)
        print(M2)
    
        print(dev1)
        print(dev2)
    
        # 对于像素相同的矩阵,方差均为0,这里使用了全0矩阵,所以输出的均值和方差均为0
        # 若使用ones全1矩阵,那么输出均值为1,方差为0
        img = np.zeros([h, w], np.uint8)
        m, dev = cv.meanStdDev(img)
        print(m)
        print(dev)
    
    
    src1 = cv.imread("D:/image/linux.jpg")
    src2 = cv.imread("D:/image/window.jpg")
    # cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)有没有影响不大,除非对图片有大小变化需求
    cv.imshow("Hello linux!", src1)
    cv.imshow("Hello window!", src2)
    # add
    add_pixels(src1, src2)
    # subtract
    subtract_pixels(src1, src2)
    # multiply
    multiply_pixels(src1, src2)
    # divide
    divide_pixels(src1, src2)
    
    
    others(src1, src2)
    
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    print("Hi,Python!")
    
    

    (2)逻辑运算(按位与或非异或运算+粗略提高图像对比度和亮度)

    opencv自带图片色素的处理函数:

    与:bitwise_add() 全1则1,其他为0

    或:bitwise_or() 有1为1,其他为0

    非:bitwise_not() 1为0,0为1

    异或:bitwise_xor() 相同为0,不同为1

    对于0 1 的来说,这四种操作比较好理解,对于像素值来说要采用下表方式进行按位与或非、异或操作:
    逻辑操作

    import cv2 as cv
    import numpy as np
    
    
    def logic_demo(m1, m2):
        """
        逻辑运算 与或非异或
        :param m1: 第一张图片
        :param m2: 第二张图片
        """
        dst = cv.bitwise_and(m1, m2)
        cv.imshow("and", dst)
        dst = cv.bitwise_or(m1, m2)
        cv.imshow("or",dst)
        dst = cv.bitwise_not(m1)
        cv.imshow("not1", dst)
        dst = cv.bitwise_not(m2)
        cv.imshow("not2", dst)
        dst = cv.bitwise_xor(m1, m2)
        cv.imshow("xor", dst)
    
    
    def contrast_brightness_demo(image, c, b):
        """
        调整图像对比度和亮度
        :param image: 要调整的图片
        :param c: 对比度
        :param b: 亮度
        """
        h, w, ch = image.shape
        # blank是一个全0的矩阵,是黑色的
        blank = np.zeros([h, w, ch], image.dtype)
        dst = cv.addWeighted(image, c, blank, 1-c, b)
        cv.imshow("demo", dst)
    
    
    src1 = cv.imread("D:/image/linux.jpg")
    src2 = cv.imread("D:/image/window.jpg")
    # cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello linux!", src1)
    cv.imshow("Hello window!", src2)
    
    # 逻辑运算 与或非异或
    # logic_demo(src1, src2)
    
    # 调整图像对比度和亮度
    contrast_brightness_demo(src2, 1.5, 0)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    
    print("Hi,Python!")
    
    

    addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);

    一共有七个参数:前4个是两张要合成的图片及它们所占比例,第5个double gamma起微调作用,第6个OutputArray dst是合成后的图片,第七个输出的图片的类型(可选参数,默认-1)

    有公式得出两个图片加成输出的图片为:dst=src1alpha+src2beta+gamma

    九、图像的切割,合并和填充

    从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域ROI(region of interest)

    import cv2 as cv
    import numpy as np
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello opencv!", src)
    # 切割图像,范围的查找要自己慢慢试
    img = src[50:200, 230:350]
    # 将切割出的图像填充变成灰色
    gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    # 下面这行代码是为了增加通道,因为gray为灰度图像,是单通道,而src是三通道,所以需要cvtColor一下,将其转换为三通道
    # 而且由于灰度图像无法再恢复成彩色图像,所以cvtColor之后,只会增加通道数,图像表现还是灰色
    backface = cv.cvtColor(gray, cv.COLOR_RGB2BGR)
    # 合并图像
    src[50:200, 230:350] = backface
    cv.imshow("gray", src)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    print("Hi,Python!")
    
    

    十、floodFill填充函数(泛洪填充)

    floodFill函数:漫水填充算法

    基本思想:
    所谓漫水填充,简单来说,就是自动选中了和种子点相连的区域,接着将该区域替换成指定的颜色,这是个非常有用的功能,经常用来标记或者分离图像的一部分进行处理或分析.漫水填充也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或者只处理掩码指定的像素点.

    以此填充算法为基础,类似photoshop的魔术棒选择工具就很容易实现了。漫水填充(FloodFill)是查找和种子点联通的颜色相同的点,魔术棒选择工具则是查找和种子点联通的颜色相近的点,将和初始种子像素颜色相近的点压进栈作为新种子

    在OpenCV中,漫水填充是填充算法中最通用的方法。且在OpenCV 2.X中,使用C++重写过的FloodFill函数有两个版本。一个不带掩膜mask的版本,和一个带mask的版本。这个掩膜mask,就是用于进一步控制哪些区域将被填充颜色(比如说当对同一图像进行多次填充时)。这两个版本的FloodFill,都必须在图像中选择一个种子点,然后把临近区域所有相似点填充上同样的颜色,不同的是,不一定将所有的邻近像素点都染上同一颜色,漫水填充操作的结果总是某个连续的区域。当邻近像素点位于给定的范围(从loDiff到upDiff)内或在原始seedPoint像素值范围内时,FloodFill函数就会为这个点涂上颜色。

    官方定义为
    第一个版本的floodfill(该版本没有mask参数)

     int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )
    

    第二个版本的floodfill

     int floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint,Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )
    

    以第二个版本进行介绍,但不知道为什么,python中调用这个函数,Rect* rect=0这个参数没有,剩下7个参数 ,至于Rect*类型的rect,有默认值0,一个可选的参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域。在pycharm中没有暂时不考虑

    通俗解释:floodFill( 1.操作的图像, 2.掩模, 3.起始像素点,4.填充的颜色, 6.填充颜色的低值, 7.填充颜色的高值 ,8.填充的方法)第五个rect忽略

    参数6.填充颜色的低值就是:参数3位置的像素 减去 参数6

    参数7.填充颜色的高值就是:参数3位置的像素 加上 参数7

    即是这两个数值之间的色素替换为参数4的颜色

    彩色图像一般是FLOODFILL_FIXED_RANGE 指定颜色填充

    还有一种是FLOODFILL_MASK_ONLY,mask的指定的位置为零时才填充,不为零不填充

    最后一个参数的比较:
    FLOODFILL_FIXED_RANGE - 如果设置为这个标识符的话,就会考虑当前像素与种子像素之间的差,否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。
    FLOODFILL_MASK_ONLY - 如果设置为这个标识符的话,函数不会去填充改变原始图像 (也就是忽略第四个参数newVal),而是去填充掩模图像(mask)。这个标识符只对第二个版本的floodFill有用,因第一个版本里面压根就没有mask参数。

    至于指定颜色填充的过程,就和FLOODFILL_FIXED_RANGE解释的一样,会和相邻的像素作比较,采用泛洪的方法填充(个人理解,没有找到可信度高的介绍,很遗憾)

    该链接是我参考的一篇博客,专门讲解floodfill函数,有兴趣可以看一看
    【https://blog.csdn.net/qq_27901569/article/details/49934763】

    import cv2 as cv
    import numpy as np
    
    
    # 指定颜色填充
    def fill_color_demo(image):
        copyImg = image.copy()
        h, w = image.shape[:2]
        # zeros和ones不写通道数默认单通道
        # mask它应该为单通道、8位、长和宽上都比输入图像 image 大两个像素点的图像 +2是官方函数要求
        # 需要注意的是,漫水填充不会填充掩膜mask的非零像素区域。也就是只填充掩膜mask的0的区域
        mask = np.zeros([h+2, w+2], np.uint8)
        cv.floodFill(copyImg, mask, (100, 100), (0, 255, 255), (100, 100, 100), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE)
        cv.imshow("fill_color_demo", copyImg)
    
    
    # 指定位置填充
    def fill_binary():
        image = np.ones([400, 400, 3], np.uint8)
        image[100:300, 100:300, :] = 255
        cv.imshow("fill_binary", image)
    
        # zeros和ones不写通道数默认单通道
        mask = np.ones([402, 402], np.uint8)
        # 将要填充位置的像素设为0
        mask[101:301, 101:301] = 0
        cv.floodFill(image, mask, (100, 100), (0, 0, 255), cv.FLOODFILL_MASK_ONLY)
        cv.imshow("filled binary", image)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello opencv!", src)
    
    # 第一个使用图片填充,第二个自己在函数内随便建了一个图像进行填充的
    fill_color_demo(src)
    fill_binary()
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    print("Hi,Python!")
    
    

    十一、利用卷积对图像模糊处理

    1.均值模糊函数blur():定义:blur(src,ksize,dst=None, anchor=None, borderType=None)

    定义是有5个参数,但最后三个均为none,所以也就2个参数

    src:要处理的原图像

    ksize: 周围关联的像素的范围:代码中(5,5)就是5*5的大小,就是计算这些范围内的均值来确定中心位置的大小

    2.中值模糊函数medianBlur(): 定义:medianBlur(src, ksize, dst=None)

    ksize与blur()函数不同,不是矩阵,而是一个数字,例如为5,就表示了5*5的方阵

    3.高斯平滑函数GaussianBlur():定义:GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)

    sigmaX:标准差

    4.双边滤波函数bilateralFilter():定义:bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
    d:邻域直径
    sigmaColor:颜色标准差
    sigmaSpace:空间标准差

    5.自定义模糊
    使用的函数为:filter2D():定义为filter2D(src,ddepth,kernel)

    ddepth:深度,输入值为-1时,目标图像和原图像深度保持一致

    kernel: 卷积核(或者是相关核),一个单通道浮点型矩阵

    修改kernel矩阵即可实现不同的模糊

    原图:
    lena
    lena_graylena_pepper_salt
    lena的加入椒盐噪声的彩色图片没找到,只有找到灰色图像,可以用这个加入椒盐噪声的lena图片对均值和中值进行比较,中值会取得比较好的效果

    import cv2 as cv
    import numpy as np
    
    
    # 均值模糊
    def blur_demo(image):
        # (5,5)分别表示横向和竖向,(5,5)比较常用
        dst = cv.blur(image, (5, 5))
        cv.imshow("blue_demo", dst)
    
    
    # 中值模糊,用于处理椒盐噪声,比均值处理效果好
    def median_blur_demo(image):
        dst = cv.medianBlur(image, 5)
        cv.imshow("median_blur_demo", dst)
    
    
    # 高斯模糊
    def gaussian_blur_demo(image):
        dst = cv.GaussianBlur(image, (5, 5), 2)
        cv.imshow("gaussian_blur_demo", dst)
    
    
    # 双边滤波
    def bilateralFilter_demo(image):
        dst = cv.bilateralFilter(image, 5, 5, 2)
        cv.imshow("bilateralFilter_demo", dst)
    
    
    # 自定义模糊、锐化处理;
    # 总和为0,做边缘梯度;奇数或者总和为1,做增强,锐化处理
    def custom_blur_demo(image):
        # 自定义矩阵,并防止数值溢出(第一种表示方法)
        # kernel = np.ones([5, 5], np.float32)/25
        # (第二种表示方法)
        # kernel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], np.float32)/9
        # 下方数据为标准的锐化算子(一般数据要求奇数或总和为1)
        kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
        dst = cv.filter2D(image, -1, kernel=kernel)
        cv.imshow("median_blur_demo", dst)
    
    
    src = cv.imread("D:/image/lena.jpg")
    cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello opencv!", src)
    
    # 均值模糊
    # blur_demo(src)
    # 中值模糊
    # median_blur_demo(src)
    # 高斯模糊
    # gaussian_blur_demo(src)
    # 双边滤波
    # bilateralFilter_demo(src)
    # 自定义模糊
    custom_blur_demo(src)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    print("Hi,Python!")
    
    

    十二、添加高斯噪声并使用高斯模糊处理

    import cv2 as cv
    import numpy as np
    
    
    def clamp(pv):
        if pv > 255:
            return 255
        elif pv < 0:
            return 0
        else:
            return pv
    
    
    # 增加高斯噪声
    def gaussian_noise(image):
        h, w, c = image.shape
        for row in range(h):
            for col in range(w):
                s = np.random.normal(0, 20, 3)
                b = image[row, col, 0]  # blue
                g = image[row, col, 1]  # green
                r = image[row, col, 2]  # red
                image[row, col, 0] = clamp(b + s[0])
                image[row, col, 1] = clamp(g + s[1])
                image[row, col, 2] = clamp(r + s[2])
        cv.imshow("noise image", image)
    
    
    src = cv.imread("D:/image/lena.jpg")
    cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello opencv!", src)
    
    t1 = cv.getTickCount()
    # 增加高斯噪声
    gaussian_noise(src)
    t2 = cv.getTickCount()
    time = (t2 - t1) / cv.getTickFrequency()
    print("time consume : %s" % (time*1000))
    # 高斯模糊处理,结果说明高斯模糊对高斯噪声有抑制作用
    dst = cv.GaussianBlur(src, (5, 5), 0)
    cv.imshow("Gaussian Blur", dst)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    print("Hi,Python!")
    
    

    结果说明高斯模糊对高斯噪声有抑制作用

    十三、边缘保留滤波(EPF)

    这个堪比磨皮,非常好玩!

    高斯双边
    dst = cv.bilateralFilter( src,d,sigmaColor,sigmaSpace [,dst [,borderType]] )
    dst也就是输出,和borderType都是可选参数
    src
    源8位或浮点,1通道或3通道图像。
    dst
    与src大小和类型相同的目标映像。
    d
    滤波期间使用的每个像素邻域的直径。如果它不是正值,则从sigmaSpace计算得出。
    sigmaColor
    在色彩空间中过滤sigma。参数的较大值表示像素邻域内的其他颜色(请参见sigmaSpace)将混合在一起,从而导致较大区域的半均等颜色。
    sigmaSpace
    在坐标空间中过滤sigma。该参数的值越大,表示越远的像素就会相互影响,只要它们的颜色足够接近即可(请参见sigmaColor)。当d> 0时,它指定邻域大小,而不考虑sigmaSpace。否则,d与sigmaSpace成比例。
    borderType
    用于推断图像外部像素的边框模式

    均值迁移
    dst = cv.pyrMeanShiftFiltering( src,sp,sr [,dst [,maxLevel [,termcrit]]] )
    dst也就是输出,和maxLevel、termcrit都是可选参数
    src
    源8位3通道图像。
    dst
    与源格式和大小相同的目标图像。
    SP
    空间窗口半径。
    SR
    彩色窗口半径。
    maxLevel
    用于分割的金字塔的最高级别。
    termcrit
    终止标准:何时停止均值漂移迭代。

    import cv2 as cv
    import numpy as np
    
    
    # 高斯双边
    def bi_demo(image):
        dst = cv.bilateralFilter(image, 0, 100, 15)
        cv.imshow("bi_demo", dst)
    
    
    # 均值迁移
    def shift_demo(image):
        dst = cv.pyrMeanShiftFiltering(image, 10, 50)
        cv.imshow("shift_demo", dst)
    
    
    src = cv.imread("D:/image/dingxia.jpg")
    cv.namedWindow("Hello opencv!", cv.WINDOW_AUTOSIZE)
    cv.imshow("Hello opencv!", src)
    
    bi_demo(src)
    shift_demo(src)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    print("Hi,Python!")
    
    

    运行结果如下:
    原图像
    freckle
    高斯双边后图像:
    bi_demo
    均值迁移后图像:
    shift_demo

  • 相关阅读:
    [Vue] #常见开发场景 #条件渲染#手动挂载 #组件方法的值驱动执行
    [JS高程] Typed Array 定型数组
    [JS高程]JavaScript中的RegExp对象
    [JS高程] Map 和 Set
    [JS高程] JavsScript 常用数组方法总结
    [JS高程] 字符串模式匹配方法
    自动化集成:Pipeline整合Docker容器
    自动化集成:Docker容器入门简介
    自动化集成:Jenkins管理工具详解
    分布式系统中,权限设计实践
  • 原文地址:https://www.cnblogs.com/ycycn/p/13788366.html
Copyright © 2020-2023  润新知