<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ##使用Canny算子檢測輪廓 在:[http://blog.csdn.net/liyuefeilong/article/details/43927909](http://blog.csdn.net/liyuefeilong/article/details/43927909)?中,主要討論了使用sobel算子和拉普拉斯變換進行邊緣檢測。其中主要使用了了對梯度大小進行閾值化以得到二值的邊緣圖像的方法。在一幅圖像中,邊緣往往包含著重要的視覺信息,因為它們描繪出圖像元素的輪廓。然而,僅僅使用簡單的二值邊緣圖像有兩大缺陷: 1\. 使用這種方法檢測得到的邊緣過粗,這意味著難以實現物體的精確定位。 2\. 難以找到這樣的閥值,既能足夠低檢測到所有重要的邊緣,同時也不至于包含過多次要的邊緣。 這兩個問題正是此節所使用的Canny算法所要嘗試解決的。Canny算子是JohnCanny于1986年提出的,它與Marr(LoG)邊緣檢測方法類似,屬于先平滑后求導數的方法。 Canny算子通常基于Sobel算子(當然,也可以使用其他的梯度算子)。一般來說,圖像梯度幅值矩陣中的元素值越大,說明圖像中該像素點的梯度值越大,但這并不能說明該點就是邊緣。在Canny算法中,非極大值抑制是進行邊緣檢測的重要步驟,通俗意義上是指尋找像素點局部最大值,將非極大值點所對應的灰度值置為0,這樣可以剔除掉一大部分非邊緣的點。較高的亮度梯度比較有可能是邊緣,但是沒有一個確切的值來限定多大的亮度梯度是邊緣多大又不是,所以 Canny使用了磁滯閥值化的策略: 1\. 磁滯閥值化的原理是使用高與低兩個閾值。假設圖像中的重要邊緣都是連續的曲線,這樣就可以跟蹤給定曲線中模糊的部分,并且避免將沒有組成曲線的噪聲像素當成邊緣。所以使用一個較大的閾值,標識出比較確信的真實邊緣,使用前面導出的方向信息,從這些真正的邊緣開始在圖像中跟蹤整個的邊緣。 2\. 在跟蹤的時候,我們使用一個較小的閾值,這樣就可以跟蹤曲線的模糊部分直到我們回到起點。這樣根據兩個閾值分別進行劃分,得到兩幅邊緣圖。 3\. Canny算法組合兩幅邊緣圖以生成一副“最優”的輪廓圖。如果存在連續的邊緣點,則將低閥值圖像中的邊緣點與高閥值圖像中的邊緣相連接,那么就保留低閥值圖像中的邊緣點。 Canny算法通常處理的圖像為灰度圖,因此若輸入的是彩色圖像,則需要進行灰度化。對于RGB圖像,通常灰度化采用的方法主要有:? 1\. Gray=(R+G+B)/3;? 2\. Gray=0.299R+0.587G+0.114B;(這種參數考慮到了人眼的生理特點)? 注意,在程序設計時要考慮到圖像格式中RGB的順序通常為BGR。然而,opencv支持將輸入圖像直接轉化為灰度圖像,因此可以跳過這個步驟。 Canny算法對于兩個閾值的選擇有一定的要求。對于較低那個閾值,應該包括所有被認為是屬于明顯圖像輪廓的邊緣像素。而較高的閾值的角色應該是定義屬于所有重要輪廓的邊緣,它應該排除所有異常值。 在OpenCV中,實現Canny算法的函數是cv::Canny,首先需要知道的是,cv::Canny的兩個閾值都需要用戶親自輸入,且使用的邊緣梯度是用sobel算子,該函數的調用方法如下: ~~~ cv::contours; cv::Canny(image, // 輸入的灰度圖像 contours, // 輸出輪廓 125, // 低閾值 200); // 高閾值 ~~~ 首先創建一個Qt控制臺項目,并新建一個名為Canny算法的類,修改canny.h: ~~~ #ifndef CANNY_H #define CANNY_H #define PI 3.1415926 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> class Canny { private: cv::Mat img; // 輸入圖像 cv::Mat sobel; int aperture; // 存放閾值 cv::Mat sobelMagnitude; // Sobel大小 cv::Mat sobelOrientation; // Sobel方向 public: Canny():aperture(3){} // 設定閾值 void setAperture(int a) { aperture = a; } // 獲取閾值 int getAperture() const; // 計算Sobel結果 void computeSobel(const cv::Mat &image); // 獲取幅度 cv::Mat getMagnitude(); // 獲取Sobel方向 cv::Mat getOrientation(); // 輸入門限獲取二值圖像 cv::Mat getBinaryMap(double Threhhold); // 轉化為CV_8U圖像 cv::Mat getSobelImage(); // 獲取梯度 cv::Mat getSobelOrientationImage(); }; #endif // CANNY_H ~~~ 接著,對各個函數進行定義,修改canny.cpp文件: ~~~ #include "canny.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> // 獲取閾值 int Canny::getAperture() const { return aperture; } // 計算Sobel結果 void Canny::computeSobel(const cv::Mat &image) { cv::Mat sobelX; cv::Mat sobelY; cv::Sobel(image,sobelX,CV_32F,1,0,aperture); cv::Sobel(image,sobelY,CV_32F,0,1,aperture); cv::cartToPolar(sobelX,sobelY,sobelMagnitude,sobelOrientation); } // 獲取幅度 cv::Mat Canny::getMagnitude() { return sobelMagnitude; } // 獲取Sobel方向 cv::Mat Canny::getOrientation() { return sobelOrientation; } // 輸入門限獲取二值圖像 cv::Mat Canny::getBinaryMap(double Threhhold) { cv::Mat bgImage; threshold(sobelMagnitude,bgImage,Threhhold,255,cv::THRESH_BINARY_INV); return bgImage; } // 轉化為CV_8U圖像 cv::Mat Canny::getSobelImage() { cv::Mat bgImage; double minval,maxval; cv::minMaxLoc(sobelMagnitude,&minval,&maxval); sobelMagnitude.convertTo(bgImage,CV_8U,255/maxval); return bgImage; } // 獲取梯度 cv::Mat Canny::getSobelOrientationImage() { cv::Mat bgImage; sobelOrientation.convertTo(bgImage,CV_8U,90/PI); return bgImage; } ~~~ 最后修改main函數: ~~~ #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <QDebug> #include "canny.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); cv::Mat image = cv::imread("C:/peng.jpg",0); if(! image.data) qDebug() << "No input image"; cv::imshow("Original Image",image); // 計算sobel Canny h; h.computeSobel(image); // 獲取sobel的大小和方向 cv::imshow("orientation of sobel",h.getSobelOrientationImage()); cv::imshow("Magnitude of sobel",h.getSobelImage()); // 使用兩種閾值的檢測結果 cv::imshow("The Lower Threshold",h.getBinaryMap(125)); cv::imshow("The Higher Threshold",h.getBinaryMap(225)); // 使用canny算法 cv::Mat contours; cv::Canny(image,contours,125,225); cv::Mat contoursInv; cv::threshold(contours,contoursInv,128,255,cv::THRESH_BINARY_INV); cv::imshow("Edge Image",contoursInv); return a.exec(); } ~~~ 在輸出結果中,可以觀察到使用Sobel算子得出的方向和大小: ![](https://box.kancloud.cn/2015-12-30_5683a7547f901.jpg) 以及使用兩個閾值得到的兩個檢測結果及融合兩個結果所得出的最終結果: ![](https://box.kancloud.cn/2015-12-30_5683a754aa3bd.jpg) 當然,如果只是想直接實現Canny算法,無需建立Canny類,直接在main函數中添加以下內容即可: ~~~ #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); cv::Mat image = cv::imread("c:/peng.jpg", 0); if(!image.data) { qDebug() << "No input image"; } cv::Mat result; cv::Canny(image, result, 150, 220); cv::namedWindow("Original Image"); cv::imshow("Original Image", image); cv::namedWindow("Canny Result"); cv::imshow("Canny Result", result); return a.exec(); } ~~~ 效果: ![](https://box.kancloud.cn/2015-12-30_5683a754bdd72.jpg) 以下是Sobel算子進行邊緣檢測的輸出效果: ![](https://box.kancloud.cn/2015-12-30_5683a754d81d6.jpg) 對比Sobel算子,Canny算子能得到較薄的邊緣,這是因為Canny算法采用了額外的策略來提升圖像的質量。在使用磁滯閾值化之前,所有在梯度大小并非最大值的邊緣點都被移除。這樣一來梯度的朝向總是與邊緣垂直,因此該方向的局部梯度最大值對應的是輪廓強度最大的點。Canny 算法適用于不同的場合。它的參數允許根據不同實現的特定要求進行調整以識別不同的邊緣特性。 需要注意的是,使用Canny 算法檢測輪廓時需要考慮一些可以調整的參數,它們將影響到算法的計算的時間與實效。 1\. 高斯濾波器的大小:第一步所用的平滑濾波器將會直接影響 Canny 算法的結果。較小的濾波器產生的模糊效果也較少,這樣就可以檢測較小、變化明顯的細線。較大的濾波器產生的模糊效果也較多,將較大的一塊圖像區域涂成一個特定點的顏色值。這樣帶來的結果就是對于檢測較大、平滑的邊緣更加有用,例如彩虹的邊緣。 2\. 閾值:使用兩個閾值比使用一個閾值更加靈活,但是它還是有閾值存在的共性問題。設置的閾值過高,可能會漏掉重要信息;閾值過低,將會把枝節信息看得很重要。很難給出一個適用于所有圖像的通用閾值。目前還沒有一個經過驗證的實現方法。 最近發現了一篇博客,深受啟發:[http://blog.csdn.net/likezhaobin/article/details/6892629](http://blog.csdn.net/likezhaobin/article/details/6892629)?給出了一個無需設定閾值的Canny算法,其效果需要進一步論證。
                  <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>

                              哎呀哎呀视频在线观看