2013-08-15 14:24:04 zhujun007007 阅读数 1587

有时候我们需要对图像进行椒盐噪声过滤,但是opencv并没有椒盐噪声过滤的函数。

下面我自己写的一个简单的椒盐噪声过滤函数,适合于二值化后出现的椒盐噪声过滤,

opencv版本:2.3.1  IDE:vs2010 语言:C++。


/**
*@brief 随机噪声点过滤
*@param src 预处理图片
*@param w 预处理噪声点像素宽
*@param h 预处理噪声点像素高
@return None
*/
void Recognize::randomPointNoseFilter(Mat &src, int w, int h)
{
    for(int i = 0; i < src.rows - h; i++)
        for(int j = 0; j < src.cols - w; j++)
        {
            int countw = 0,counth = 0;
            for(int k = 0; k < w; k++)
            {
                if((int)src.data[i * src.cols + j + k] != 0 || (int)src.data[(i + h - 1) * src.cols + j + k] != 0)
                    break;
                countw++;
            }
            for(int k = 0; k < h; k++)
            {
                if((int)src.data[(i + k) * src.cols + j] != 0 || (int)src.data[(i + k) * src.cols + j + w - 1] != 0)
                    break;
                counth++;
            }
            if(countw == w && counth == h)
            {
                for(int k = 0; k < h; k++)
                    for(int l = 0; l < w; l++)
                        src.data[(i + k) * src.cols + j + l] = 0;
            }
        }
}

2018-11-15 13:28:52 lehuoziyuan 阅读数 718

椒盐噪声是椒噪声和盐噪声的合称,它是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声,去除椒盐噪声的最常用算法是中值滤波,在去除椒盐噪声的效果上均值滤波不如中值滤波,本文所给的代码会证明这个结论。

首先说下怎么给图像加上椒噪声和盐噪声。我们可以利用C++的srand函数和rand函数来产生随机坐标,并把这些坐标置为椒噪声点或盐噪声点。
这两个函数的用法就不多说了,大家可自行搜索下网上的资源,再结合代码大家很容易知道怎么用。值得一提的是rand函数的范围为0至RAND_MAX,是整数,RAND_MAX的值在stdlib.h中有定义,定义如下:
#define RAND_MAX 0x7fff

在本文的代码中,盐噪声的BGR值为(250,150,250),椒噪声的BGR值为(250,150,50)

再来说均值滤波和中值滤波
均值滤波:它是用某点邻域窗口内的的所有像素的平均值来代替锚点处的值。它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。
中值滤波:中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。

OpenCV提供了函数medianBlur和函数blur来实现均值滤波和中值滤波,这两个函数的使用方法简单,没必要作过多的说明,唯一需要说明白是这两个函数的第三个参数均需提供核算子的大小,关于“核算子”的概念,大家可参考博文https://blog.csdn.net/lehuoziyuan/article/details/84101788

代码如下

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
代码中用到的图像下载链接:http://pan.baidu.com/s/1kUI2NAn 密码:nu5t

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <time.h>  
#include <iostream>

using namespace cv;
using namespace std;

void ColorSalt(Mat& image, int n)//本函数加入彩色盐噪声  
{
        srand((unsigned)time(NULL));
        for (int k = 0; k<n; k++)//将图像中n个像素随机置零  
        {
                int i = rand() % image.cols;
                int j = rand() % image.rows; RAND_MAX
                //将图像颜色随机改变  
                image.at<Vec3b>(j, i)[0] = 250;
                image.at<Vec3b>(j, i)[1] = 150;
                image.at<Vec3b>(j, i)[2] = 250;
        }
}

void ColorPepper(Mat& image, int n)//本函数加入彩色椒噪声  
{
        srand((unsigned)time(NULL));
        for (int k = 0; k<n; k++)
        {
                int i = rand() % image.cols;
                int j = rand() % image.rows;
                //将图像颜色随机改变  
                image.at<Vec3b>(j, i)[0] = 250;
                image.at<Vec3b>(j, i)[1] = 150;
                image.at<Vec3b>(j, i)[2] = 50;
        }
}

