前言
Canny邊緣檢測速度很快,OpenCV中經常會用到Canny邊緣檢測,以前的Demo中使用Canny邊緣檢測都是自己手動修改高低閾值引數,最近正好要研究點小東西時,就想能不能做個自適應的閾值,在不影響整體效果的基礎上不用手動調參,話不多說,且看下文。
實現思路:
- 影像轉成灰度影像
- 求其灰度直方圖,並找出中位數
- 根據中位數和設定的sigma值求出高低閾值
- 使用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邊緣檢測時直接就按這兩個高低閾值處理的。對於灰度影像,效果較好。
嚴謹性不高,後續仍需改進!!???