欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C語言

當前位置:主頁 > 軟件編程 > C語言 >

OpenCV圖像分割中的分水嶺算法原理與應用詳解

來源:本站原創(chuàng)|時間:2020-01-10|欄目:C語言|點擊: 次

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

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

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

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

然而基于梯度圖像的直接分水嶺算法容易導致圖像的過分割,產(chǎn)生這一現(xiàn)象的原因主要是由于輸入的圖像存在過多的極小區(qū)域而產(chǎn)生許多小的集水盆地,從而導致分割后的圖像不能將圖像中有意義的區(qū)域表示出來。所以必須對分割結果的相似區(qū)域進行合并。
[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.改進的分水嶺算法基本原理

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


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

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

3.基于標記點的分水嶺算法應用

基于標記點的分水嶺算法應用步驟

● 封裝分水嶺算法類

● 獲取標記圖像

獲取前景像素,并用255標記前景

獲取背景像素,并用128標記背景,未知像素,使用0標記

合成標記圖像

● 將原圖和標記圖像輸入分水嶺算法

● 顯示結果

(1)封裝分水嶺算法類

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

#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; 
    //在變換前,把每個像素p轉換為255p+255(在conertTo中實現(xiàn)) 
    markers.convertTo(tmp,CV_8U,255,255); 
 
    return tmp; 
   } 
}; 
#endif 

(2)獲取標記圖像

標記前景

讀取原圖

// 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標記。這里使用閾值分割初步分割前景和背景,接著使用形態(tài)學閉運算連接二值圖像中前景的各個部分,并平滑邊緣。如何更好的獲取前景像素,需要根據(jù)實際圖像的情況靈活處理。

// 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結構元素 
  cv::Mat fg1; 
  cv::morphologyEx(binary, fg1,cv::MORPH_CLOSE,element5,Point(-1,-1),1);// 閉運算填充物體內(nèi)細小空洞、連接鄰近物體 
 
  // Display the foreground image 
  cv::namedWindow("Foreground Image"); 
  cv::imshow("Foreground Image",fg1); 
  waitKey(); 

閾值分割原圖像的灰度圖


閉運算獲取前景

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

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

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

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

合成標記圖像

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

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

標記圖像

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

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

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

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


顯示分水嶺分割圖像


分水嶺分割線顯示

(4)顯示結果圖像

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

// 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型指針則移動1個字節(jié),即移動到下1列 
    } 
   } 
  cv::namedWindow("result"); 
  cv::imshow("result",maskimage); 
  waitKey(); 

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


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

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

貼出實驗原始圖像:)

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持我們。

上一篇:C語言實現(xiàn)學生信息管理系統(tǒng)(單鏈表)

欄    目:C語言

下一篇:C++實現(xiàn)企業(yè)職工工資管理系統(tǒng)

本文標題:OpenCV圖像分割中的分水嶺算法原理與應用詳解

本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/939.html

網(wǎng)頁制作CMS教程網(wǎng)絡編程軟件編程腳本語言數(shù)據(jù)庫服務器

如果侵犯了您的權利,請與我們聯(lián)系,我們將在24小時內(nèi)進行處理、任何非本站因素導致的法律后果,本站均不負任何責任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權所有