摘要

本篇来用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);

网格缺陷检测(二值化阈值分析)-LMLPHP网格缺陷检测(二值化阈值分析)-LMLPHP

这里采用的是双阈值处理。我们可以对比三种阈值处理的情况:

(1)全局阈值OTSU方法:

网格缺陷检测(二值化阈值分析)-LMLPHP

 可以看到有部分正常孔洞和网格相连,会导致正常孔洞也被标记为缺陷。

(2)自适应阈值:

网格缺陷检测(二值化阈值分析)-LMLPHP

 可以看到效果还不错。

(3)双阈值:

网格缺陷检测(二值化阈值分析)-LMLPHP

 对比自适应阈值,可以看到分割的还是比较明显一点的。

 参考博文:python-opencv函数总结之(一)threshold、adaptiveThreshold、Otsu 二值化_sinat_21258931的博客-CSDN博客

                 OpenCV与AI深度学习

06-05 03:45