修改了之前滤波中的中值滤波算法,采用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 }
原图:
时间: 2024-12-22 19:50:36