最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

OpenCV圖像分割中的分水嶺算法原理與應(yīng)用詳解

 更新時(shí)間:2018年01月22日 09:10:06   作者:iracer  
這篇文章主要為大家詳細(xì)介紹了OpenCV圖像分割中的分水嶺算法原理與應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

圖像分割是按照一定的原則,將一幅圖像分為若干個(gè)互不相交的小局域的過程,它是圖像處理中最為基礎(chǔ)的研究領(lǐng)域之一。目前有很多圖像分割方法,其中分水嶺算法是一種基于區(qū)域的圖像分割算法,分水嶺算法因?qū)崿F(xiàn)方便,已經(jīng)在醫(yī)療圖像,模式識(shí)別等領(lǐng)域得到了廣泛的應(yīng)用。

1.傳統(tǒng)分水嶺算法基本原理

分水嶺比較經(jīng)典的計(jì)算方法是L.Vincent于1991年在PAMI上提出的[1]。傳統(tǒng)的分水嶺分割方法,是一種基于拓?fù)淅碚摰臄?shù)學(xué)形態(tài)學(xué)的分割方法,其基本思想是把圖像看作是測(cè)地學(xué)上的拓?fù)涞孛?,圖像中每一像素的灰度值表示該點(diǎn)的海拔高度,每一個(gè)局部極小值及其影響區(qū)域稱為集水盆地,而集水盆地的邊界則形成分水嶺。分水嶺的概念和形成可以通過模擬浸入過程來說明。在每一個(gè)局部極小值表面,刺穿一個(gè)小孔,然后把整個(gè)模型慢慢浸人水中,隨著浸入的加深,每一個(gè)局部極小值的影響域慢慢向外擴(kuò)展,在兩個(gè)集水盆匯合處構(gòu)筑大壩如下圖所示,即形成分水嶺。

傳統(tǒng)分水嶺算法示意圖

然而基于梯度圖像的直接分水嶺算法容易導(dǎo)致圖像的過分割,產(chǎn)生這一現(xiàn)象的原因主要是由于輸入的圖像存在過多的極小區(qū)域而產(chǎn)生許多小的集水盆地,從而導(dǎo)致分割后的圖像不能將圖像中有意義的區(qū)域表示出來。所以必須對(duì)分割結(jié)果的相似區(qū)域進(jìn)行合并。
[1]L.Vincent, P Soille. Watersheds in digital space: An efficientalgorithms based on immersion simulation[J]. IEEE Trans. on Pattern Analysisand Machine Intelligence, 1991, 13(6): 583-598.

2.改進(jìn)的分水嶺算法基本原理

因?yàn)閭鹘y(tǒng)分水嶺算法存在過分割的不足,OpenCV提供了一種改進(jìn)的分水嶺算法,使用一系列預(yù)定義標(biāo)記來引導(dǎo)圖像分割的定義方式。使用OpenCV的分水嶺算法cv::wathershed,需要輸入一個(gè)標(biāo)記圖像,圖像的像素值為32位有符號(hào)正數(shù)(CV_32S類型),每個(gè)非零像素代表一個(gè)標(biāo)簽。它的原理是對(duì)圖像中部分像素做標(biāo)記,表明它的所屬區(qū)域是已知的。分水嶺算法可以根據(jù)這個(gè)初始標(biāo)簽確定其他像素所屬的區(qū)域。傳統(tǒng)的基于梯度的分水嶺算法和改進(jìn)后基于標(biāo)記的分水嶺算法示意圖如下圖所示。


傳統(tǒng)基于梯度的分水嶺算法和基于標(biāo)記的分水嶺算法原理圖

從上圖可以看出,傳統(tǒng)基于梯度的分水嶺算法由于局部最小值過多造成分割后的分水嶺較多。而基于標(biāo)記的分水嶺算法,水淹過程從預(yù)先定義好的標(biāo)記圖像(像素)開始,較好的克服了過度分割的不足。本質(zhì)上講,基于標(biāo)記點(diǎn)的改進(jìn)算法是利用先驗(yàn)知識(shí)來幫助分割的一種方法。因此,改進(jìn)算法的關(guān)鍵在于如何獲得準(zhǔn)確的標(biāo)記圖像,即如何將前景物體與背景準(zhǔn)確的標(biāo)記出來。

