網格缺陷檢測(二值化閾值分析)

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

摘要

本篇來用OpenCV實現Halcon中一個簡單的網格缺陷檢測例項。 Halcon中對應的例子為novelty_detection_dyn_threshold.hdev。並對二值化中的三種閾值處理進行介紹和比較:

  • 全域性閾值二值化(含OTSU方法)
  • 自適應閾值二值化

  • 雙閾值二值化

閾值處理分析

1️⃣全域性閾值二值化-threshold()

OpenCV的threshold函式一般是給定一個閾值,對超過或者低於這個閾值的畫素進行處理,函式如下:

threshold(
    InputArray src,      // 輸入影像
    OutputArray dst,     // 輸出影像
    double thresh,       // 閾值
    double maxValue,     // 最大值(對於三通道影像一般是255)
    int thresholdType    // 閾值化操作的型別 
          )
 閾值化操作的型別常用兩種:
THRESH_BINARY     //黑背景找白目標(即超過設定閾值的值置255,其他為0)
THRESH_BINARY_INV //白背景找黑目標(即超過設定閾值的值置0,其他為255)

 全域性閾值類似一刀切的概念。對於整體影像來說,找到一個合適的閾值,將影像分為0(黑色)和255(白色)。

2️⃣自適應閾值二值化-adaptiveThreshold()

對於亮度分佈差異較大的影像,因為常常無法找到一個合適的閾值。因此我們需要一種改進的閾值化演算法,即自適應閾值化。

adaptiveThreshold(  
    InputArray src,       // 輸入影像  
    OutputArray dst,      // 輸出影像  
    double maxValue,      // 最大值  
    int adaptiveMethod,   // 自適應方法,平均或高斯  
    int thresholdType     // 閾值化型別  
    int blockSize,        // 塊大小(大小必須為奇數)
    double C              // 常量(即偏移值調整量)
                  ) 
//adaptiveThreshold()支援兩種自適應方法:
ADAPTIVE_THRESH_MEAN_C       //平均:閾值是鄰域的平均值
ADAPTIVE_THRESH_GAUSSIAN_C //高斯:閾值是鄰域值的加權和,其中權重是高斯視窗

 自適應閾值化能夠根據影像不同區域亮度分佈的,改變閾值。因此,我們針對同一影像的不同區域獲得不同的閾值,併為具有不同照明的影像提供更好的結果。

 3️⃣雙閾值二值化

對於影像具有明顯的雙分界特徵,可以使用雙閾值法進行二值化操作,即實現Halcon中的threshold函式。

簡單來說:

  • Halcon的threshold函式是獲取區間[a, b]之間的灰度值(雙閾值)
  • OpenCV的threshold只能針對大於或者小於a或者b的灰度值處理(單閾值)

因此我們可以預設兩個特定的閾值量thresh1、thresh2,並且thresh1 < thresh2 。閾值化的過程就是,將在 (thresh1,thresh2) 這個區間內的灰度值設定為maxVal(255),將其餘部分設定為0 。

    const int maxVal = 255;        //預設最大值
    int low_threshold = 90;        //較小的閾值量
    int high_threshold = 190;      //較大的閾值量
    //小閾值對源灰度影像進行二進位制閾值化操作
    threshold(srcGray, dst1, low_threshold, maxVal, THRESH_BINARY);
    //大閾值對源灰度影像進行反二進位制閾值化操作
    threshold(srcGray, dst2, high_threshold, maxVal, THRESH_BINARY_INV);
    //矩陣"與運算"得到二值化結果
    bitwise_and(dst1, dst2, dst); //對畫素加和
    imshow("雙閾值二值化", dst);
程式中主要還是用到了threshold()函式,對較小的閾值量進行二進位制閾值化,而對較大的閾值量進行反二進位制化操作,最後將所得的兩幅影像進行與運算,得到最終效果。

網格缺陷檢測

進入正題,本篇對網格缺陷檢測的思路很簡單:

  1. 動態閾值處理
  2. 面積篩選顯示缺陷

opencv實現:

    Mat src = imread("D:/opencv練習圖片/網格缺陷檢測1.png");
    imshow("原圖", src);
    cvtColor(src, gray, COLOR_RGB2GRAY);
    GaussianBlur(gray, gray, Size(3, 3), 1, 0);
    //雙閾值方法
    threshold(gray, binary1, 25, 255, THRESH_BINARY);
    threshold(gray, binary2, 80, 255, THRESH_BINARY_INV);
    bitwise_and(binary1, binary2, binary);
    imshow("雙閾值二值化", binary);
    vector<vector<Point>>contours;
    findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
    for (int i = 0; i < contours.size(); i++)
    {
        float area = contourArea(contours[i]);
        if (area>350)
        {
            drawContours(src, contours, i, Scalar(0, 0, 255), 2, 8);
            int baseline = 0;
            Size textSize = getTextSize("Mesh Not OK", FONT_HERSHEY_SIMPLEX, 1.0, 2, &baseline);        
            rectangle(src, Rect(10, 10, textSize.width, textSize.height + baseline), Scalar(212, 233, 252), -1, 8);
            putText(src, "Mesh Not OK", Point(10, 5 + textSize.height + baseline), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
        }
        else
        {
            int baseline = 0;
            Size textSize = getTextSize("Mesh OK", FONT_HERSHEY_SIMPLEX, 1.0, 2, &baseline);
            rectangle(src, Rect(10, 10, textSize.width, textSize.height + baseline), Scalar(212, 233, 252), -1, 8);
            putText(src, "Mesh OK", Point(10, 5 + textSize.height + baseline), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2, 8);
        }
    }
    imshow("缺陷", src);

這裡採用的是雙閾值處理。我們可以對比三種閾值處理的情況:

(1)全域性閾值OTSU方法:

 可以看到有部分正常孔洞和網格相連,會導致正常孔洞也被標記為缺陷。

(2)自適應閾值:

 可以看到效果還不錯。

(3)雙閾值:

 對比自適應閾值,可以看到分割的還是比較明顯一點的。

 參考博文:python-opencv函式總結之(一)threshold、adaptiveThreshold、Otsu 二值化_sinat_21258931的部落格-CSDN部落格

                 OpenCV與AI深度學習

 

相關文章