<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ##兩種圖像分割方法比較 此次研究兩種圖像分割法,分別是基于形態學的分水嶺算法和基于圖割理論的GrabCut算法。OpenCV均提供了兩張算法或其變種。鑒于研究所需,記錄一些知識點,開發平臺為OpenCV2.4.9+Qt5.3.2。 一、使用分水嶺算法進行圖像分割 分水嶺變換是一種常用的圖像處理算法,在網上很容易搜到詳細的原理分析。簡單來說,這是一種基于拓撲理論的數學形態學的圖像分割方法,其基本思想是把圖像看作是測地學上的拓撲地貌,圖像中每一點像素的灰度值表示該點的海拔高度,每一個局部極小值及其影響區域稱為集水盆,而集水盆的邊界則形成分水嶺。分水嶺的概念和形成可以通過模擬浸入過程來說明。在每一個局部極小值表面,刺穿一個小孔,然后把整個模型慢慢浸入水中,隨著浸入的加深,每一個局部極小值的影響域慢慢向外擴展,在兩個集水盆匯合處構筑大壩,即形成分水嶺。 分水嶺算法簡單,因此存在一些缺陷,如容易導致圖像的過度分割。分水嶺算法對微弱邊緣具有良好的響應,圖像中的噪聲、物體表面細微的灰度變化,都會產生過度分割的現象。 為消除分水嶺算法產生的過度分割,有兩種常規的處理方法,一是利用先驗知識去除無關邊緣信息。二是修改梯度函數使得集水盆只響應想要探測的目標。 OpenCV提供了該算法的改進版本,使用預定義的一組標記來引導對圖像的分割,該算法是通過cv::watershed函數來實現的。 要實現分水嶺算法,首先新建一個類WaterShedSegmentation,在watershedsegmentation.h中添加: ~~~ #ifndef WATERSHEDSEGMENTATION_H #define WATERSHEDSEGMENTATION_H #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> class WaterShedSegmentation { public: void setMarkers(const cv::Mat &markerImage); // 將原圖像轉換為整數圖像 cv::Mat process(const cv::Mat &image); // // 分水嶺算法實現 // 以下是兩種簡化結果的特殊方法 cv::Mat getSegmentation(); cv::Mat getWatersheds(); private: cv::Mat markers; // 用于非零像素點的標記 }; #endif // WATERSHEDSEGMENTATION_H ~~~ 接著,在watershedsegmentation.cpp中添加: ~~~ #include "watershedsegmentation.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> void WaterShedSegmentation::setMarkers(const cv::Mat &markerImage) // 該函數將原圖像轉換為整數圖像 { markerImage.convertTo(markers,CV_32S); } cv::Mat WaterShedSegmentation::process(const cv::Mat &image) { // 使用分水嶺算法 cv::watershed(image,markers); return markers; } // 以下是兩種簡化結果的特殊方法 // 以圖像的形式返回分水嶺結果 cv::Mat WaterShedSegmentation::getSegmentation() { cv::Mat tmp; // 所有像素值高于255的標簽分割均賦值為255 markers.convertTo(tmp,CV_8U); return tmp; } cv::Mat WaterShedSegmentation::getWatersheds() { cv::Mat tmp; markers.convertTo(tmp,CV_8U,255,255); return tmp; } ~~~ main函數修改如下: ~~~ #include <QCoreApplication> #include "watershedsegmentation.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 輸入待處理的圖像 cv::Mat image= cv::imread("c:/Fig4.41(a).jpg"); if (!image.data) return 0; cv::namedWindow("Original Image"); cv::imshow("Original Image",image); // 輸入圖像,將其轉化為二值圖像 cv::Mat binary; binary= cv::imread("c:/Fig4.41(a).jpg",0); // 顯示二值圖像 cv::namedWindow("Binary Image"); cv::imshow("Binary Image",binary); // 移除噪點 cv::Mat fg; cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6); // 顯示前景圖像 cv::namedWindow("Foreground Image"); cv::imshow("Foreground Image", fg); // 識別背景圖像,生成的黑色像素對應背景像素 cv::Mat bg; cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6); cv::threshold(bg, bg, 1, 128, cv::THRESH_BINARY_INV); // 顯示背景圖像 cv::namedWindow("Background Image"); cv::imshow("Background Image", bg); // 顯示標記圖像 cv::Mat markers(binary.size(), CV_8U,cv::Scalar(0)); markers= fg + bg; cv::namedWindow("Markers"); cv::imshow("Markers", markers); // 以下進行分水嶺算法 WaterShedSegmentation segmenter; segmenter.setMarkers(markers); segmenter.process(image); // 以下是兩種處理結果,顯示分割結果 cv::namedWindow("Segmentation"); cv::imshow("Segmentation", segmenter.getSegmentation()); cv::namedWindow("Watersheds"); cv::imshow("Watersheds",segmenter.getWatersheds()); return a.exec(); } ~~~ 效果1:算法識別出屬于前景和背景的像素(有誤差)。 ![](https://box.kancloud.cn/2015-12-30_5683a74d3dd5d.jpg) 效果2:組合前景和背景圖,形成標記圖形,這是分水嶺的輸入參數。 ![](https://box.kancloud.cn/2015-12-30_5683a74d526e5.jpg) 效果3:分割結果中,標記圖像得到更新。 ![](https://box.kancloud.cn/2015-12-30_5683a74d60f25.jpg) 效果4:顯示邊界圖像。 ![](https://box.kancloud.cn/2015-12-30_5683a74d769cc.jpg) 可以看出,分水嶺算法對微弱邊緣具有良好的響應,是得到封閉連續邊緣的保證的。但對于不同質量的圖像其分割效果不盡相同,但總的來說效果仍需要改進。 二、使用GrabCut算法分割圖像 GrabCut是另一種同樣較為流行的圖像分割算法。GrabCut是在GraphCut基礎上改進的一種圖像分割算法,它并非基于圖像形態學,而是基于圖割理論(參考:[http://www.cnblogs.com/tornadomeet/archive/2012/11/06/2757585.html](http://www.cnblogs.com/tornadomeet/archive/2012/11/06/2757585.html))。在使用GrabCut時,需要人工給定一定區域的目標或者背景,然后算法根據設定的參數來進行分割。GrabCut在計算時比分水嶺算法更加復雜,尤其適合從靜態圖像中提取前景照片的應用。? OpenCV中提供了cv::grabcut函數,因此只需提供圖像并標記背景像素和前景像素,基于局部的標記,算法即可將圖像中的像素進行分割。在這里使用的局部標記方法是定義一個矩形。cv::grabcut的函數定義如下: ~~~ cv::grabCut(image, // 輸入圖像 result, // 分割輸出結果 rectangle,// 包含前景物體的矩形 bgModel,fgModel, // 模型 1, // 迭代次數 cv::GC_INIT_WITH_RECT); // 使用矩形進行初始化 ~~~ 在main函數添加: ~~~ // GrabCut算法 cv::Mat image= cv::imread("c:/Fig8.04(a).jpg"); // 設定矩形 cv::Rect rectangle(50,70,image.cols-150,image.rows-180); cv::Mat result; // 分割結果 (4種可能取值) cv::Mat bgModel,fgModel; // 模型(內部使用) // 進行GrabCut分割 cv::grabCut(image, result, rectangle, bgModel, fgModel, 1, cv::GC_INIT_WITH_RECT); // 得到可能為前景的像素 cv::compare(result, cv::GC_PR_FGD, result,cv::CMP_EQ); // 生成輸出圖像 cv::Mat foreground(image.size(), CV_8UC3, cv::Scalar(255,255,255)); image.copyTo(foreground, result); // 不復制背景數據 // 包含矩形的原始圖像 cv::rectangle(image, rectangle, cv::Scalar(255,255,255),1); cv::namedWindow("Orginal Image"); cv::imshow("Orginal Image", image); // 輸出前景圖像結果 cv::namedWindow("Foreground Of Segmented Image"); cv::imshow("Foreground Of Segmented Image", foreground); ~~~ 效果:? ![](https://box.kancloud.cn/2015-12-30_5683a74d87283.jpg) 在函數cv::grabCut中,最后一個參數表示我們使用的是包圍盒模式,而該算法支持的輸入/輸出分割圖像可以有四種數值,如函數cv::compare函數中的參數:? cv::GC_BGD:確定屬于背景的像素;? cv::GC_FGD:確定屬于前景的元素;? cv::GC_PR_BGD:可能屬于背景的元素;? cv::GC_PR_FGD:可能屬于前景的元素。 在上圖中,GrabCut算法通過指定方框區域來提取前景物體。同時,也可將數值cv::GC_BGD和cv::GC_FGD賦予分割圖像的某些特定像素,并且把這類分割圖像作為cv::grabcut函數的第二個參數(此時需要指定GC_INIT_WITH_MASK作為輸入模式)。 基于這些信息,GrabCut通過以下主要步驟創建分割: 1. 前景標簽(cv::GC_PR_FGD)被臨時賦予所有為標記的像素。基于當前的分類,算法將像素歸類為顏色或灰度值相似的聚類。 2. 通過引入背景與前景像素的邊界進行分割。這個優化的過程嘗試將標簽相似的像素相連接,這里利用了在強度相對已知的區域之間對邊界像素的(懲罰?)。這個最優化問題通過GraphCut算法得到高效解決。 3. 對獲取的分割結果產生新的像素標簽,重復聚類過程,找到新的最優解。根據場景的復雜度,得到最佳結果,對于簡單的場景,有時只需要一次迭代。 關于GrabCut算法,還需要進一步研究GraphCut才能深刻理解。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看