1. 程式人生 > >opencv之分水嶺實現影象分割

opencv之分水嶺實現影象分割

本文需要了解的庫函式有:

void cvWatershed( const CvArr* image, CvArr* markers );//分水嶺演算法分割影象
void  cvAddWeighted( const CvArr* src1, double alpha,
                     const CvArr* src2, double beta,
                     double gamma, CvArr* dst );//計算兩個陣列的加權值的和

程式碼演示:
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cxcore.lib")
#include<cv.h>
#include<highgui.h>
#include<stdio.h>
#include<math.h>

IplImage	*image=NULL;
IplImage	*gray=NULL;//灰度影象
IplImage	*img0=NULL;
IplImage	*mask=NULL;
IplImage	*maskers=NULL;//標記輪廓線的影象
IplImage	*wated=NULL;//分水嶺分割後的影象
CvPoint prev_pt;


void on_mouse( int event, int x, int y, int flags, void* param )
{
    if( !image )
        return;

    if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
        prev_pt = cvPoint(-1,-1);
    else if( event == CV_EVENT_LBUTTONDOWN )
        prev_pt = cvPoint(x,y);
    else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) )
    {
        CvPoint pt = cvPoint(x,y);
        if( prev_pt.x < 0 )
            prev_pt = pt;
        cvLine( mask, prev_pt, pt, cvScalarAll(255), 5, 8, 0 );
        cvLine( image, prev_pt, pt, cvScalarAll(255), 5, 8, 0 );
        prev_pt = pt;
        cvShowImage( "image", image );
    }
}

int main()
{
	CvRNG rng = cvRNG(-1);
	image = cvLoadImage("fruits.jpg",1);	//載入影象

	img0 = cvCloneImage(image);	//拷貝影象
	mask = cvCreateImage(cvGetSize(image),8,1);//掩碼影象
	maskers = cvCreateImage(cvGetSize(image),IPL_DEPTH_32S,1);//標記輪廓線的影象
	wated  = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3);//分水嶺分割後的影象
 	gray = cvCreateImage(cvGetSize(image),8,3);//彩色灰度影象
	//生成灰度彩色影象
	cvCvtColor(image,mask,CV_BGR2GRAY);
	cvCvtColor(mask,gray,CV_GRAY2BGR);


	cvZero(mask);//清空
	cvNamedWindow("image",1);
    cvShowImage( "image", image );
	cvNamedWindow("分水嶺分割",1);
    cvSetMouseCallback( "image", on_mouse, 0 );
	CvMemStorage* storage = cvCreateMemStorage(0);	

	for(;;)
	{
		char c =cvWaitKey(0);
		if(c=='\r')
		{
			cvClearMemStorage(storage);//清空
			//查詢輪廓
			 CvSeq* seq =NULL;
            cvFindContours( mask, storage, &seq, sizeof(CvContour),
                            CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );		
			 
			cvZero(maskers);//清空
			int count = 0;//計數器

			for(;seq!=NULL;seq=seq->h_next,count++)
			{
				cvDrawContours(maskers,seq,cvScalarAll(count+1),cvScalarAll(count+1),-1,-1,8,cvPoint(0,0));//繪製到標記影象上
			}

			//產生隨機顏色
            CvMat* color_tab = cvCreateMat( 1, count, CV_8UC3 );
            for(int j = 0; j < count; j++ )
            {
                uchar* ptr = color_tab->data.ptr + j*3;
                ptr[0] = (uchar)(cvRandInt(&rng)%180 + 50);
                ptr[1] = (uchar)(cvRandInt(&rng)%180 + 50);
                ptr[2] = (uchar)(cvRandInt(&rng)%180 + 50);
            }
			
			//運動分水嶺分割演算法
			cvWatershed(img0,maskers);
			//顯示演算法後的分割影象
		   for(int  i = 0; i < maskers->height; i++ )
			   for(int  j = 0; j < maskers->width; j++ )
				 {
					int idx = CV_IMAGE_ELEM( maskers, int, i, j );
					uchar* dst = &CV_IMAGE_ELEM( wated, uchar, i, j*3 );
					if( idx == -1 )
						dst[0] = dst[1] = dst[2] = (uchar)255;
					else if( idx <= 0 || idx > count )
						 dst[0] = dst[1] = dst[2] = (uchar)0; // should not get here
					else
					{
					//	dst[0] = 255; dst[1] = 0; dst[2] =0; //填充顏色
                        uchar* ptr = color_tab->data.ptr + (idx-1)*3;
                        dst[0] = ptr[0]; dst[1] = ptr[1]; dst[2] = ptr[2];
					}
			   }
			cvAddWeighted(gray,0.5,wated,0.5,0,wated);
			cvShowImage( "分水嶺分割", wated );
            cvReleaseMat( &color_tab );
		}
	}


 
	cvDestroyWindow("image");
	cvDestroyWindow("分水嶺分割");
	cvReleaseMemStorage(&storage);
	cvReleaseImage(&image);	
	cvReleaseImage(&img0);	
	cvReleaseImage(&mask);
	cvReleaseImage(&gray);
	cvReleaseImage(&maskers);
	cvReleaseImage(&wated);
	return 0;
}