• 图片操作笔记-滤波-python


    滤波的应用

    高斯噪声和椒盐噪声 两者在视觉上的区别就是,高斯噪声是和原来图像像素值相关的噪声,而椒盐噪声则是很多的黑白像素点
    高斯噪声是一种加性噪声,即噪声直接加到原图像上,因此可以用线性滤波器滤除
    椒盐噪声又称为脉冲噪声,它是一种随机出现的白点(盐噪声)或者黑点(椒噪声),类似把椒盐撒在图像上,因此得名,如电视里的雪花噪声等。
    椒盐噪声可以认为是一种逻辑噪声,用线性滤波器滤除的结果不好,一般采用中值滤波器滤波可以得到较好的结果

    滤波操作

    自适应中值滤波
    高斯滤波
    双边滤波
    导向滤波

    自适应中值滤波算法

    图片没用部分的噪声

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
     
     
    # for gray image
    # S_max mast be grather 3
    def auto_median_filter(img, S_max):
        output = img.copy()
     
        def class_B(z_xy, z_med, z_max, z_min):
            if (z_min < z_xy) & (z_xy < z_max):
                return z_xy
            else:
    		    #z_xy 是个噪声,消除它: 使用z_med替换
                return z_med
     
        S_ori = 3
    	# cv2.copyMakeBorder() 函数是用来在图像周围添加边框的
    	# 增加边框,兼容边界的像素点
    	# 可以在开始的时候增加S_max厚度的边框,后面就不用动态增加了
    	# S_ori // 2  取整
        copy = cv2.copyMakeBorder(img, *[S_ori // 2] * 4, borderType=cv2.BORDER_DEFAULT)  # 补零
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                def class_A(copy, S_ori=3):
                    board = S_ori // 2
                    z_med = np.median(copy[i:i + board, j:j + board])
                    z_max = np.max(copy[i:i + board, j:j + board])
                    z_min = np.min(copy[i:i + board, j:j + board])
     
                    if (z_min < z_med) & (z_med < z_max):
    				    # z_med 不是噪声
                        output[i, j] = class_B(copy[i, j], z_med, z_max, z_min)
                    else:
                        # next_size = S_ori + 2
    					# # z_med 是个噪声,增大滤波窗口,寻找下一个不是噪声的中值
                        next_size = cv2.copyMakeBorder(copy, *[1] * 4, borderType=cv2.BORDER_DEFAULT)  # 增尺寸
                        S_ori = S_ori + 2
                        if S_ori <= S_max:
    					    # 
                            return class_A(next_size, S_ori)
                        else:
    					    #到达最大窗口,没有找到“不是噪声的中值”,直接中值滤波
                            output[i, j] = z_med
                class_A(copy, 3)
        return output.astype(np.uint8)
     
    def label_def(): # 定义坐标数字字体及大小
        plt.xticks(fontproperties='Times New Roman', size=8)
        plt.yticks(fontproperties='Times New Roman', size=8)
     
    if __name__ == '__main__':
        img = cv2.imread('D://pictures//Fig0335(a)(ckt_board_saltpep_prob_pt05).tif', 0)
        img_median = cv2.medianBlur(img, 7)
        out = auto_median_filter(img, 7)
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        plt.subplot(131), plt.imshow(img, "gray"), plt.title('椒盐噪声', fontsize='small'), label_def()
        plt.subplot(132), plt.imshow(img_median, "gray"), plt.title('中值滤波', fontsize='small'), label_def()
        plt.subplot(133), plt.imshow(out, "gray"), plt.title('自适应中值滤波', fontsize='small'), label_def()
        plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    高斯滤波

    opencv函数 cv2.GaussianBlur(img,(3,3),1.3) 实现高斯滤波
    其中(3,3)为滤波器的大小;1.3为滤波器的标准差,如果标准差这个参数设置为0,则程序会根据滤波器大小自动计算得到标准差。
    图片内容里面噪声

    import cv2
    img=cv2.imread('../001.jpg')
    #(3, 3)表示高斯滤波器的长和宽都为3,1.3表示滤波器的标准差
    out=cv2.GaussianBlur(img,(3,3),1.3)
    cv2.imwrite('out.jpg',out)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    双边滤波

    双边滤波是一种非线性滤波方法,是结合了图像的邻近度和像素值相似度的一种折中,在滤除噪声的同时可以保留原图的边缘信息。整个双边滤波是由两个函数构成:一个函数是由空间距离决定的滤波器系数,另外一个诗由像素差值决定的滤波器系数。
    保全图像中的边缘信息,能在保持边界清晰的情况下有效的去除噪音
    https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
    API形如:cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)

    #API形如:cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)
    
    import cv2
    img = cv2.imread('11.png')
    # 双边滤波 
    # params:img,处理半径 d=-1则自动计算,sigmaColor(灰度差权重),sigmaSpace(邻域距离权重)
    # 灰度差越大(边缘),权重越小
    # 邻域距离越大,权重越小
    img01 = cv2.bilateralFilter(img, 51, 10, 10)
    cv2.imshow("bilateralFilter01", img01)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    https://zhuanlan.zhihu.com/p/522225954?utm_id=0

    导向滤波

    介绍-百度 http://www.taodudu.cc/news/show-5704877.html?action=onClick
    在滤波效果上,引导滤波和双边滤波差不多,然后在一些细节上,引导滤波较好(在PS的磨皮美白中,经过亲生实践,效果更好)。
    引导滤波最大的优势:可以写出时间复杂度与窗口大小无关的算法,因此在使用大窗口处理图片时,其效率更高。

    import argparse  # 导包
    import cv2
    import matplotlib.pyplot as plt
    import skimage
    
    #cv2.guidedFilter(guide, src, dst, radius, eps[, dDepth]) 
    #guide: nparrayguided image (or array of images) with up to 3 channels,if it have more then 3 channels then only first 3 channels will be used.
    #src: nparrayfiltering image with any numbers of channels.
    #radius: intradius of Guided Filter.
    #eps: floatregularization term of Guided Filter.{eps}^2 is similar to the sigma in the color space into bilateralFilter().
    #dDepth: intoptional depth of the output image. 一般取-1
    
    img=cv2.imread('../001.jpg')
    guide=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #用灰度图作为引导
    dst1=cv2.ximgproc.guidedFilter(guide=guide,src=img,radius=8,eps=50,dDepth=-1)
    dst2=cv2.ximgproc.guidedFilter(guide=guide,src=img,radius=8,eps=200,dDepth=-1)
    dst3=cv2.ximgproc.guidedFilter(guide=guide,src=img,radius=8,eps=500,dDepth=-1)
    
    cv2.imshow("Img",img)  
    cv2.imshow("dst1",dst1)
    cv2.imshow("dst2",dst2)
    cv2.imshow("dst3",dst3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    实践操作

    上面讲述完了,上干活
    环境配置-少走弯路

    # 我用的Python3.8
    # 安装 cv2 包
    pip3 install opencv-python
    # 安装 cv2.ximgproc包
    # 注意 opencv-contrib-python 和 opencv-python 版本号必须一致,否则问题无穷,哭不出的那种
    pip list | grep opencv       
    #>> opencv-python             4.7.0.72  
    pip3 install opencv-contrib-python==4.7.0.72 
    # 检查一下
    pip list | grep opencv
    >> opencv-contrib-python     4.7.0.72            
    >> opencv-python             4.7.0.72  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Note:

    1. 目前自适应中值滤波算法之能处理灰度图片,后续优化
    2. 导向滤波,使用灰度做引导,因此读取的时候要注意参数 “cv2.IMREAD_COLOR”
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
     
     
    # for gray image
    # S_max mast be grather 3
    # 此算法只支持 灰度图片的滤波
    def auto_median_filter(img, S_max):
        output = img.copy()
     
        def class_B(z_xy, z_med, z_max, z_min):
            if (z_min < z_xy) & (z_xy < z_max):
                return z_xy
            else:
    		    #z_xy 是个噪声,消除它: 使用z_med替换
                return z_med
     
        S_ori = 3
    	# cv2.copyMakeBorder() 函数是用来在图像周围添加边框的
    	# 增加边框,兼容边界的像素点
    	# 可以在开始的时候增加S_max厚度的边框,后面就不用动态增加了
    	# S_ori // 2  取整
        copy = cv2.copyMakeBorder(img, *[S_ori // 2] * 4, borderType=cv2.BORDER_DEFAULT)  # 补零
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                def class_A(copy, S_ori=3):
                    board = S_ori // 2
                    z_med = np.median(copy[i:i + board, j:j + board])
                    z_max = np.max(copy[i:i + board, j:j + board])
                    z_min = np.min(copy[i:i + board, j:j + board])
     
                    if (z_min < z_med) & (z_med < z_max):
    				    # z_med 不是噪声
                        output[i, j] = class_B(copy[i, j], z_med, z_max, z_min)
                    else:
                        # next_size = S_ori + 2
    					# # z_med 是个噪声,增大滤波窗口,寻找下一个不是噪声的中值
                        next_size = cv2.copyMakeBorder(copy, *[1] * 4, borderType=cv2.BORDER_DEFAULT)  # 增尺寸
                        S_ori = S_ori + 2
                        if S_ori <= S_max:
    					    # 
                            return class_A(next_size, S_ori)
                        else:
    					    #到达最大窗口,没有找到“不是噪声的中值”,直接中值滤波
                            output[i, j] = z_med
                class_A(copy, 3)
        return output.astype(np.uint8)
     
    def label_def(): # 定义坐标数字字体及大小
        plt.xticks(fontproperties='Times New Roman', size=8)
        plt.yticks(fontproperties='Times New Roman', size=8)
     
    if __name__ == '__main__':
        img = cv2.imread('./image_002.png',cv2.IMREAD_GRAYSCALE)
        img_median = cv2.medianBlur(img, 7)
        out = auto_median_filter(img, 7) 
    	#这里的image 要求必须是单通道的(cv2.IMREAD_GRAYSCALE),否则会 出现异常: " Use a.any() or a.all() ",因为np.max执行完之后,返回值不是一个而是一组
    	#因此auto_median_filter的入参中img 必须是灰度的
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        plt.subplot(231), plt.imshow(img, "gray"), plt.title('椒盐噪声', fontsize='small'), label_def()
        plt.subplot(232), plt.imshow(img_median, "gray"), plt.title(' 中值滤波', fontsize='small'), label_def()
        plt.subplot(233), plt.imshow(out, "gray"), plt.title('中值滤波', fontsize='small'), label_def()
        # 高斯滤波
        img = cv2.imread('./image_002.png',cv2.IMREAD_COLOR) 
        img_gaosi=cv2.GaussianBlur(img,(3,3),1.3)
        plt.subplot(234), plt.imshow(img_gaosi, "gray"), plt.title('高斯滤波', fontsize='small'), label_def()
    
        #双边滤波
        img01 = cv2.bilateralFilter(img, 51, 10, 10)
        plt.subplot(235), plt.imshow(img01, "gray"), plt.title('双边滤波', fontsize='small'), label_def()
    
        #导向滤波
        img = cv2.imread('./image_002.png',cv2.IMREAD_COLOR) # 
        guide=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #用灰度图作为引导,这里要求img 是多通道读取(cv2.IMREAD_COLOR),否则报异常 " 'scn' is 1 "
        dst1=cv2.ximgproc.guidedFilter(guide=guide,src=img,radius=8,eps=50,dDepth=-1)
        plt.subplot(236), plt.imshow(dst1, "导向滤波"), plt.title('dao xiang', fontsize='small'), label_def()
    
        plt.show()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    【游戏开发算法每日一记】使用随机prime算法生成错综复杂效果的迷宫(C#,C++和Unity版)
    Codeforces 1605C. Dominant Character
    上海控安SmartRocket系列产品推介(五):SmartRocket Scanner软件成分分析工具
    devops-4:Jenkins基于k8s cloud和docker cloud动态增减节点
    企业日志分析ELK(Logstash+Elasticsearch+Kibana)介绍及搭建
    拼搏一周,刷了 1000 道 Java 高频面试题喜提阿里 offer,定级 P7
    水厂除砷项目,砷出水未检出
    测试工程师常见的面试问题及回答建议
    基于SSM的计算机技术论坛管理系统,高质量论文范例,可拿去就用
    深蓝激光slam理论与实践-第五节笔记(基于滤波器的激光slam方法(Grid-based))
  • 原文地址:https://blog.csdn.net/guiyuan_yelang/article/details/132831795