python-opencv 中值滤波{cv2.medianBlur(src, ksize)}的用法

编辑: admin 分类: python 发布时间: 2021-12-24 来源:互联网

python-opencv 中值滤波{cv2.medianBlur(src, ksize)}

中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。与邻域平均法类似,但计算的是中值

#用中值法
for y in xrange(1,myh-1):
    for x in xrange(1,myw-1):
        lbimg[y,x]=np.median(tmpimg[y-1:y+2,x-1:x+2]

下面调用opencv的函数

# -*- coding: utf-8 -*-   
#code:myhaspl@myhaspl.com
#中值滤波
import cv2
import numpy as np
fn="test3.jpg"
myimg=cv2.imread(fn)
img=cv2.cvtColor(myimg,cv2.COLOR_BGR2GRAY)
#加上椒盐噪声
#灰阶范围
w=img.shape[1]
h=img.shape[0]
newimg=np.array(img)
#噪声点数量
noisecount=50000
for k in xrange(0,noisecount):
    xi=int(np.random.uniform(0,newimg.shape[1]))
    xj=int(np.random.uniform(0,newimg.shape[0]))
    newimg[xj,xi]=255
#滤波去噪
lbimg=cv2.medianBlur(newimg,3)
cv2.imshow('src',newimg)
cv2.imshow('dst',lbimg)
cv2.waitKey()
cv2.destroyAllWindows()       

中值滤波忽略了较高阶灰度和较低阶灰度,直接取中值,因此有效得过滤椒盐噪声。

这里写图片描述

对高斯噪声的滤波

这里写图片描述

用scipy.signal中值滤波

中值滤波技术能有效抑制噪声,通过把数字图像中一点的值用该点周围的各点值的中位数来代替,让这些值接近,以消除原图像中的噪声。

*模拟中值滤波

>>> import random
>>> import numpy as np
>>> import scipy.signal as signal
>>> x=np.arange(0,100,10)
>>> random.shuffle(x)
>>> x
array([70, 80, 30, 20, 10, 90,  0, 60, 40, 50])
>>> signal.medfilt(x,3) #一维中值滤波
array([ 70.,  70.,  30.,  20.,  20.,  10.,  60.,  40.,  50.,  40.])

signal的medfilt()方法传入两个参数,第一个参数是要作中值滤波的信号,第二个参数是邻域的大小(奇数)。如邻域为3即是每个点自己和左右各一个点成为一个邻域。在每个位置的邻域中选取中位数替换这个位置的数,也就是该函数的返回值数组。如果邻域中出现没有元素的位置,那么以0补齐。

>>> x=np.random.randint(1,1000,(4,4))
>>> x
array([[ 31,  33, 745, 483],
       [331, 469, 804, 479],
       [235, 487, 244, 982],
       [857, 114, 167, 174]])
>>> signal.medfilt(x,(3,3)) #二维中值滤波
array([[   0.,   33.,  469.,    0.],
       [  33.,  331.,  483.,  479.],
       [ 235.,  331.,  469.,  174.],
       [   0.,  167.,  167.,    0.]])

二维中值滤波还可以用signal.medfilt2d(),速度较快,但只支持int8,float32和float64。

*对图像中值滤波 (这个代码我还没试,如果出现问题可以怀疑是代码的问题)

import numpy as np
from PIL import Image
import scipy.signal as signal
im=Image.open('test.jpg') #读入图片并建立Image对象im
data=[] #存储图像中所有像素值的list(二维)
width,height=im.size #将图片尺寸记录下来
#读取图像像素的值
for h in range(height): #对每个行号h
    row=[] #记录每一行像素
    for w in range(width): #对每行的每个像素列位置w
        value=im.getpixel((h,w)) #用getpixel读取这一点像素值
        row.append(value)#把它加到这一行的list中去
    data.append(row) #把记录好的每一行加到data的子list中去,就建立了模拟的二维list
data=signal.medfilt(data,kernel_size=3) #二维中值滤波
data=np.int32(data) #转换为int类型,以使用快速二维滤波
#创建并保存结果
for h in range(height): #对每一行
    for w in range(width): #对该行的每一个列号
        im.putpixel((h,w),tuple(data[h][w])) #将data中该位置的值存进图像,要求参数为tuple
im.save('result.jpg')#存储

opencv中值滤波medianBlur

中值滤波是一种典型的非线性滤波,是基于排序统计理论的一种能够有效抑制噪声的非线性信号处理技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。该方法在取出脉冲噪声、椒盐噪声的同时能保留图像的边缘细节。这些优良特性是线性滤波所不具备的。

中值滤波首先也得生成一个滤波模板,将该模板内的各像素值进行排序,生成单调上升或单调下降的二维数据序列,二维中值滤波输出为g(x, y)=medf{f(x-k, y-1),(k, l∈w)},其中f(x,y)和g(x,y)分别是原图像和处理后图像, w为输入的二维模板,能够在整幅图像上滑动,通常尺寸为3*3或5*5区域,也可以是不同的形状如线状、圆形、十字形、圆环形等。通过从图像中的二维模板取出奇数个数据进行排序,用排序后的中值取代要处理的数据即可。

中值滤波对消除椒盐噪声非常有效,能够克服线性滤波器带来的图像细节模糊等弊端,能够有效保护图像边缘信息,是非常经典的平滑噪声处理方法。在光学测量条纹图像的香味分析处理方法中有特殊作用,但在条纹中心分析方法中作用不大。

中值滤波相较于线性滤波中的均值滤波优点在前面已经提到,取得良好滤波效果的代价就是耗时的提升,可能达到均值滤波的数倍,而且对于细节较多的图像也不太适用。

opencv中提供了medianBlur()函数实现了中值滤波操作,其原型如下:

C++: void medianBlur(InputArray src, OutputArray dst, int ksize)

参数解释:

. InputArray src: 输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个,如而对于较大孔径尺寸的图片,图像深度只能是CV_8U。

. OutputArray dst: 输出图像,尺寸和类型与输入图像一致,可以使用Mat::Clone以原图像为模板来初始化输出图像dst

. int ksize: 滤波模板的尺寸大小,必须是大于1的奇数,如3、5、7……

示例程序:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
//定义全局变量
Mat g_mSrcImage;
Mat g_mDstImage;
const int g_nMedianBlurMaxValue = 5;
int g_nMedianBlurValue;
int g_nkernelSize;
//定义回调函数
void on_medianBlurTrackBar(int, void*);
int main()
{
    g_mSrcImage = imread("lena.jpg");
    //判断文件是否加载成功
    if(g_mSrcImage.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl;
    //判断图像是否是CV_8U图像
    if(0 <= g_mSrcImage.depth() <= 255)
        cout << "加载图像符合处理要求!" << endl;
    else
    {
        cout << "图像深度不是CV_8U,程序即将退出..." << endl;
        return -1;
    }
    namedWindow("原图像", WINDOW_AUTOSIZE);
    imshow("原图像", g_mSrcImage);
    //输出图像窗口属性及轨迹条名称
    namedWindow("中值滤波图像", WINDOW_AUTOSIZE);
    char medianBlurName[20];
    sprintf(medianBlurName, "核函数尺寸 %d", g_nMedianBlurMaxValue);
    g_nMedianBlurValue = 1;
    //创建轨迹条
    createTrackbar(medianBlurName, "中值滤波图像", &g_nMedianBlurValue,
                    g_nMedianBlurMaxValue, on_medianBlurTrackBar);
    on_medianBlurTrackBar(g_nMedianBlurValue, 0);
    waitKey(0);
    return 0;
}
void on_medianBlurTrackBar(int, void*)
{
    //重新计算尺寸值,尺寸值应为大于1的奇数
    g_nkernelSize = g_nMedianBlurValue * 2 + 1;
    medianBlur(g_mSrcImage, g_mDstImage, g_nkernelSize);
    imshow("中值滤波图像", g_mDstImage);
}

运行结果:

这里写图片描述

程序说明:

对于程序中对图像深度的判断根据如下标准:

    CV_8U - 8-bit unsigned integers ( 0..255 )
    CV_8S - 8-bit signed integers ( -128..127 )
    CV_16U - 16-bit unsigned integers ( 0..65535 )
    CV_16S - 16-bit signed integers ( -32768..32767 )
    CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
    CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
    CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )

以上为个人经验,希望能给大家一个参考,也希望大家多多支持hwidc。

【本文由:http://www.yidunidc.com/krzq.html 复制请保留原URL】