适合的主要目标:二值化图像(只有黑白两色)
主要效果:去除较小的噪点和大块的噪点。
具体参考的博客:https://blog.csdn.net/ysc6688/article/details/50772382
真的很有用啊。
如果还不理解的话,这里有一份解读:
https://www.jianshu.com/p/ec78a1419bae
要注意的是,例子中的是白色是背景,黑色是目标和噪点,如果是在深度图中,那么就是黑色是背景(超过量程或者看不到就都是黑色),白色是目标。
因此建议大家先看完原文,我这里给出自己修改后的(有点小尴尬啦,其实我就是使用了一下,对,就是这么理直气壮。^-^)
下面是例子啦:
去除小的噪点:
/* 函数名: NaiveRemoveNoise
* 传入变量:
* img: 图像指针
* pNum: 元素周围的个数
* return: void
*/
void NaiveRemoveNoise(int pNum, Mat* img)
{
//naive remove noise
int i,j,m,n,nValue,nCount;
int nWidth = img->cols;
int nHeight =img->rows;
//set boundry to be white
for (i = 0; i < nWidth ; ++i)
{
img->at(0,i)=WHITE; //先行后列
img->at(nHeight-1,i)=WHITE; //先行后列
}
for (i = 0; i < nHeight ; ++i)
{
img->at(i,0)=WHITE;
img->at(i,nWidth-1)=WHITE;
}
//if the neighbor of a point is white but it is black, delete it
for (j = 1; j < nHeight-1; ++j)//行数
for (i = 1; i < nWidth-1; ++i)//列数
{
nValue = img->at(j,i);
if ( !nValue )//如果是黑色噪点
{
nCount = 0;
for (m = i-1; m <= i+1; ++m)//i是列数
for (n = j-1; n <= j+1; ++n)//j是行数
{
if( !(img->at(n,m)) )
nCount++;
}
if (nCount <= pNum)//判断3X3范围内一共有几个黑色噪点,最多有9个黑色噪点,噪点数目低于pNum, 该噪点变为白色
img->at(j,i)=WHITE;
}
else
{
nCount = 0;
for (m = i-1; m <= i+1; ++m)
for (n = j-1; n <= j+1; ++n)
{
if( !(img->at(n,m)) )
nCount++;
}
if (nCount >= 7)
img->at(j,i)=BLACK;
}
}
}
然后是去除大的噪点的:
/* 函数名: Flood_filled_ContoursRemoveNoise
* 传入变量:
* img: 图像指针
* pArea: 大块黑色噪点的像素点的多少,如果少于这个数目,就把它们变为白色的背景
* return: void
*/
void Flood_filled_ContoursRemoveNoise(double pArea, Mat * img)
{
int i,j;
int color = 1;
int nHeight = img->rows;
int nWidth = img->cols;
for (i = 0; i < nWidth; ++i)//列数
for (j = 0; j < nHeight; ++j) //行数
{
if ( !img->at(j,i) )
{
//FloodFill each point in connect area using different color
floodFill(*img,cvPoint(i,j),cvScalar(color));
color++;
}
}
int ColorCount[255] = { 0 };
for (i = 0; i < nWidth; ++i) //列数
{
for (j = 0; j < nHeight; ++j) //行数
{
//caculate the area of each area
if (img->at(j,i) != 255)
{
ColorCount[img->at(j,i)]++;
}
}
}
//get rid of noise point
for (i = 0; i < nWidth; ++i) //列数
{
for (j = 0; j < nHeight; ++j) //行数
{
if (ColorCount[img->at(j,i)] <= pArea)
{
img->at(j,i)=WHITE;
}
}
}
for (i = 0; i < nWidth; ++i)//列数
{
for (j = 0; j < nHeight; ++j) //行数
{
if (img->at(j,i) < WHITE)
{
img->at(j,i)=BLACK;
}
}
}
}
#include
#include
#include
#include
using namespace cv;
using namespace std;
#define WHITE 255
#define BLACK 0
int main(void)
{
Mat img=imread("C:\\Users\\fan\\Desktop\\first_image.jpg");
Mat img_gray;
//imshow("img1",img);
/*转化为灰度图*/
cvtColor(img,img_gray,COLOR_BGR2GRAY);
//imshow("img2",img_gray);
/*图像二值化*/
threshold(img_gray,img_gray,225,255,THRESH_BINARY);
imshow("img3",img_gray);
/*去除小的噪点,判断的条件是4个像素点*/
NaiveRemoveNoise(4, &img_gray);
//imshow("the img4",img_gray);
/*去除大的像素点*/
Flood_filled_ContoursRemoveNoise(4.1, &img) ;
imshow("the img4",img_gray);
waitKey();
return 0;
}
这是一个具体的使用了。
要注意:上面的程序实现的效果是:去除白色背景的黑色像素点,如果想要实现去除黑色背景的白色噪点(我是经常这么干的),有两个方法,要么修改下函数里面的东西(将WHITE和BLACK对调),或者我们就直接把两个宏对调。
原本是
#define WHITE 255
#define BLACK 0
那么修改为
#define WHITE 0
#define BLACK 255
就可以有同样的效果啦。(去除黑色背景的白色噪点)