亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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)文章

  • C語言 圖文并茂詳解程序編譯過程

    C語言 圖文并茂詳解程序編譯過程

    C語言是一種編譯型語言,需要把源文件進(jìn)行編譯之后才能運(yùn)行,它的編譯過程是:預(yù)處理:展開頭文件、宏替換,去掉注釋,條件編譯;編譯:檢查語法,生成匯編;匯編:把生成的匯編文件匯編成機(jī)器碼;鏈接:鏈接到一起生成可執(zhí)行程序
    2022-04-04
  • C語言實(shí)現(xiàn)三角函數(shù)表

    C語言實(shí)現(xiàn)三角函數(shù)表

    這篇文章主要為大家詳細(xì)介紹了C語言三角函數(shù)表,打印出相對(duì)應(yīng)的三角函數(shù)值,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • C語言超詳細(xì)講解getchar函數(shù)的使用

    C語言超詳細(xì)講解getchar函數(shù)的使用

    C 庫函數(shù) int getchar(void) 從標(biāo)準(zhǔn)輸入 stdin 獲取一個(gè)字符(一個(gè)無符號(hào)字符)。這等同于 getc 帶有 stdin 作為參數(shù),下面讓我們?cè)敿?xì)來看看
    2022-05-05
  • C++ seekg函數(shù)用法案例詳解

    C++ seekg函數(shù)用法案例詳解

    這篇文章主要介紹了C++ seekg函數(shù)用法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C++控制臺(tái)強(qiáng)化如何實(shí)現(xiàn)一定界面效果(簡潔版)

    C++控制臺(tái)強(qiáng)化如何實(shí)現(xiàn)一定界面效果(簡潔版)

    這篇文章主要介紹了C++控制臺(tái)強(qiáng)化如何實(shí)現(xiàn)一定界面效果(簡潔版),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++11新特性之智能指針(shared_ptr/unique_ptr/weak_ptr)

    C++11新特性之智能指針(shared_ptr/unique_ptr/weak_ptr)

    這篇文章主要介紹了C++11新特性之智能指針,包括shared_ptr, unique_ptr和weak_ptr的基本使用,感興趣的小伙伴們可以參考一下
    2016-08-08
  • VS2022中使用Copilot的圖文教程

    VS2022中使用Copilot的圖文教程

    大家都知道Copilot可以自動(dòng)幫助寫代碼,那么這個(gè)工具是如果使用的呢?很多朋友不是很清楚,今天小編給大家分享一篇教程關(guān)于VS2022中使用Copilot的圖文教程,感興趣的朋友一起看看吧
    2022-04-04
  • opencv3/C++ FLANN特征匹配方式

    opencv3/C++ FLANN特征匹配方式

    今天小編就為大家分享一篇opencv3/C++ FLANN特征匹配方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • opencv3機(jī)器學(xué)習(xí)之EM算法示例詳解

    opencv3機(jī)器學(xué)習(xí)之EM算法示例詳解

    這篇文章主要介紹了opencv3機(jī)器學(xué)習(xí)之EM算法的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • VisualStudio?禁用移動(dòng)文件到文件夾自動(dòng)修改命名空間功能

    VisualStudio?禁用移動(dòng)文件到文件夾自動(dòng)修改命名空間功能

    這篇文章主要介紹了VisualStudio?禁用移動(dòng)文件到文件夾自動(dòng)修改命名空間功能,文章底部給大家介紹了解決安裝VS2022時(shí),出現(xiàn)未能安裝包“Microsoft.VisualCpp.Redist.14,version=14.32.31332,chip”=x86,的問題及解決方法,需要的朋友可以參考下
    2022-09-09

最新評(píng)論