opencv——自適應閾值Canny邊緣檢測

唯有自己強大發表於2021-06-03

前言

Canny邊緣檢測速度很快,OpenCV中經常會用到Canny邊緣檢測,以前的Demo中使用Canny邊緣檢測都是自己手動修改高低閾值引數,最近正好要研究點小東西時,就想能不能做個自適應的閾值,在不影響整體效果的基礎上不用手動調參,話不多說,且看下文。


 實現思路:

  1. 影像轉成灰度影像
  2. 求其灰度直方圖,並找出中位數
  3. 根據中位數和設定的sigma值求出高低閾值
  4. 使用Canny邊緣檢測

程式碼實現:

int main() 
{
    int GetMatMidVal(Mat& img);
    void GetMatMinMaxThreshold(Mat& img, int& minval, int& maxval, float sigma);
    Mat src = imread("D:/opencv練習圖片/灰度圖片.png");
    imshow("原圖", src);
    Mat gray,binary_1,binary_2;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size(3, 3), 0.5, 0.5);
    int minthreshold, maxthreshold;
    GetMatMinMaxThreshold(gray, minthreshold, maxthreshold,0.2);
    cout << "min:" << minthreshold << "  max:" << maxthreshold << endl;
    Canny(gray, binary_1, minthreshold, maxthreshold);
    imshow("自適應邊緣", binary_1);
    //Canny(gray, binary_2, 100, 200, 3);
    //imshow("邊緣", binary_2);
    waitKey(0);
    return 0;
}

//求Mat的中位數
int GetMatMidVal(Mat& img)
{
    //判斷如果不是單通道直接返回128
    if (img.channels() > 1) return 128;
    int rows = img.rows;
    int cols = img.cols;
    //定義陣列
    float mathists[256] = { 0 };
    //遍歷計算0-255的個數
    for (int row = 0; row < rows; ++row) {
        for (int col = 0; col < cols; ++col) {
            int val = img.at<uchar>(row, col);
            mathists[val]++;
        }
    }
    int calcval = rows * cols / 2;
    int tmpsum = 0;
    for (int i = 0; i < 255; ++i) {
        tmpsum += mathists[i];
        if (tmpsum > calcval) {
            return i;
        }
    }
    return 0;
}

//求自適應閾值的最小和最大值
void GetMatMinMaxThreshold(Mat& img, int& minval, int& maxval, float sigma)
{
    int midval = GetMatMidVal(img);
    cout << "midval:" << midval << endl;
    // 計算低閾值
    minval = saturate_cast<uchar>((1.0 - sigma) * midval);
    //計算高閾值
    maxval = saturate_cast<uchar>((1.0 + sigma) * midval);
}

結論:

 從上圖中可以看出,命令列視窗中min和max就是求出的高低閾值,使用Canny邊緣檢測時直接就按這兩個高低閾值處理的。對於灰度影像,效果較好。

嚴謹性不高,後續仍需改進!!???

 

相關文章