int main()
{
        //源图像  
        Mat scr = imread("qiu_ye.jpg");
        Mat dst;
        Mat img = scr.clone();
        Mat img1 = scr.clone();

        cout << scr.channels() << " " << scr.type() << "  " << scr.depth();
        imshow("原图像", scr);

        ColorSalt(scr, 5000);  //加入白盐噪声  
        ColorPepper(scr, 1000); //加入黑椒噪声  
        imshow("带噪声的图像", scr);

        medianBlur(scr, dst, 3);  //中值滤波,核算子大小为3,锚点为默认的中间点
        imshow("中值滤波结果", dst);

        ColorSalt(img, 5000);
        ColorPepper(img, 1000);
        blur(img, dst, Size(3, 3));//均值滤波,核算子大小为3,锚点为默认的中间点
        imshow("均值滤波结果", dst);

        waitKey(0);
        return EXIT_SUCCESS;
}


运行结果截图如下

从截图中我们可以看出,对于椒盐噪声,中值滤波的效果优于均值滤波。

2019-10-06 14:01:14 qq_39653453 阅读数 45

%过滤椒盐噪声较好的办法使用Q为正值的反调和滤波器
clc
clear
f=imread('D:\研究生课程\其他\MATLAB图像处理\亮度调节与空间滤波\5.jpg');
[M,N]=size(f);
R=imnoise2('salt & pepper',M,N,0.1,0);%概率为0.1的椒盐噪声
c=find(R==0);
gp=f;
gp(c)=0;
subplot(3,2,1)
imshow(f)
title('原图')
subplot(3,2,2)
imshow(gp)
title('概率0.1椒盐噪声污染')

R=imnoise2('salt & pepper',M,N,0,0.1);%仅被盐粒噪声污染
c=find(R==1);
gs=f;
gs(c)=255;
subplot(3,2,3)
imshow(gs);
title('被盐粒噪声污染')

%用反调和滤波器处理
fp=spfilt(gp,'chmean',3,3,1.5);%椒盐噪声是加了暗值的干扰,所以1.5
subplot(3,2,4)%3*3 Q=1.5的反调和滤波器滤波结果
imshow(fp)
title('过滤椒盐噪声')

fs=spfilt(gs,'chmean',3,3,-1.5);%椒盐噪声是加了亮值的干扰,所以-1.5
subplot(3,2,5)
imshow(fs)
title('过滤盐粒噪声')


 

2017-02-06 22:31:00 weixin_33851604 阅读数 120

总结学习下图像处理方面基础知识。

这是第一篇,简单的介绍下使用OpenCV的三个基本功能:

  • 图像的读取
  • 图像的显示
  • 访问图像的像素值

然后概述下图像噪声的类型,并为图像添加两种常见的噪声:高斯噪声和椒盐噪声。
最后,使用中值滤波和均值滤波来处理带有噪声的图像。

OpenCV基础

在OpenCV中,完成图像的输入输出以及显示,只需要以下几个函数:

namedWindow
创建一个可以通过其名字引用的窗口。第一个参数,设置窗口的name,可以通过name引用该窗口;第二个参数,设置窗口的大小。有以下几个选择:

  • WINDOW_NORMAL or WINDOW_AUTOSIZE 调整窗口的大小以适应图像,不同的是,使用WINDOW_NORMAL可以手动调整窗口的大小;WINDOW_AUTOSIZE不能调整窗口的大小。
  • WINDOW_FREERATIO or WINDOW_KEEPRATIO 改变窗口时是否会保持图像的ratio不变,没发现这俩有什么区别。

imshow显示图像

imread 读取图像数据到Mat中,第一个参数是图像的文件名;第二个参数是标志,标识怎么处理图像的色彩。常用的几个选项:

  • IMREAD_UNCHANGED 和原图像保持一直不变
  • IMREAD_GRAYSCALE 将图像转换为单通道的灰度图
  • IMREAD_COLOR 将图像转换为3通道的BGR,默认选项
  • IMREAD_REDUCED_GRAYSCALE_2 IMREAD_REDUCED_GRAYSCALE_4 IMREAD_REDUCED_GRAYSCALE_8 单通道灰度图读入图像,并减小图像的大小。减小的值为1/2,1/4,1/8
  • IMREAD_REDUCED_COLOR_2 IMREAD_REDUCED_COLOR_4 IMREAD_REDUCED_COLOR_2 3通道BGR读入图像,并减小图像的大小。减小的值为1/2,1/4,1/8

