Opencv+python:中值滤波十字形窗口(2020.09.01更新)

前言

在进行图像空域处理时,对于椒盐噪声的图像,中值滤波是一个很不错的选择,一般来说mask有矩形 椭形 和十字形,
十字形被认为在处理含有少数尖锥基元的图像更能保证尖锥的形状,由于没找到Matlab自带的函数库实现十字窗口,并且论坛上有极少的Opencv基于python的代码,大多还是付费的,于是自己写了一个模板,能够实现基本原理,至于效果和处理速度,有时间以后会进行优化。
2020.08.27:基本实现中值滤波十字窗口
2020.09.01:修复了8.27中除3×3窗口以外自定义窗口时图像显示错误的问题

中值滤波

中值滤波的原理很简单,不考虑图像填充,将一个框架,框在图像像素,框架上的像素数值按升降序排列,取中位数作为原像素点的新值。矩形的窗口都有专门的函数轻松实现,十字窗口则是以像素点为中心点,向四周直线发散,形成十字样式。
至于python上的实现逻辑,我将它分成RGB模式和Gray模式。
先说灰度模式,比较简单,它是一个二维张量,只需要用模板进行排序,通过基础的循环进行mask滑动,并且重新赋值即可。
RGB模式比灰度模式多了一步,将RGB图像是三维张量,先将其拆分成3个二维张量,然后再按照灰度模式的方法进行赋值,最后再进行图像合并。
目前代码的计算复杂度较高,还没有进行优化,彩色图像处理会花费较长时间。

更新:2020年09月01日 (修复自定义窗口大小问题)

修复了8.27日代码中只能实现3×3窗口十字滤波,更改窗口大小无法显示或显示错误的漏洞。
1.不需要指定色彩模式,只要是RGB或者灰度图可以直接传入函数
2.支持自定义框架大小
3.支持常数边界填充,也可以稍微改动进行OpenCV支持的所有填充方式
4.目前就写了十字窗口,所以type只支持十字类型
5.耗时间长效果未调试

def medfilter (pic,scale=[3,3],pad = [0,0,0],type='cross'):
    '''
    中值滤波器
    pic 为被作用图片
    type  为中值窗口类型 可选参数为 'cross'
    scale 为窗口大小,如[3,3]
    pad   为填充方法 输入值为一维矩阵
    '''
    import numpy as np
    import cv2 as cv
	#分别获取用于常数填充的四周填充的距离
    top_bottom = int((scale[1]-1)/2)
    left_right = int((scale[0]-1)/2)
	#获取用于中值滤波窗口的中值位数(如3×3中,5个数排序后取第三个数)
    mednum = (scale[1]+scale[0])/2-1
    total_dim = np.shape(pic)
    #获取图像的行列数据
    pic_line = total_dim[0]
    pic_row  = total_dim[1] #列
    #进行指定的边界填充
    pic = cv.copyMakeBorder(pic,top_bottom,top_bottom,left_right,left_right,cv.BORDER_CONSTANT,value = pad)

	#定义十字中指滤波函数
    def crossfilt(pic = pic ,pic_line = pic_line,pic_row = pic_row):
        for i in range(pic_line):
            for j in range(pic_row):	#两个for循环遍历图像所有像素
                mask=[pic[i,j]]			#确定十字形窗口中心
                for n in range(1,top_bottom+1):	#以第(i,j)个像素为中心点像四周十字形发散
                    arra = [pic[i,j+n],pic[i,j-n],pic[i-n,j],pic[i+n,j]]
                    mask = np.hstack((mask,arra))
                pic[i,j] = np.sort(mask)[int(mednum)]
    #通过输入图像维度判断Gray或者RGB
    if len(total_dim)>2:			#RGB图像
        r,g,b = cv.split(pic)
        r,g,b = medfilter(r),medfilter(g),medfilter(b)
        pic = cv.merge([r,g,b])
    elif len(total_dim)<=2:			#灰度图像
        crossfilt(pic)
    return pic

测试及效果

'''
========================================以下为测试区===============================================================
 '''


import cv2 as cv
import numpy as np
A = cv.imread('lena2.png',0)
B = medfilter(A)
cv.namedWindow('img',cv.WINDOW_FREERATIO)
cv.imshow('img',B)
cv.waitKey(0)
cv.destroyAllWindows()
cv.imwrite('lena2po.png',B)

在这里插入图片描述

===================== 历史更新日志================

2020年08月27日 所需库及函数特点

OpenCV
numpy

1.不需要指定色彩模式,只要是RGB或者灰度图可以直接传入函数
2.支持自定义框架大小
3.支持常数边界填充,也可以稍微改动进行OpenCV支持的所有填充方式
4.目前就写了十字窗口,所以type只支持十字类型
5.耗时间长效果未调试

代码(请确保安装所需库)

def medfilter (pic,scale=[3,3],pad = [0,0,0],type='cross'):
    '''
    中值滤波器
    pic 为被作用图片
    type  为中值窗口类型 可选参数为 'cross'
    scale 为窗口大小,如[3,3]
    pad   为填充方法 输入值为一维矩阵
    '''
    import numpy as np
    import cv2 as cv
#获取图像的长宽基本信息,以及边界填充上下左右的距离,并实现边界填充
    top_bottom = int((scale[1]-1)/2)
    left_right = int((scale[0]-1)/2)
    mednum = (scale[1]+scale[0])/2-1
    total_dim = np.shape(pic)
    pic_line = total_dim[0]
    pic_row  = total_dim[1] #列
    pic = cv.copyMakeBorder(pic,top_bottom,top_bottom,left_right,left_right,cv.BORDER_CONSTANT,value = pad)
#通过双重for循环进行十字框架的游走,以当前元素为中心点进行四周发散,形成十字框架,并排序后赋予新的像素值

    def crossfilt(pic = pic ,pic_line = pic_line,pic_row = pic_row):
        for i in range(pic_line):
            for j in range(pic_row):
                mask = [pic[i,j], pic[i+1,j], pic[i-1,j], pic[i,j+1], pic[i,j-1]]
                pic[i,j] = np.sort(mask)[int(mednum)]
#判断图像模式大于2则为RGB模式,小于等于2则为灰度模式
    if len(total_dim)>2:
        r,g,b = cv.split(pic)
        r,g,b = medfilter(r),medfilter(g),medfilter(b)
        pic = cv.merge([r,g,b])
    elif len(total_dim)<=2:
        crossfilt(pic)
    return pic
'''


  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曹栩珩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值