3.基于標(biāo)記點(diǎn)的分水嶺算法應(yīng)用

基于標(biāo)記點(diǎn)的分水嶺算法應(yīng)用步驟

● 封裝分水嶺算法類

● 獲取標(biāo)記圖像

獲取前景像素,并用255標(biāo)記前景

獲取背景像素,并用128標(biāo)記背景,未知像素,使用0標(biāo)記

合成標(biāo)記圖像

● 將原圖和標(biāo)記圖像輸入分水嶺算法

● 顯示結(jié)果

(1)封裝分水嶺算法類

將分水嶺算法cv::watershed(image,markers)封裝進(jìn)類WatershedSegmenter,并保存為頭文件以便于操作。(本段封裝代碼參考《OpenCV計(jì)算機(jī)視覺編程攻略(第二版)》)

#if !defined WATERSHS 
#define WATERSHS 
 
#include <opencv2/core/core.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
 
class WatershedSegmenter { 
 
 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; 
    //在變換前,把每個(gè)像素p轉(zhuǎn)換為255p+255(在conertTo中實(shí)現(xiàn)) 
    markers.convertTo(tmp,CV_8U,255,255); 
 
    return tmp; 
   } 
}; 
#endif 

(2)獲取標(biāo)記圖像

標(biāo)記前景

讀取原圖

// Read input image 
  cv::Mat image1= cv::imread("image.jpg"); 
  if (!image1.data) 
    return 0;  
// Display the color image 
  cv::resize(image1, image1, cv::Size(), 0.7, 0.7); 
  cv::namedWindow("Original Image1"); 
  cv::imshow("Original Image1",image1); 

原圖

以下代碼目的是獲取前景物體的像素,并用255標(biāo)記。這里使用閾值分割初步分割前景和背景,接著使用形態(tài)學(xué)閉運(yùn)算連接二值圖像中前景的各個(gè)部分,并平滑邊緣。如何更好的獲取前景像素,需要根據(jù)實(shí)際圖像的情況靈活處理。

// Identify image pixels with object 
   
  Mat binary; 
  cv::cvtColor(image1,binary,COLOR_BGRA2GRAY); 
  cv::threshold(binary,binary,30,255,THRESH_BINARY_INV);//閾值分割原圖的灰度圖,獲得二值圖像 
  // Display the binary image 
  cv::namedWindow("binary Image1"); 
  cv::imshow("binary Image1",binary); 
  waitKey(); 
   
  // CLOSE operation 
  cv::Mat element5(5,5,CV_8U,cv::Scalar(1));//5*5正方形,8位uchar型,全1結(jié)構(gòu)元素 
  cv::Mat fg1; 
  cv::morphologyEx(binary, fg1,cv::MORPH_CLOSE,element5,Point(-1,-1),1);// 閉運(yùn)算填充物體內(nèi)細(xì)小空洞、連接鄰近物體 
 
  // Display the foreground image 
  cv::namedWindow("Foreground Image"); 
  cv::imshow("Foreground Image",fg1); 
  waitKey(); 

閾值分割原圖像的灰度圖


閉運(yùn)算獲取前景

標(biāo)記背景和未知區(qū)域

在上面閾值分割得到的二值圖像binary的基礎(chǔ)上,通過對(duì)白色前景的深度膨脹運(yùn)算獲得一個(gè)超過前景實(shí)際大小的物體,緊接著用反向閾值將深度膨脹后的圖像中的黑色部分轉(zhuǎn)換成128,即完成了對(duì)背景像素的標(biāo)記。實(shí)際上,在0~255范圍內(nèi),任意不為0或255的值均可作為背景的標(biāo)記。當(dāng)然如果有其他類型的物體,可以使用另外一個(gè)數(shù)值作為其標(biāo)記。也就是說,多個(gè)目標(biāo)可以有多個(gè)標(biāo)記來幫助分水嶺算法正確分割圖像。

// Identify image pixels without objects 
   
  cv::Mat bg1; 
  cv::dilate(binary,bg1,cv::Mat(),cv::Point(-1,-1),4);//膨脹4次,錨點(diǎn)為結(jié)構(gòu)元素中心點(diǎn) 
  cv::threshold(bg1,bg1,1,128,cv::THRESH_BINARY_INV);//>=1的像素設(shè)置為128(即背景) 
  // Display the background image 
  cv::namedWindow("Background Image"); 
  cv::imshow("Background Image",bg1); 
  waitKey(); 