Mat是OpenCV中最重要的数据结构,在做图像处理时基本都是对该结构体的操作。Mat由两部分构成:矩阵头矩阵数据,矩阵头较小,创建的每个Mat实例都拥有一个矩阵头,而矩阵数据通常占有较大的空间,OpenCV中通过引用计数来管理这部分内存空间,当调用赋值运算符和拷贝构造函数时,并不会只复制矩阵头,并不会复制矩阵数据,只是将其的引用计数加1.例如:

Mat m = imread("img.jpg");
Mat a = m; // 赋值运算符
Mat b(m); // 拷贝构造函数

上面代码中的a,bm各自拥有自己的矩阵头,其引用的数据却指向同一份。也就是说,修改了其中任意一个,都会影响到其余的两个。

要想复制矩阵数据,可以调用clonecopyTo这两个函数

Mat m = imread("img.jpg");
Mat f = m.clone();
Mat g ;
m.copyTo(g);

将图像读入到Mat后,有三种方式访问Mat中的数据:

  • 通过指针
  • 使用迭代器
  • 调用at

图像噪声

图像噪声是图像在获取或传输的过程中受到随机信号的干扰,在图像上出现的一些随机的、离散的、孤立的像素点,这些点会干扰人眼对图像信息的分析。图像的噪声通常是比较复杂的,很多时候将其看成是多维随机过程,因而可以借助于随即过程描述噪声,即使用概率分布函数和概率密度函数。

图像的噪声很多,性质也千差万别, 可以通过不同的方法给噪声分类。
按照产生的原因:

  • 外部噪声
  • 内部噪声
    这种分类方法,有助于理解噪声产生的源头,但对于降噪算法只能起到原理上的帮组。

噪声和图像信号的关系,可以分为:

  • 加性噪声,加性噪声和图像信号强度不相关,这类噪声可以看着理想无噪声图像f和噪声的和。
  • 乘性噪声,乘性噪声和图像信号是相关的,往往随图像信号的变化而变化。
    而为了分析处理的方便,常常将乘性噪声近似认为是加性噪声,而且总是假定信号和噪声是互相独立的。

最重要的来了,按照概率密度函数(PDF)分类:

  • 高斯噪声,高斯噪声模型经常被用于实践中。
  • 脉冲噪声(椒盐噪声),图像上一个个点,也可称为散粒和尖峰噪声。
  • 伽马噪声
  • 瑞利噪声
  • 指数分布噪声
  • 均匀分布噪声
    这种分类方法,引入了数学模型,对设计过滤算法比较有帮助。

给图像添加噪声

按照指定的噪声类型,生成一个随机数,然后将这个随机数加到源像素值上,并将得到的值所放到[0,255]区间即可。

C++11 随机数发生器

新的随机数生成器被抽象成了两个部分:随机数生成引擎和要生成的随机数符合的分布。
随机数引擎有三种:

  • linear_congruential_engine 线性同余算法
  • mersenne_twister_engine 梅森旋转算法
  • subtract_with_carry_engine 带进位的线性同余算法

第一种最常用,而且速度比较快;第二种号称最好的伪随机数生成器

#include <random>

std::random_device rd; // 随机数种子
std::mt19937 mt(rd()); // 随机数引擎
std::normal_distribution<> d(5,20); // 高斯分布

std::map<int,int> hist;
for(int n = 0; n < 10000; n ++)
    ++hist[std::round(d(mt))]; // 生成符合高斯分布的随机数

添加图像噪声

使用C++的随机数发生器为图像添加两种噪声:椒盐噪声和高斯噪声。
椒盐噪声是图像中离散分布的白点或者黑点,其代码如下:

