修改了之前滤波中的中值滤波算法,采用copyMakeBorder处理边界像素
void MedianBlur(const Mat &image_Src, Mat &image_Dst, int width_Aperture)
{
/////////////////////////////重新分配图像(如果需要)/////////////////////////////////////////////
int width_Dst=image_Src.cols;
int height_Dst=image_Src.rows;
image_Dst.create(Size(width_Dst,height_Dst),CV_8UC1);//如果重新分配,之前的空间会扔掉
image_Dst.setTo(Scalar(0));//置为0
//滑动窗口
int pixelCount=width_Aperture*width_Aperture;//窗口内像素总个数
Mat image_Aperture(width_Aperture,width_Aperture,CV_8UC1);//滑动窗口图像
//直方图
Mat histogram;
int histogramSize=256;//灰度等级
int thresholdValue=pixelCount/2+1;//step1.设置阈值(步骤参考:图像的高效编程要点之四)
//计算起点坐标
int startX=width_Aperture/2;
int startY=width_Aperture/2;
///////////////////////////////扩充图像边界///////////////////////////////////////////
int height_Extend=startY;
int width_Extend=startX;
Mat image_New;
copyMakeBorder(image_Src,image_New,height_Extend,height_Extend,width_Extend,width_Extend,BORDER_DEFAULT);//默认采用BORDER_REFLECT
int height_New=image_New.rows;
int width_New=image_New.cols;
//第一行
//这里需要设置3个指针,一起滑动
//1.源图像中被处理的像素
//2.目标图像被处理的像素
//3.源图像滑动窗口
uchar *row_New=image_New.data+startY*width_New+startX;//新图像
uchar *row_Dst=image_Dst.data;//目标图像
uchar *row_Aperture_New=image_New.data;//源图像中的滑动窗口
for (int y=startY;y<=height_New-startY-1;++y)
{
//列
uchar *col_New=row_New;
uchar *col_Dst=row_Dst;
uchar *col_Aperture_New=row_Aperture_New;//操作整个滑动窗口
///////////////////////////////对滑动窗口操作///////////////////////////////////////////
//计算每行第一个滑动窗口直方图
//提取滑动窗口图像
uchar *row_Aperture=image_Aperture.data;//滑动窗口图像
uchar *row_Aperture_New_2=col_Aperture_New;
for (int k=0;k<=width_Aperture-1;++k)
{
//列
uchar *col_ApertureImage=row_Aperture;
uchar *col_Aperture_New_2=row_Aperture_New_2;
for (int w=0;w<=width_Aperture-1;++w)
{
//处理每个像素
col_ApertureImage[0]=col_Aperture_New_2[0];
//下一个像素
col_ApertureImage++;
col_Aperture_New_2++;
}
//下一行
row_Aperture+=width_Aperture;
row_Aperture_New_2+=width_New;
}
//step 2.确定中值,并记录亮度<=中值的像素点个数
//求直方图
calcHist(&image_Aperture,
1,//Mat的个数
0,//用来计算直方图的通道索引,通道索引依次排开
Mat(),//Mat()返回一个空值,表示不用mask,
histogram, //直方图
1, //直方图的维数,如果计算2个直方图,就为2
&histogramSize, //直方图的等级数(如灰度等级),也就是每列的行数
0//分量的变化范围
);
//求亮度中值和<=中值的像素点个数
int medianValue,pixleCountLowerMedian;
CalculateImage_MedianGray_PixelCount(histogram,pixelCount,medianValue,pixleCountLowerMedian);
//////////////////////////////滑动窗口操作结束////////////////////////////////////////////
//滤波
col_Dst[0]=(uchar)medianValue;
//滑动一个像素(三个指针在一起移动)
col_Dst++;
col_New++;
col_Aperture_New++;
for (int x=startX+1;x<=width_New-startX-1;++x)//从每行第二个滤波像素开始
{
//////////////////////////////////维持滑动窗口直方图////////////////////////////////////////
//step 3.去掉左侧
uchar *col_Left=col_Aperture_New-1;
float *data=(float*)histogram.data;
for (int k=0;k<=width_Aperture-1;++k)
{
int gray=col_Left[0];
data[gray]-=1.0;
if (gray<=medianValue)
{
pixleCountLowerMedian--;
}
col_Left+=width_New;
}
//step 4.增加右侧
uchar *col_Right=col_Aperture_New+width_Aperture-1;
for (int k=0;k<=width_Aperture-1;++k)
{
int gray=col_Right[0];
data[gray]+=1.0;
if (gray<=medianValue)
{
pixleCountLowerMedian++;
}
col_Right+=width_New;
}
//搜索新的中值
if (pixleCountLowerMedian>thresholdValue)//step 6.
{
while(1)
{
pixleCountLowerMedian-=data[medianValue];
medianValue--;
if (pixleCountLowerMedian<=thresholdValue)
{
break;
}
}
}
else
{
while(pixleCountLowerMedian<thresholdValue)//step 5
{
medianValue++;
pixleCountLowerMedian+=data[medianValue];
}
}
//滤波
col_Dst[0]=(uchar)medianValue;
//滑动一个像素
col_New++;
col_Dst++;
col_Aperture_New++;
}//end of x
//下一行
row_New+=width_New;
row_Dst+=width_Dst;
row_Aperture_New+=width_New;
}//end of y
}原图:
高效中值滤波(采用copyMakeBorder处理边界像素)
原文地址:http://blog.csdn.net/qianqing13579/article/details/42324771