將背景設(shè)置為128,未知區(qū)域設(shè)置為0

合成標(biāo)記圖像

將前景、背景及未知區(qū)域合成為一個(gè)標(biāo)記圖像。則標(biāo)記圖像中通過255標(biāo)記前景物體,通過128標(biāo)記背景,通過0標(biāo)記未知區(qū)域。

//Get markers image 
 
  Mat markers1 = fg1 + bg1; //使用Mat類的重載運(yùn)算符+來合并圖像。 
  cv::namedWindow("markers Image"); 
  cv::imshow("markers Image",markers1); 
  waitKey(); 

標(biāo)記圖像

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

將標(biāo)記圖像和原圖輸入分水嶺算法封裝的類WatershedSegmenter,執(zhí)行分水嶺算法,并顯示算法運(yùn)行的結(jié)果。

// Apply watershed segmentation 
 
  WatershedSegmenter segmenter1; //實(shí)例化一個(gè)分水嶺分割方法的對(duì)象 
  segmenter1.setMarkers(markers1);//設(shè)置算法的標(biāo)記圖像,使得水淹過程從這組預(yù)先定義好的標(biāo)記像素開始 
  segmenter1.process(image1);   //傳入待分割原圖 
    
  // Display segmentation result 
  cv::namedWindow("Segmentation1"); 
  cv::imshow("Segmentation1",segmenter1.getSegmentation());//將修改后的標(biāo)記圖markers轉(zhuǎn)換為可顯示的8位灰度圖并返回分割結(jié)果(白色為前景,灰色為背景,0為邊緣) 
  waitKey(); 
    // Display watersheds 
  cv::namedWindow("Watersheds1"); 
  cv::imshow("Watersheds1",segmenter1.getWatersheds());//以圖像的形式返回分水嶺(分割線條) 
  waitKey(); 

代碼segmenter1.process(image)將修改標(biāo)記圖像markers,每個(gè)值為0的像素都會(huì)被賦予一個(gè)輸入標(biāo)簽,而邊緣處的像素賦值為-1,得到的標(biāo)簽圖像如下圖所示。


顯示分水嶺分割圖像


分水嶺分割線顯示

(4)顯示結(jié)果圖像

本步驟的目的是將前景物體的分割結(jié)果在黑/白底色中顯示出來。背景顏色由黑轉(zhuǎn)白時(shí)使用了Mat矩陣掃描的.ptr方法與指針運(yùn)算。

// Get the masked image 
  Mat maskimage = segmenter1.getSegmentation(); 
  cv::threshold(maskimage,maskimage,250,1,THRESH_BINARY); 
  cv::cvtColor(maskimage,maskimage,COLOR_GRAY2BGR); 
 
  maskimage = image1.mul(maskimage); 
  cv::namedWindow("maskimage"); 
  cv::imshow("maskimage",maskimage); 
  waitKey(); 
 
  // Turn background (0) to white (255) 
  int nl= maskimage.rows; // number of lines 
  int nc= maskimage.cols * maskimage.channels(); // total number of elements per line 
 
  for (int j=0; j<nl; j++) { 
     uchar* data= maskimage.ptr<uchar>(j); 
    for (int i=0; i<nc; i++)  
    { 
      // process each pixel --------------------- 
      if (*data==0) //將背景由黑色改為白色顯示 
        *data=255; 
      data++;//指針操作:如為uchar型指針則移動(dòng)1個(gè)字節(jié),即移動(dòng)到下1列 
    } 
   } 
  cv::namedWindow("result"); 
  cv::imshow("result",maskimage); 
  waitKey(); 

原圖的前景分割圖(黑色背景)


原圖的前景分割圖(白色背景)

從上圖的分割結(jié)果可以看出,基于標(biāo)記圖像的分水嶺算法較好的實(shí)現(xiàn)了復(fù)雜背景下前景目標(biāo)分割。算法應(yīng)用的關(guān)鍵步驟為標(biāo)記圖像的獲取,目前很多文獻(xiàn)提出了各類獲取標(biāo)記圖像的方法,如何使用還需要根據(jù)所處理的圖像來量身確定。

