保邊濾波之Mean shift filter

                          Mean shift filter

目錄

                          Mean shift filter

一、算法原理

二、練手實現的算法代碼如下:

三、實現結果




一、算法原理

在OpenCV中,meanshift filter函數爲 pyrMeanShiftFiltering, 它的函數調用格式如下:

C++: void pyrMeanShiftFiltering(InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteriatermcrit=TermCriteria( TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) )

Parameters:

  • src – The source 8-bit, 3-channel image. //三通道的輸入圖像
  • dst – The destination image of the same format and the same size as the source. //相同尺寸格式輸出圖像
  • sp – The spatial window radius.  //空間域半徑
  • sr – The color window radius.  //顏色域半徑
  • maxLevel – Maximum level of the pyramid for the segmentation. //分割用金字塔的最大層數
  • termcrit – Termination criteria: when to stop meanshift iterations. //迭代終止的條件

算法的描述大致如下:

對於輸入圖像的每個像素點(X,Y) ,在它的半徑爲sp的空間域,執行meanshift迭代算法,

像素點(X,Y)的顏色值爲(R,G,B), 它的空間鄰域點(x,y)的顏色值爲(r,g,b),如果點(x,y)的到(X,Y)的顏色距離小於sr,則滿足條件,最終我們求得滿足條件點的平均空間座標(X’,Y’)以及平均顏色向量(R',G',B'),並把它們作爲下一次迭代的輸入。

迭代結果後,我們把最初輸入位置的顏色值用最終迭代的顏色值代替。

 

二、練手實現的算法代碼如下:

#include"cv.h"
#include"highgui.h"
#include"cxcore.h"
#include<stdio.h>
#include<stdlib.h>
#include"types.h"

void ToYIQ(IplImage *img,IplImage *YIQ_img)
{
	int i,j;
	float Y,I,Q;
	uchar R,G,B;

	for(i = 0 ;i < img->height;i++)
	{
		for(j = 0; j < img->width;j++)
		{
			B = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+0];
			G = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+1];
			R = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+2];


			Y = 0.299*R +0.587*G +0.114*B;
			I = 0.5957*R-0.2744*G-0.3212*B;
			Q = 0.2114*R-0.5226*G+0.3111*B;

			((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+0] = Y;
			((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+1] = I;
			((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+2] = Q;

		}
	}
}


void Mean_Shift_Filter(IplImage *img, IplImage *YIQ_img, IplImage *mean_shift_img,int rad,int colordis )
{
	float shift,Yc,Ic,Qc,YcOld,IcOld,QcOld,Y2,I2,Q2,dY,dI,dQ,mY,mI,mQ,num_;
	int i,j,ry,rx,y2,x2,xc,yc,xcOld,ycOld,num,dx,dy,iters,mx,my;
	uchar R,G,B;

	shift  = 0;
	iters  = 0;
	for(i = 0; i < img->height;i++)
	{
		for(j = 0; j < img->width;j++)
		{
			yc = i;
			xc = j;

			Yc = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+0];
			Ic = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+1];
			Qc = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+2];

			iters = 0;
			do{
				ycOld = yc;
				xcOld = xc;
				YcOld = Yc;
				IcOld = Ic;
				QcOld = Qc;

				mx = 0;
				my = 0;
				mY = 0;
				mI = 0;
				mQ = 0;
				num = 0;
/*///
假若是rad= 3,則其鄰域範圍爲:其中#爲包含在內需要計算的像素點
				***#***
				**###**
				*#####*
				#######
				*#####*
				**###**
				***#***
///*/
				for(ry = - rad;ry <= rad;ry++)
				{
					y2 = yc+ry;
					if(y2 >= 0 && y2 < img->height)
					{
						for(rx = -rad;rx <= rad;rx++)
						{
							x2 = xc+rx;
							if(x2 >= 0 && x2 < img->width)
							{
								if(ry*ry+rx*rx <= rad*rad)
								{
									Y2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+0];
									I2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+1];
									Q2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+2];

									dY = Yc-Y2;
									dI = Ic- I2;
									dQ = Qc- Q2;

									if(dY*dY + dI*dI+dQ*dQ <= colordis)//當前像素比周圍鄰域像素相差比較大的時候,在rad半徑內(一個菱形領域),只有當前像素滿足此條件,所以最後替換當前像素還是自己本身
									{
										mx += x2;
										my += y2;
										mY += Y2;
										mI += I2;
										mQ += Q2;
										num++;
									}

								}
							}
						}

					}
				}
			num_ = 1.0/num;
			Yc = mY*num_;
			Ic = mI*num_;
			Qc = mQ*num_;
			xc = (int)(mx*num_+0.5);
			yc = (int)(my*num_+0.5);
			
			dx = xc - xcOld;
			dy = yc -ycOld;
			dY = Yc - YcOld;
			dI = Ic- IcOld;
			dQ = Qc - QcOld;

			shift = dx*dx+dy*dy+dY*dY+dI*dI+dQ*dQ;
			iters++;
			}
			while(shift> 3 && iters < 100);

			R = CLIP((int)(Yc+0.9653*Ic+0.6210*Qc),0,255);
			G = CLIP((int)(Yc-0.2721*Ic-0.6473*Qc),0,255);
			B = CLIP((int)(Yc-1.1070*Ic+1.7046*Qc),0,255);

			((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+0] = B;
			((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+1] = G;
			((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+2] = R;	
		}
	}

}
int main(void)
{
	int w,h;
	CvSize img_size;
	IplImage *src,*mean_shift_img,*YIQ_img;

	src = cvLoadImage("lg-image4.bmp",-1);
	if(src == NULL)
	{
		printf("Please insert image\n");
		return 0;
	}
	img_size = cvGetSize(src);
	w = img_size.width;
	h = img_size.height;


	YIQ_img = cvCreateImage(img_size,IPL_DEPTH_32F,3);
	mean_shift_img = cvCreateImage(img_size,IPL_DEPTH_8U,3);

	if((mean_shift_img == NULL) || (YIQ_img==NULL))
		printf("malloc for image memory failure!\n");


	cvZero(YIQ_img);
	cvZero(mean_shift_img);


	cvNamedWindow("Show original image",0);
	cvShowImage("Show original image",src);
	
	ToYIQ(src,YIQ_img);
	Mean_Shift_Filter(src, YIQ_img, mean_shift_img,5,15*15 );
	cvNamedWindow("Mean Shift image",0);
	cvShowImage("Mean Shift image",mean_shift_img);
	cvSaveImage("lg-image4_Mean_Shift_filter.bmp",mean_shift_img);

	cvWaitKey(0);
	cvDestroyWindow("Mean Shift image");
	cvDestroyWindow("Show original image");
	printf("done\n");
	cvReleaseImage(&YIQ_img);
	cvReleaseImage(&mean_shift_img);

	return 0;
}

三、實現結果

左側爲原始圖像;右側爲結果圖像
標題左側爲原始圖像;右側爲結果圖像

 

但是針對椒鹽噪聲,其效果基本無效:

左側爲原始圖像;右側爲添加椒鹽噪聲圖像

 

左側爲原始圖像mean_shift filter之後結果;右側爲添加椒鹽噪聲圖像mean_shift_filter處理結果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章