// 添加椒盐噪声
void addSaltNoise(Mat &m, int num)
{
    // 随机数产生器
    std::random_device rd; //种子
    std::mt19937 gen(rd()); // 随机数引擎

    auto cols = m.cols * m.channels();

    for (int i = 0; i < num; i++)
    {
        auto row = static_cast<int>(gen() % m.rows);
        auto col = static_cast<int>(gen() % cols);

        auto p = m.ptr<uchar>(row);
        p[col++] = 255;
        p[col++] = 255;
        p[col] = 255;
    }
}

上述代码中使用ptr<uchar>()获取图像某一行的行首指针,得到行首指针后就可以任意的访问改行的像素值。

高斯噪声是一种加性噪声,为图像添加高斯噪声的代码如下:

// 添加Gussia噪声
// 使用指针访问
void addGaussianNoise(Mat &m, int mu, int sigma)
{
    // 产生高斯分布随机数发生器
    std::random_device rd;
    std::mt19937 gen(rd());

    std::normal_distribution<> d(mu, sigma);

    auto rows = m.rows; // 行数
    auto cols = m.cols * m.channels(); // 列数

    for (int i = 0; i < rows; i++)
    {
        auto p = m.ptr<uchar>(i); // 取得行首指针
        for (int j = 0; j < cols; j++)
        {
            auto tmp = p[j] + d(gen);
            tmp = tmp > 255 ? 255 : tmp;
            tmp = tmp < 0 ? 0 : tmp;
            p[j] = tmp;
        }
    }
}

随机产生符合高斯分布的随机数,然后将该值和图像原有的像素值相加,并将得到的和压缩到[0,255]区间内。

439761-20170206223013229-1830634395.png

左边是原图,中间的是添加高斯噪声后的图像,最右边的是添加椒盐噪声后的图像。

使用滤波器去除噪声

根据噪声类型的不同,选择不同的滤波器过滤掉噪声。通常,对于椒盐噪声,选择中值滤波器(Median Filter),在去掉噪声的同时,不会模糊图像;对于高斯噪声,选择均值滤波器(Mean Filter),能够去掉噪声,但会对图像造成一定的模糊。
在OpenCV中,对应于均值滤波器的函数是blur,该函数需要5个参数,通常只设置前3个后两个使用默认值即可。
blur(m, m2, Size(5, 5));第一个参数是输入的图像,第二个参数是输出的图像,第三个参数是滤波器的大小,这里使用的是\(5 \times 5\)的矩形。

对应于中值滤波器的函数是medianBlur(m1, m3, 5);前两个参数是输入输出的图像,第三个参数是滤波器的大小,由于是选取的是中值,滤波器的大小通常是一个奇数。

下图是对有噪声图像使用滤波器后的结果,中间的是原始图像,左边的是使用均值滤波器过滤高斯噪声后的结果;右边的是使用中值滤波器过滤椒盐噪声后的结果。可以明显的看出,这两种滤波器都能够很好的去掉图像的噪声,但会对图像造成一定的模糊,尤其是均值滤波器造成的模糊比较明显。
439761-20170206223048635-583219556.png

总结

本文算是第一篇文章,简单的介绍下OpenCV的基本使用;接着访问图像中的像素,并借助于C++11的随机数库,为图像添加高斯噪声和椒盐噪声;最后使用中值滤波器和均值滤波器除去图像,并对结果进行了对比。

以后坚持每日对图像处理的一些知识进行整理。

2017-02-10 16:19:41 pvxv1bbl 阅读数 354

总结学习下图像处理方面基础知识。

这是第一篇,简单的介绍下使用OpenCV的三个基本功能:

  • 图像的读取
  • 图像的显示
  • 访问图像的像素值

然后概述下图像噪声的类型,并为图像添加两种常见的噪声:高斯噪声和椒盐噪声。
最后,使用中值滤波和均值滤波来处理带有噪声的图像。

OpenCV基础

在OpenCV中,完成图像的输入输出以及显示,只需要以下几个函数:

