• <em id="6vhwh"><rt id="6vhwh"></rt></em>

    <style id="6vhwh"></style>

    <style id="6vhwh"></style>
    1. <style id="6vhwh"></style>
        <sub id="6vhwh"><p id="6vhwh"></p></sub>
        <p id="6vhwh"></p>
          1. 国产亚洲欧洲av综合一区二区三区 ,色爱综合另类图片av,亚洲av免费成人在线,久久热在线视频精品视频,成在人线av无码免费,国产精品一区二区久久毛片,亚洲精品成人片在线观看精品字幕 ,久久亚洲精品成人av秋霞

            分水嶺算法(分水嶺算法分割圖像)

            更新時間:2023-03-01 12:57:05 閱讀: 評論:0

            使用C++、opencv進行分水嶺分割圖像

            分水嶺概念是以對圖像進行三維可視化處理為基礎的:其中兩個是坐標,另一個是灰度級。基于“地形學”的這種解釋,我們考慮三類點:

            a.屬于局部性最小值的點,也可能存在一個最小值面,該平面內的都是最小值點

            b.當一滴水放在某點的位置上的時候,水一定會下落到一個單一的最小值點

            c.當水處在某個點的位置上時,水會等概率地流向不止一個這樣的最小值點

            對一個特定的區域最小值,滿足條件(b)的點的集合稱為這個最小值的“匯水盆地”或“分水嶺”。滿足條件(c)的點的集合組成地形表面的峰線,稱做“分割線”或“分水線”。

            分水嶺分割方法,是一種基于拓撲理論的數學形態學的分割方法,目前較著名且使用較多的有2種算法:

            (1) 自下而上的模擬泛洪的算法 (2) 自上而下的模擬降水的算法

            這里介紹泛洪算法的過程。

            算法主要思想:

            我們把圖像看作是測地學上的拓撲地貌,圖像中每一點像素的灰度值表示該點的海拔高度,模擬泛洪算法的基本思想是:假設在每個區域最小值的位置上打一個洞并且讓水以均勻的上升速率從洞中涌出,從低到高淹沒整個地形。當處在不同的匯聚盆地中的水將要聚合在一起時,修建的大壩將阻止聚合。水將達到在水線上只能見到各個水壩的頂部這樣一個程度。這些大壩的邊界對應于分水嶺的分割線。所以,它們是由分水嶺算法提取出來的(連續的)邊界線。

            原圖像: 地形俯視圖:

            ?

            原圖像顯示了一個簡單的灰度級圖像,其中“山峰”的高度與輸入圖像的灰度級值成比例。為了阻止上升的水從這些結構的邊緣溢出,我們想像將整幅地形圖的周圍用比最高山峰還高的大壩包圍起來。最高山峰的值是由輸入圖像灰度級具有的最大值決定的。

            ?

            ?

            ?

            圖一被水淹沒的第一個階段,這里水用淺灰色表示,覆蓋了對應于圖中深色背景的區域。在圖二和三中,我們看到水分別在第一和第二匯水盆地中上升。由于水持續上升,最終水將從一個匯水盆地中溢出到另一個之中。

            ?

            ?

            左圖中顯示了溢出的第一個征兆。這里,水確實從左邊的盆地溢出到右邊的盆地,并且兩者之間有一個短“壩”(由單像素構成)阻止這一水位的水聚合在一起。隨著水位不斷上升,如右圖所顯示的那樣。這幅圖中在兩個匯水盆地之間顯示了一條更長的壩,另一條水壩在右上角。這條水壩阻止了盆地中的水和對應于背景的水的聚合。

            這個過程不斷延續直到到達水位的最大值(對應于圖像中灰度級的最大值)。水壩最后剩下的部分對應于分水線,這條線就是要得到的分割結果。

            ?

            對于這個例子,分水線在圖中顯示為疊加到原圖上的一個像素寬的深色路徑。注意一條重要的性質就是分水線組成一條連通的路徑,由此給出了區域之間的連續的邊界。

            動圖演示了整個分水嶺算法的過程:

            ?

            算法實現:

            ?

            ?

            算法應用:

            分水嶺算法對噪聲等影響非常敏感。所以在真實圖像中,由于噪聲點或者其它干擾因素的存在,使用分水嶺算法常常存在過度分割的現象,這是因為很多很小的局部極值點的存在,比如下面的圖像,這樣的分割效果是毫無用處的。

            ?

            ?

            為了解決過度分割的問題,可以使用基于標記(mark)圖像的分水嶺算法,就是通過先驗知識,來指導分水嶺算法,以便獲得更好的圖像分段效果。通常的mark圖像,都是在某個區域定義了一些灰度層級,在這個區域的洪水淹沒過程中,水平面都是從定義的高度開始的,這樣可以避免一些很小的噪聲極值區域的分割。下面的動圖很好的演示了基于mark的分水嶺算法過程:

            ?

            上面的過度分割圖像,我們通過指定mark區域,可以得到很好的分段效果:

            ?

            ?

            以上參考:岡薩雷斯《數字圖象處理(第三版)》和https://www.cnblogs.com/mikewolf2002/p/3304118.html

            相關API:

            void tMoucallback(const string& winname, MouCallback onMou, void* urdata=0)

            winname:窗口的名字onMou:鼠標響應函數,回調函數。指定窗口里每次鼠標時間發生的時候,被調用的函數指針。 這個函數的原型應該為void on_Mou(int event, int x, int y, int flags, void* param);urdate:傳給回調函數的參數

            void on_Mou(int event, int x, int y, int flags, void* param)

            event: CV_EVENT_*變量之一x和y:鼠標指針在圖像坐標系的坐標(不是窗口坐標系) flags:CV_EVENT_FLAG的組合, param是用戶定義的傳遞到tMouCallback函數調用的參數。

            附常用的event:CV_EVENT_MOUSEMOVE、CV_EVENT_LBUTTONDOWN 、CV_EVENT_RBUTTONDOWN、 CV_EVENT_LBUTTONUP 、 CV_EVENT_RBUTTONUP

            和標志位flags有關的:CV_EVENT_FLAG_LBUTTON

            C++: void watershed(InputArray image,InputoutputArray markers)

            第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可,且需為8位三通道的彩色圖像。

            第二個參數,InputOutput Array類型的markers,函數調用后的運算結果存在這里,輸入/輸出32位單通道圖像的標記結果。即這個參數用于存放函數調后的輸出結果,需和源圖片有一樣的尺寸和類型。

            代碼實現:

            #include "stdafx.h"#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> #include <fstream> 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_Mou(int event, int x, int y, int flags, void*);int main(){ //【0】改變console字體顏色 system("color 02"); //【1】載入原圖并顯示,初始化掩膜和灰度圖 g_srcImage = imread("D:\pic-sam\哀.JPG", 1); namedWindow(WINDOW_NAME1, WINDOW_NORMAL); 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】設置鼠標回調函數 tMouCallback(WINDOW_NAME1, on_Mou, 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, RETR_CCOMP, CHAIN_APPROX_SIMPLE); //輪廓為空時的處理 if (contours.empty()) continue; //拷貝掩膜 Mat maskImage(g_maskImage.size(), CV_32S); maskImage = Scalar::all(0); //循環繪制出輪廓 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(" 處理時間 = %gms ", dTime*1000. / getTickFrequency()); //雙層循環,將分水嶺圖像遍歷存入watershedImage中 Mat watershedImage(maskImage.size(), CV_8UC3); int index1 = 0; for (i = 0; i < maskImage.rows; i++) for (j = 0; j < maskImage.cols; j++) { if(maskImage.at<int>(i, j)>index1) index1 = maskImage.at<int>(i, j); } for (i = 0; i < maskImage.rows; i++) for (j = 0; j < maskImage.cols; j++) { int index = maskImage.at<int>(i, j); //對watershed函數生成的index的規律不是很清楚,經測試,并不是按照標記順序給出index的 //具體每一塊的index是怎么給出的還需要研究源碼 if (index == -1) watershedImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255); el if (index <= 0 || index > compCount) watershedImage.at<Vec3b>(i, j) = Vec3b(0, 0, 0); el if (index ==index1) watershedImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255); el watershedImage.at<Vec3b>(i, j) = Vec3b(index*10, 0, 0);//這里想給不同的物體標記為不同程度的顏色 //方便后面去除背景,顯示目標物體 } //混合灰度圖和分水嶺效果圖并顯示最終的窗口 //watershedImage = watershedImage*0.5 + grayImage*0.5; imshow(WINDOW_NAME2, watershedImage);//直接顯示分水嶺的效果圖 //這里想直接根據index,將背景顯示為黑色,需要分割出來的目標物體直接顯示 //但對index生成的規律還未搞清楚,結果可能不是很穩定 Mat src = imread("D:\pic-sam\哀.JPG", 1); for (int i = 0; i < src.rows; i++) for (int j = 0; j < src.cols; j++) { int a = abs(watershedImage.at<Vec3b>(i, j)[0] - 250) / 150; src.at<Vec3b>(i, j)[0] *= a; src.at<Vec3b>(i, j)[1] *= a; src.at<Vec3b>(i, j)[2] *= a; } namedWindow("dst", WINDOW_NORMAL); imshow("dst", src); } } return 0;}//鼠標消息回調函數 static void on_Mou(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); el if (event == CV_EVENT_LBUTTONDOWN) prevPt = Point(x, y); //鼠標左鍵按下并移動,繪制出線條 el 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), 4, 8, 0); line(g_srcImage, prevPt, pt, Scalar::all(255), 4, 8, 0); prevPt = pt; imshow(WINDOW_NAME1, g_srcImage); }}// 描述:輸出一些幫助信息 static void ShowHelpText(){ printf(" 當前使用的OpenCV版本為:" CV_VERSION); printf(" ---------------------------------------------------------------------------- "); //輸出一些幫助信息 printf(" 歡迎來到【分水嶺算法】示例程序~ "); printf(" 請先用鼠標在圖片窗口中標記出大致的區域, 然后再按鍵【1】或者【SPACE】啟動算法。" " 按鍵操作說明: " " 鍵盤按鍵【1】或者【SPACE】- 運行的分水嶺分割算法 " " 鍵盤按鍵【2】- 恢復原始圖片 " " 鍵盤按鍵【ESC】- 退出程序 ");}

            源圖像:

            ?

            進行標記的圖像:

            ?

            分水嶺算法得到的圖像:

            ?

            分割后圖像:

            ?

            代碼的第108-122行是對opencv分水嶺算法生成的結果圖進行分析,目前對watershed函數生成的index的規律不是很清楚,經測試,并不是按照標記順序給出index的,具體每一塊的index是怎么給出的還需要研究源碼

            代碼第130-138行,目的是想直接根據分水嶺算法生成的圖像中的index,將背景顯示為黑色,需要分割出來的目標物體直接顯示,但對index生成的規律還未搞清楚,結果可能不是很穩定

            以上部分參考: 毛星云 《OpenCV3編程入門》

            -----------------------------------------------------

            2019年4月19日增加:

            查閱到opencv分水嶺算法中,在“循環繪制出輪廓”時用到一個參數compCount,這個參數并不是記錄輪廓數目的,它的作用是把每個輪廓設為同一像素值,而maskImage中的像素值就是用1-compcount 的像素值標注的,這樣問題又轉化為不清楚在查找輪廓時,算法是按照什么樣的順序找出輪廓放入vector中的。

            本文發布于:2023-02-28 19:58:00,感謝您對本站的認可!

            本文鏈接:http://www.newhan.cn/zhishi/a/167764662575441.html

            版權聲明:本站內容均來自互聯網,僅供演示用,請勿用于商業和其他非法用途。如果侵犯了您的權益請與我們聯系,我們將在24小時內刪除。

            本文word下載地址:分水嶺算法(分水嶺算法分割圖像).doc

            本文 PDF 下載地址:分水嶺算法(分水嶺算法分割圖像).pdf

            下一篇:返回列表
            標簽:分水嶺   算法   圖像
            相關文章
            留言與評論(共有 0 條評論)
               
            驗證碼:
            推薦文章
            排行榜
            Copyright ?2019-2022 Comsenz Inc.Powered by ? 實用文體寫作網旗下知識大全大全欄目是一個全百科類寶庫! 優秀范文|法律文書|專利查詢|
            主站蜘蛛池模板: 国产精品综合一区二区三区| 国模雨珍浓密毛大尺度150p| 精品国产一区av天美传媒| 国产无遮挡18禁无码网站免费| 日韩精品久久久肉伦网站| 亚洲欧美日韩综合二区三区| 日韩av爽爽爽久久久久久 | 精品国产福利一区二区在线| 欧美精品日韩精品一卡| 久久精品av国产一区二区| 91精品啪在线观看国产91九色| 欧美极品色午夜在线视频| 免费大黄网站在线观看| 国产亚洲精品岁国产精品| 日韩精品中文字幕国产一| 精品一区二区三区不卡| 亚洲精品区午夜亚洲精品区| 18禁成人免费无码网站| 波多野结衣无内裤护士| 国产片精品av在线观看夜色| 色综合久久一区二区三区| 91福利一区福利二区| 亚洲无码a∨在线视频| 国产一区二区亚洲一区二区三区 | 精品九九人人做人人爱| 无码人妻精品一区二区三区下载| 日韩人妻无码精品久久久不卡| 欲乱人妻少妇邻居毛片| 国内精品久久人妻无码妲| 国产精品夜间视频香蕉| 成人福利一区二区视频在线| 国产蜜臀精品一区二区三区| 国产午精品午夜福利757视频播放 国产午夜亚洲精品国产成人 | 亚洲天堂久久一区av| 国产一区在线播放无遮挡| 亚洲国产精品综合久久网各| 亚洲日本乱码熟妇色精品| 伊人精品成人久久综合97| 国产午夜福利视频一区二区| 亚洲国产午夜精品福利| 中文字幕第一页国产|