貼出實(shí)驗(yàn)原始圖像:)

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 構(gòu)造函數(shù)不能聲明為虛函數(shù)的原因及分析

    構(gòu)造函數(shù)不能聲明為虛函數(shù)的原因及分析

    構(gòu)造函數(shù)不需要是虛函數(shù),也不允許是虛函數(shù),因?yàn)閯?chuàng)建一個(gè)對(duì)象時(shí)我們總是要明確指定對(duì)象的類型,盡管我們可能通過實(shí)驗(yàn)室的基類的指針或引用去訪問它但析構(gòu)卻不一定,我們往往通過基類的指針來銷毀對(duì)象
    2013-10-10
  • C語言每日練習(xí)之進(jìn)制轉(zhuǎn)換

    C語言每日練習(xí)之進(jìn)制轉(zhuǎn)換

    這篇文章主要介紹了C語言進(jìn)制轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • C++命名空間域的實(shí)現(xiàn)示例

    C++命名空間域的實(shí)現(xiàn)示例

    命名空間域就是一個(gè)獨(dú)立的空間外面不能直接調(diào)用該空間域只能用訪問限定符指定訪問該空間域,本文主要介紹了C++命名空間域的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • VSCode保存代碼自動(dòng)格式化無效的解決方法

    VSCode保存代碼自動(dòng)格式化無效的解決方法

    最近一直使用vscode,VSCode中各種配置后,自動(dòng)保存格式化仍然無效,本文就來介紹一下解決方法,感興趣的可以了解一下
    2023-08-08
  • 詳解C++11中的右值引用與移動(dòng)語義

    詳解C++11中的右值引用與移動(dòng)語義

    本篇文章主要介紹了詳解C++11中的右值引用與移動(dòng)語義,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Qt數(shù)據(jù)庫應(yīng)用之實(shí)現(xiàn)csv文件轉(zhuǎn)xls

    Qt數(shù)據(jù)庫應(yīng)用之實(shí)現(xiàn)csv文件轉(zhuǎn)xls

    這篇文章主要為大家詳細(xì)介紹了如何利用Qt實(shí)現(xiàn)csv文件轉(zhuǎn)xls功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定參考價(jià)值,需要的可以了解一下
    2022-06-06
  • Qt數(shù)據(jù)庫應(yīng)用之通用數(shù)據(jù)庫同步

    Qt數(shù)據(jù)庫應(yīng)用之通用數(shù)據(jù)庫同步

    數(shù)據(jù)庫同步的主要功能是將本地的數(shù)據(jù)庫記錄同步到遠(yuǎn)程的數(shù)據(jù)庫。本文將利用Qt實(shí)現(xiàn)通用數(shù)據(jù)庫同步功能,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-03-03
  • C語言模擬內(nèi)存函數(shù)分析之mencpy與memmove

    C語言模擬內(nèi)存函數(shù)分析之mencpy與memmove

    這篇文章主要介紹了C語言詳解如何模擬內(nèi)存函數(shù),用到了mencpy與memmove兩個(gè)函數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • 解決Qt設(shè)置QTextEdit行高的問題

    解決Qt設(shè)置QTextEdit行高的問題

    這篇文章介紹了Qt設(shè)置QTextEdit行高的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 簡單解讀C++中的虛函數(shù)

    簡單解讀C++中的虛函數(shù)

    這篇文章主要介紹了C++中的虛函數(shù),在C++中,虛函數(shù)聯(lián)系到多態(tài)、多態(tài)聯(lián)系到繼承,因而虛函數(shù)是C++中的一大重要特性,需要的朋友可以參考下
    2016-04-04

最新評(píng)論

渭源县| 乃东县| 尼玛县| 洮南市| 郎溪县| 商丘市| 蓬莱市| 苍梧县| 灵石县| 潮安县| 吉木乃县| 河北省| 庄河市| 黄平县| 吉安县| 梅州市| 柞水县| 突泉县| 马尔康县| 湘乡市| 成都市| 彝良县| 晋中市| 体育| 收藏| 乡城县| 南安市| 尚志市| 罗田县| 泸溪县| 南雄市| 邓州市| 东方市| 乌鲁木齐县| 彭水| 宁化县| 墨江| 南康市| 海晏县| 巴南区| 长春市|