namedWindow
创建一个可以通过其名字引用的窗口。第一个参数,设置窗口的name,可以通过name引用该窗口;第二个参数,设置窗口的大小。有以下几个选择:

  • WINDOW_NORMAL or WINDOW_AUTOSIZE 调整窗口的大小以适应图像,不同的是,使用WINDOW_NORMAL可以手动调整窗口的大小;WINDOW_AUTOSIZE不能调整窗口的大小。
  • WINDOW_FREERATIO or WINDOW_KEEPRATIO 改变窗口时是否会保持图像的ratio不变,没发现这俩有什么区别。

imshow显示图像

imread 读取图像数据到Mat中,第一个参数是图像的文件名;第二个参数是标志,标识怎么处理图像的色彩。常用的几个选项:

  • IMREAD_UNCHANGED 和原图像保持一直不变
  • IMREAD_GRAYSCALE 将图像转换为单通道的灰度图
  • IMREAD_COLOR 将图像转换为3通道的BGR,默认选项
  • IMREAD_REDUCED_GRAYSCALE_2 IMREAD_REDUCED_GRAYSCALE_4 IMREAD_REDUCED_GRAYSCALE_8 单通道灰度图读入图像,并减小图像的大小。减小的值为1/2,1/4,1/8
  • IMREAD_REDUCED_COLOR_2 IMREAD_REDUCED_COLOR_4 IMREAD_REDUCED_COLOR_2 3通道BGR读入图像,并减小图像的大小。减小的值为1/2,1/4,1/8

Mat是OpenCV中最重要的数据结构,在做图像处理时基本都是对该结构体的操作。Mat由两部分构成:矩阵头矩阵数据,矩阵头较小,创建的每个Mat实例都拥有一个矩阵头,而矩阵数据通常占有较大的空间,OpenCV中通过引用计数来管理这部分内存空间,当调用赋值运算符和拷贝构造函数时,并不会只复制矩阵头,并不会复制矩阵数据,只是将其的引用计数加1.例如:

Mat m = imread("img.jpg");
Mat a = m; // 赋值运算符
Mat b(m); // 拷贝构造函数

上面代码中的a,bm各自拥有自己的矩阵头,其引用的数据却指向同一份。也就是说,修改了其中任意一个,都会影响到其余的两个。

要想复制矩阵数据,可以调用clonecopyTo这两个函数

Mat m = imread("img.jpg");
Mat f = m.clone();
Mat g ;
m.copyTo(g);

将图像读入到Mat后,有三种方式访问Mat中的数据:

  • 通过指针
  • 使用迭代器
  • 调用at

图像噪声

图像噪声是图像在获取或传输的过程中受到随机信号的干扰,在图像上出现的一些随机的、离散的、孤立的像素点,这些点会干扰人眼对图像信息的分析。图像的噪声通常是比较复杂的,很多时候将其看成是多维随机过程,因而可以借助于随即过程描述噪声,即使用概率分布函数和概率密度函数。

图像的噪声很多,性质也千差万别, 可以通过不同的方法给噪声分类。
按照产生的原因:

  • 外部噪声
  • 内部噪声
    这种分类方法,有助于理解噪声产生的源头,但对于降噪算法只能起到原理上的帮组。

噪声和图像信号的关系,可以分为:

  • 加性噪声,加性噪声和图像信号强度不相关,这类噪声可以看着理想无噪声图像f和噪声的和。
  • 乘性噪声,乘性噪声和图像信号是相关的,往往随图像信号的变化而变化。
    而为了分析处理的方便,常常将乘性噪声近似认为是加性噪声,而且总是假定信号和噪声是互相独立的。

最重要的来了,按照概率密度函数(PDF)分类:

  • 高斯噪声,高斯噪声模型经常被用于实践中。
  • 脉冲噪声(椒盐噪声),图像上一个个点,也可称为散粒和尖峰噪声。
  • 伽马噪声
  • 瑞利噪声
  • 指数分布噪声
  • 均匀分布噪声
    这种分类方法,引入了数学模型,对设计过滤算法比较有帮助。

给图像添加噪声

按照指定的噪声类型,生成一个随机数,然后将这个随机数加到源像素值上,并将得到的值所放到[0,255]区间即可。

C++11 随机数发生器

新的随机数生成器被抽象成了两个部分:随机数生成引擎和要生成的随机数符合的分布。
随机数引擎有三种:

  • linear_congruential_engine 线性同余算法
  • mersenne_twister_engine 梅森旋转算法
  • subtract_with_carry_engine 带进位的线性同余算法

