1. 程式人生 > >影象分割--分水嶺分割法

影象分割--分水嶺分割法

#include <iostream>  
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\opencv.hpp>
  
using namespace std;    
using namespace cv;

IplImage* marker_mask = 0;  
IplImage* markers = 0;  
IplImage* img0 = 0, *img = 0, *img_gray = 0, *wshed = 0;  
CvPoint prev_pt = {-1,-1};  

void on_mouse( int event, int x, int y, int flags, void* param );//opencv 會自動給函式傳入合適的值  
static void ShowHelpText() ;

int main(int argc, char** argv)
{
	CvMemStorage* storage=cvCreateMemStorage(0);
	CvRNG rng=cvRNG(-1);   //初始化隨機數生成器並返回其狀態
	ShowHelpText();
	if (argc==2 && (img0=cvLoadImage(argv[1],-1))!=0)
	{
		return -1;
	}
	else
	{
		img0=cvLoadImage("0.jpg",1);
	}
	cvNamedWindow("image",1);
	cvNamedWindow("watershed transform",1);
	img=cvCloneImage(img0);
	img_gray=cvCloneImage(img0);
	wshed=cvCloneImage(img0);
	marker_mask=cvCreateImage(cvGetSize(img),8,1);
	markers=cvCreateImage(cvGetSize(img),IPL_DEPTH_32S,1);
	cvCvtColor(img,marker_mask,CV_BGR2GRAY);//彩色空間轉換
	cvCvtColor(marker_mask,img_gray,CV_GRAY2BGR);
	cvZero(marker_mask);
	cvZero(wshed);
	cvShowImage("image",img);
	cvShowImage("watershed transform",wshed);
	cvSetMouseCallback("image",on_mouse,0);
	for (;; )
	{
		int c=waitKey(0);
		if ((char)c==27)
		{
			break;
		}
		if ((char)c=='r')
		{
			cvZero(marker_mask);
			cvCopy(img0,img);
			cvShowImage("image",img);
		}
		if ((char)c=='w' || (char)c==' ')
		{
			CvSeq* contours=0;
			CvMat* color_tab=0;
			int i ,j ,comp_count=0;

			//下面選將標記的影象取得其輪廓, 將每種輪廓用不同的整數表示  
			//不同的整數使用分水嶺演算法時,就成為不同的種子點  
			//演算法本來就是以各個不同的種子點為中心擴張  
			cvClearMemStorage(storage);  
			cvFindContours( marker_mask, storage, &contours, sizeof(CvContour),  CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );  
			cvZero( markers );  
			for( ; contours != 0; contours = contours->h_next, comp_count++ )  
			{  
				cvDrawContours(markers, contours, cvScalarAll(comp_count+1),  
					cvScalarAll(comp_count+1), -1, -1, 8, cvPoint(0,0) );  
			}  
			//cvShowImage("image",markers);  
			if( comp_count == 0 )  
				continue;  
			color_tab = cvCreateMat( 1, comp_count, CV_8UC3 );//建立隨機顏色列表  
			//不同的整數標記
			for( i = 0; i < comp_count; i++ )  
			{  
				uchar* ptr = color_tab->data.ptr + i*3;  
				ptr[0] = (uchar)(cvRandInt(&rng)%180 + 50);  
				ptr[1] = (uchar)(cvRandInt(&rng)%180 + 50);  
				ptr[2] = (uchar)(cvRandInt(&rng)%180 + 50);  
			}  
			{  
				double t = (double)cvGetTickCount();  
				cvWatershed( img0, markers );  
				cvSave("img0.xml",markers);  
				t = (double)cvGetTickCount() - t;  
				printf( "exec time = %gms\n", t/(cvGetTickFrequency()*1000.) );  
			}  
			// paint the watershed image  
			for( i = 0; i < markers->height; i++ )  
				for( j = 0; j < markers->width; j++ )  
				{  
					int idx = CV_IMAGE_ELEM( markers, int, i, j );//markers的資料型別為IPL_DEPTH_32S  
					uchar* dst = &CV_IMAGE_ELEM( wshed, uchar, i, j*3 );//BGR三個通道的數是一起的,故要j*3  
					if( idx == -1 ) //輸出時若為-1,表示各個部分的邊界  
						dst[0] = dst[1] = dst[2] = (uchar)255;  
					else if( idx <= 0 || idx > comp_count )  //異常情況  
						dst[0] = dst[1] = dst[2] = (uchar)0; // should not get here  
					else //正常情況  
					{  
						uchar* ptr = color_tab->data.ptr + (idx-1)*3;  
						dst[0] = ptr[0]; dst[1] = ptr[1]; dst[2] = ptr[2];  
					}  
				}  
				cvAddWeighted( wshed, 0.5, img_gray, 0.5, 0, wshed );//wshed.x.y=0.5*wshed.x.y+0.5*img_gray+0加權融合影象  
				cvShowImage( "watershed transform", wshed );  
				cvReleaseMat( &color_tab );  
		}  
	}  
	return 1;  
}

static void ShowHelpText()    
{    
    //輸出一些幫助資訊    
	cout<<endl<<"影象分割--分水嶺分割示例程式~"<<endl<<endl;
	cout<<"當前使用的OpenCV版本為 OpenCV "<<CV_VERSION<<endl;
	cout<<"按 'ESC' 退出程式! "<<endl<<endl;
	cout<<"按 'r' 重新顯示原影象! "<<endl<<endl;
	cout<<"按 'w' 或者 ' ' 運算該演算法! "<<endl<<endl;
	cout<<endl<<"鍵盤按鍵任意鍵- 退出程式"<<endl;
} 

void on_mouse( int event, int x, int y, int flags, void* param )//opencv 會自動給函式傳入合適的值  
{  
    if( !img )  
        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( marker_mask, prev_pt, pt, cvScalarAll(255), 5, 8, 0 );//CvScalar 成員:double val[4] RGBA值A=alpha  
        cvLine( img, prev_pt, pt, cvScalarAll(255), 5, 8, 0 );  
        prev_pt = pt;  
        cvShowImage( "image", img);  
    }  
}