5.5用分水嶺演算法實現影象分割
阿新 • • 發佈:2019-02-02
<img src="https://img-blog.csdn.net/20160409220852681?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />直接上程式碼吧,還不是太理解
//watershedSegmentation.h #if !defined WATERSHS #define WATERSHS #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> class WatershedSegmenter {<img src="https://img-blog.csdn.net/20160409220658944?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /><img src="https://img-blog.csdn.net/20160409220658944?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> private: cv::Mat markers; public: void setMarkers(const cv::Mat& markerImage) { // Convert to image of ints markerImage.convertTo(markers,CV_32S); } cv::Mat process(const cv::Mat &image) { // Apply watershed cv::watershed(image,markers); return markers; } // Return result in the form of an image cv::Mat getSegmentation() { cv::Mat tmp; // all segment with label higher than 255 // will be assigned value 255 markers.convertTo(tmp,CV_8U); return tmp; } // Return watershed in the form of an image cv::Mat getWatersheds() { cv::Mat tmp; markers.convertTo(tmp,CV_8U,255,255); return tmp; } }; #endif//
//main
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include "watershedSegmentation.h" int main() { #if 1 // Read input image cv::Mat image= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\group.jpg"); if (!image.data) return 0; // Display the image cv::namedWindow("Original Image"); cv::imshow("Original Image",image); // Get the binary map cv::Mat binary; binary= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\binary.bmp",0); // Display the binary image cv::namedWindow("Binary Image"); cv::imshow("Binary Image",binary); // Eliminate noise and smaller objects cv::Mat fg; cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6); // Display the foreground image cv::namedWindow("Foreground Image"); cv::imshow("Foreground Image",fg); cv::imwrite("ForegroundImage.jpg",fg); // Identify image pixels without objects cv::Mat bg; cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6); cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV); // Display the background image cv::namedWindow("Background Image"); cv::imshow("Background Image",bg); //cv::imwrite("BackgroundImage.jpg",bg); // Show markers image cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0)); markers= fg+bg; cv::namedWindow("Markers"); cv::imshow("Markers",markers); //cv::imwrite("Markers.jpg",markers); // Create watershed segmentation object WatershedSegmenter segmenter; // Set markers and process segmenter.setMarkers(markers); segmenter.process(image); // imshow("11",markers); // Display segmentation result cv::namedWindow("Segmentation"); cv::imshow("Segmentation",segmenter.getSegmentation()); //cv::imwrite("Segmentation.jpg",segmenter.getSegmentation()); // Display watersheds cv::namedWindow("Watersheds"); cv::imshow("Watersheds",segmenter.getWatersheds()); // cv::imwrite("Watersheds.jpg",segmenter.getWatersheds()); #endif #if 1 // Open another image image= cv::imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\tower.jpg"); // Identify background pixels cv::Mat imageMask(image.size(),CV_8U,cv::Scalar(0)); cv::rectangle(imageMask,cv::Point(5,5),cv::Point(image.cols-5,image.rows-5),cv::Scalar(255),3); // Identify foreground pixels (in the middle of the image) cv::rectangle(imageMask,cv::Point(image.cols/2-10,image.rows/2-10), cv::Point(image.cols/2+10,image.rows/2+10),cv::Scalar(1),10); // Set markers and process segmenter.setMarkers(imageMask); // imshow("mask+rectangle",imageMask); segmenter.process(image); //imshow("seg_prosswater",segmenter.process(image)); // Display the image with markers cv::rectangle(image,cv::Point(5,5),cv::Point(image.cols-5,image.rows-5),cv::Scalar(255,255,255),3); cv::rectangle(image,cv::Point(image.cols/2-10,image.rows/2-10), cv::Point(image.cols/2+10,image.rows/2+10),cv::Scalar(1,1,1),10); cv::namedWindow("Image with marker"); cv::imshow("Image with marker",image); //cv::imwrite("Image with marker.jpg",image); // Display watersheds cv::namedWindow("Watersheds of foreground object"); cv::imshow("Watersheds of foreground object",segmenter.getWatersheds()); //cv::imwrite("Watersheds of foreground object.jpg",segmenter.getWatersheds()); #endif cv::waitKey(); return 0; } <pre code_snippet_id="1640334" snippet_file_name="blog_20160409_7_2417268" name="code" class="cpp"></pre><pre code_snippet_id="1640334" snippet_file_name="blog_20160409_8_847105" name="code" class="cpp">不是太理解,標記影象第一副影象是前景和背景,但是後面一副影象直接是2個矩形。。反正經過處理之後影象的邊緣畫素值為-1
下面是opencv3的程式碼 來自毛星雲
//--------------------------------------【程式說明】------------------------------------------- // 程式說明:《OpenCV3程式設計入門》OpenCV2版書本配套示例程式77 // 程式描述:分水嶺演算法綜合示例 // 開發測試所用作業系統: Windows 7 64bit // 開發測試所用IDE版本:Visual Studio 2010 // 開發測試所用OpenCV版本: 2.4.9 // 2014年06月 Created by @淺墨_毛星雲 // 2014年11月 Revised by @淺墨_毛星雲 //------------------------------------------------------------------------------------------------ //---------------------------------【標頭檔案、名稱空間包含部分】---------------------------- // 描述:包含程式所使用的標頭檔案和名稱空間 //------------------------------------------------------------------------------------------------ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; using namespace std; //-----------------------------------【巨集定義部分】-------------------------------------------- // 描述:定義一些輔助巨集 //------------------------------------------------------------------------------------------------ #define WINDOW_NAME1 "【程式視窗1】" //為視窗標題定義的巨集 #define WINDOW_NAME2 "【分水嶺演算法效果圖】" //為視窗標題定義的巨集 //-----------------------------------【全域性函變數宣告部分】-------------------------------------- // 描述:全域性變數的宣告 //----------------------------------------------------------------------------------------------- Mat g_maskImage, g_srcImage; Point prevPt(-1, -1); //-----------------------------------【全域性函式宣告部分】-------------------------------------- // 描述:全域性函式的宣告 //----------------------------------------------------------------------------------------------- static void ShowHelpText(); static void on_Mouse( int event, int x, int y, int flags, void* ); //-----------------------------------【main( )函式】-------------------------------------------- // 描述:控制檯應用程式的入口函式,我們的程式從這裡開始執行 //----------------------------------------------------------------------------------------------- int main( int argc, char** argv ) { //【0】改變console字型顏色 system("color 6F"); //【0】顯示幫助文字 ShowHelpText( ); //【1】載入原圖並顯示,初始化掩膜和灰度圖 g_srcImage = imread("1.jpg", 1); imshow( WINDOW_NAME1, g_srcImage ); Mat srcImage,grayImage; g_srcImage.copyTo(srcImage); cvtColor(g_srcImage, g_maskImage, COLOR_BGR2GRAY); cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR); g_maskImage = Scalar::all(0); //【2】設定滑鼠回撥函式 setMouseCallback( WINDOW_NAME1, on_Mouse, 0 ); //【3】輪詢按鍵,進行處理 while(1) { //獲取鍵值 int c = waitKey(0); //若按鍵鍵值為ESC時,退出 if( (char)c == 27 ) break; //按鍵鍵值為2時,恢復源圖 if( (char)c == '2' ) { g_maskImage = Scalar::all(0); srcImage.copyTo(g_srcImage); imshow( "image", g_srcImage ); } //若檢測到按鍵值為1或者空格,則進行處理 if( (char)c == '1' || (char)c == ' ' ) { //定義一些引數 int i, j, compCount = 0; vector<vector<Point> > contours; vector<Vec4i> hierarchy; //尋找輪廓 findContours(g_maskImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); //輪廓為空時的處理 if( contours.empty() ) continue; //拷貝掩膜 Mat maskImage(g_maskImage.size(), CV_32S); maskImage = Scalar::all(0); //迴圈繪製出輪廓 //感覺這裡繪製輪廓不重要,重要的是幾個 因為後面又覆蓋了maskImage watershed( srcImage, maskImage ); for( int index = 0; index >= 0; index = hierarchy[index][0], compCount++ ) drawContours(maskImage, contours, index, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX); //compCount為零時的處理 if( compCount == 0 ) continue; //生成隨機顏色 vector<Vec3b> colorTab; for( i = 0; i < compCount; i++ ) { int b = theRNG().uniform(0, 255); int g = theRNG().uniform(0, 255); int r = theRNG().uniform(0, 255); colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r)); } //計算處理時間並輸出到視窗中 double dTime = (double)getTickCount(); watershed( srcImage, maskImage ); dTime = (double)getTickCount() - dTime; printf( "\t處理時間 = %gms\n", dTime*1000./getTickFrequency() ); //雙層迴圈,將分水嶺影象遍歷存入watershedImage中 Mat watershedImage(maskImage.size(), CV_8UC3); for( i = 0; i < maskImage.rows; i++ ) for( j = 0; j < maskImage.cols; j++ ) { int index = maskImage.at<int>(i,j); //不同的index用不同的index顏色 if( index == -1 ) watershedImage.at<Vec3b>(i,j) = Vec3b(255,255,255); else if( index <= 0 || index > compCount ) watershedImage.at<Vec3b>(i,j) = Vec3b(0,0,0); else watershedImage.at<Vec3b>(i,j) = colorTab[index - 1]; } //混合灰度圖和分水嶺效果圖並顯示最終的視窗 watershedImage = watershedImage*0.5 + grayImage*0.5; imshow( WINDOW_NAME2, watershedImage ); } } return 0; } //-----------------------------------【onMouse( )函式】--------------------------------------- // 描述:滑鼠訊息回撥函式 //----------------------------------------------------------------------------------------------- static void on_Mouse( int event, int x, int y, int flags, void* ) { //處理滑鼠不在視窗中的情況 if( x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows ) return; //處理滑鼠左鍵相關訊息 if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) ) prevPt = Point(-1,-1); else if( event == CV_EVENT_LBUTTONDOWN ) prevPt = Point(x,y); //滑鼠左鍵按下並移動,繪製出白色線條 else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) ) { Point pt(x, y); if( prevPt.x < 0 ) prevPt = pt; line( g_maskImage, prevPt, pt, Scalar::all(255), 5, 8, 0 ); line( g_srcImage, prevPt, pt, Scalar::all(0), 5, 8, 0 ); prevPt = pt; imshow(WINDOW_NAME1, g_srcImage); } } //-----------------------------------【ShowHelpText( )函式】---------------------------------- // 描述:輸出一些幫助資訊 //---------------------------------------------------------------------------------------------- static void ShowHelpText() { //輸出歡迎資訊和OpenCV版本 printf("\n\n\t\t\t非常感謝購買《OpenCV3程式設計入門》一書!\n"); printf("\n\n\t\t\t此為本書OpenCV2版的第77個配套示例程式\n"); printf("\n\n\t\t\t 當前使用的OpenCV版本為:" CV_VERSION ); printf("\n\n ----------------------------------------------------------------------------\n"); //輸出一些幫助資訊 printf( "\n\n\n\t歡迎來到【分水嶺演算法】示例程式~\n\n"); printf( "\t請先用滑鼠在圖片視窗中標記出大致的區域,\n\n\t然後再按鍵【1】或者【SPACE】啟動演算法。" "\n\n\t按鍵操作說明: \n\n" "\t\t鍵盤按鍵【1】或者【SPACE】- 執行的分水嶺分割演算法\n" "\t\t鍵盤按鍵【2】- 恢復原始圖片\n" "\t\t鍵盤按鍵【ESC】- 退出程式\n\n\n"); }