影象分割--分水嶺分割法
阿新 • • 發佈:2019-01-10
#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); } }