第一种最常用,而且速度比较快;第二种号称最好的伪随机数生成器

#include <random>

std::random_device rd; // 随机数种子
std::mt19937 mt(rd()); // 随机数引擎
std::normal_distribution<> d(5,20); // 高斯分布

std::map<int,int> hist;
for(int n = 0; n < 10000; n ++)
    ++hist[std::round(d(mt))]; // 生成符合高斯分布的随机数

添加图像噪声

使用C++的随机数发生器为图像添加两种噪声:椒盐噪声和高斯噪声。
椒盐噪声是图像中离散分布的白点或者黑点,其代码如下:

// 添加椒盐噪声
void addSaltNoise(Mat &m, int num)
{
    // 随机数产生器
    std::random_device rd; //种子
    std::mt19937 gen(rd()); // 随机数引擎

    auto cols = m.cols * m.channels();

    for (int i = 0; i < num; i++)
    {
        auto row = static_cast<int>(gen() % m.rows);
        auto col = static_cast<int>(gen() % cols);

        auto p = m.ptr<uchar>(row);
        p[col++] = 255;
        p[col++] = 255;
        p[col] = 255;
    }
}

上述代码中使用ptr<uchar>()获取图像某一行的行首指针,得到行首指针后就可以任意的访问改行的像素值。

高斯噪声是一种加性噪声,为图像添加高斯噪声的代码如下:

// 添加Gussia噪声
// 使用指针访问
void addGaussianNoise(Mat &m, int mu, int sigma)
{
    // 产生高斯分布随机数发生器
    std::random_device rd;
    std::mt19937 gen(rd());

    std::normal_distribution<> d(mu, sigma);

    auto rows = m.rows; // 行数
    auto cols = m.cols * m.channels(); // 列数

    for (int i = 0; i < rows; i++)
    {
        auto p = m.ptr<uchar>(i); // 取得行首指针
        for (int j = 0; j < cols; j++)
        {
            auto tmp = p[j] + d(gen);
            tmp = tmp > 255 ? 255 : tmp;
            tmp = tmp < 0 ? 0 : tmp;
            p[j] = tmp;
        }
    }
}

随机产生符合高斯分布的随机数,然后将该值和图像原有的像素值相加,并将得到的和压缩到[0,255]区间内。

左边是原图,中间的是添加高斯噪声后的图像,最右边的是添加椒盐噪声后的图像。

使用滤波器去除噪声

根据噪声类型的不同,选择不同的滤波器过滤掉噪声。通常,对于椒盐噪声,选择中值滤波器(Median Filter),在去掉噪声的同时,不会模糊图像;对于高斯噪声,选择均值滤波器(Mean Filter),能够去掉噪声,但会对图像造成一定的模糊。
在OpenCV中,对应于均值滤波器的函数是blur,该函数需要5个参数,通常只设置前3个后两个使用默认值即可。
blur(m, m2, Size(5, 5));第一个参数是输入的图像,第二个参数是输出的图像,第三个参数是滤波器的大小,这里使用的是\(5 \times 5\)的矩形。

对应于中值滤波器的函数是medianBlur(m1, m3, 5);前两个参数是输入输出的图像,第三个参数是滤波器的大小,由于是选取的是中值,滤波器的大小通常是一个奇数。

下图是对有噪声图像使用滤波器后的结果,中间的是原始图像,左边的是使用均值滤波器过滤高斯噪声后的结果;右边的是使用中值滤波器过滤椒盐噪声后的结果。可以明显的看出,这两种滤波器都能够很好的去掉图像的噪声,但会对图像造成一定的模糊,尤其是均值滤波器造成的模糊比较明显。

总结

本文算是第一篇文章,简单的介绍下OpenCV的基本使用;接着访问图像中的像素,并借助于C++11的随机数库,为图像添加高斯噪声和椒盐噪声;最后使用中值滤波器和均值滤波器除去图像,并对结果进行了对比。

以后坚持每日对图像处理的一些知识进行整理。


没有更多推荐了,返回首页