opencv 五 缺陷检测实战1(检测以连通域面积特征为缺陷)

一、检测需求

对某工业产品进行缺陷检测,图像示例如下所示,其缺陷为图中的大面积黑色区域
在这里插入图片描述

二、问题分析

上图为灰度图,由网格状排列黑点和大面积的黑点区域(即缺陷)组成,具体缺陷类型为粘连,其形态学特征为 连通域面积较大
查找图中缺陷(大面积的黑点)算法的核心思想为:遍历所有的轮廓,根据面积判断缺陷,当连通域面积大于一定的值(面积比普通的黑点大),即判断为缺陷,并在原图上标出缺陷轮廓。

三、基本实现步骤

1、读取图像、修改尺寸并进行灰度化处理 【图像路径要用双斜杠】
2、对图片进行全局2值化处理 【二值化阈值要适度调整;因为目标连通域是黑色,故进行颜色翻转】
3、对图形进行腐蚀 【使图形变细,连通域断开,避免误检】
4、遍历连通域,按面积筛选缺陷 【findContours:查找所有连通域;aero:计算特定连通域的面积 ;drawContours:绘制特定连通域】

四、实现过程

4.1 读取图片并修改尺寸

读取图片后将图片修改成合适的大小,这样方便看到展示的效果。读取图片时要注意读取为彩色后,因为最后的缺陷检测出来后要用红色线条标记在原图上。

Mat img = imread("C:\\Users\\aaa\\Desktop\\缺陷检测.png");//注意文件名之间用双//
Mat img2;
resize(img, img2, {
    
     600,400 });//将原图修改为600*400的图片

4.2 将尺寸合适的彩色图修改为灰度图

运用cvtColor函数将BGR颜色空间的图片(img2)转换为GRAY(灰度图),结果保存到gray_mat。

Mat gray_mat;
cvtColor(img2,  gray_mat, cv::COLOR_BGR2GRAY);
imshow("01. 灰度图", gray_mat);

代码运行效果如下所示:
在这里插入图片描述

4.3 全局二值化

运用threshold函数将图片gray_mat进行全局二值化,结果存入bin_mat图片中。二值化阈值要根据不同的图片适度调整,也可以使用大津法进行全局二值化(THRESH_OTSU),亦可使用局部二值化方法。

Mat  bin_mat;
threshold(gray_mat, bin_mat, 128, 255, THRESH_BINARY);
//threshold(gray_mat, bin_mat, 0, 255, THRESH_OTSU);//大津法
//adaptiveThreshold(img, ez_mat, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 35, 10);//局部二值化方法,自适应阈值

imshow("02.2值图", bin_mat);

代码运行效果如下所示:
在这里插入图片描述

4.4 颜色翻转

因为二值化后目标连通域是黑色,故进行颜色翻转,方便下一步的操作。代码如下图所示:

Mat  inv_mat;
inv_mat = 255 - bin_mat;
imshow("03.颜色翻转", inv_mat);

代码运行效果如下所示:
在这里插入图片描述

颜色翻转之后,二值化后黑色的大面积连通区域(缺陷)就变为了白色。

扫描二维码关注公众号,回复: 15250455 查看本文章

4.5 腐蚀

使图形变细,连通域断开,避免误检(因为可能潜在边缘区域粘连);腐蚀操作的结构元素(element )的大小要按照实际效果进行调整。

//定义一个3*3的矩形元素
	Mat erode_mat;
	cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); 
	erode(inv_mat, erode_mat, element);//用element进行腐蚀
	imshow("04.腐蚀", erode_mat);

代码运行效果如下所示:
在这里插入图片描述

4.5 连通域筛选

遍历所有连通域,按面积筛选缺陷 。运用findContours函数查找指定变量(erode_mat)的所有连通域,结果存在contours里面;运用aero函数计算特定连通域(contours[i])的面积 ;当连通域面积大于指定值(1000)时运用drawContours函数绘制特定连通域(contours,i)到img2(修改尺寸后的彩色图)上。

//查找erode_mat的轮廓,结果存在contours里面
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(erode_mat, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
     //遍历所有轮廓,绘制缺陷轮廓
    for (int i = 0; i < contours.size(); i++)
    {
    
    
		int aero=contourArea(contours[i]);//计算轮廓面积
		if (aero > 1000) {
    
    
			//绘制轮廓  
			drawContours(img2, contours, i, Scalar(0,0,255), -1, 8, hierarchy);
			cout << i << "  aero:" << aero<<endl;
		}
    }
    imshow("05.Contours Image", img2); //轮廓  

代码运行效果如下所示:
在这里插入图片描述

5、全部代码

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>  
#include <assert.h>
#include <vector>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
using namespace cv;
   int  main() {
    
    
	   /*进行基本缺陷检测,具体缺陷类型为粘连,具体形态学特征为 连通域面积较大
	  核心思想: 遍历所有的轮廓,根据面积判断缺陷
	  基本步骤:
			1、读取图像、修改尺寸并进行灰度化处理  【图像路径要用双斜杠】
			2、对图片进行全局2值化处理 【二值化阈值要适度调整;因为目标连通域是黑色,故进行颜色翻转】
			3、对图形进行腐蚀 【使图形变细,连通域断开,避免误检】
			4、遍历连通域,按面积筛选缺陷 【findContours:查找所有连通域;
			   aero:计算特定连同域的面积 ;drawContours:绘制特定连通域】
			*/
	Mat img = imread("C:\\Users\\aaa\\Desktop\\缺陷检测.png");
	Mat img2;
	resize(img, img2, {
    
     600,400 });
	imshow("0修改尺寸", img2);
	Mat gray_mat;
	cvtColor(img2,  gray_mat, cv::COLOR_BGR2GRAY);
	imshow("01. 灰度图", gray_mat);
	Mat  bin_mat;
	threshold(gray_mat, bin_mat, 128, 255, THRESH_BINARY);
	imshow("02.2值图", bin_mat);
	Mat  inv_mat;
	inv_mat = 255 - bin_mat;
	imshow("03.颜色翻转", inv_mat);
	//定义一个3*3的矩形元素
	Mat erode_mat;
	cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); 
	erode(inv_mat, erode_mat, element);//用element进行腐蚀
	imshow("04.腐蚀", erode_mat);
	 
	//查找erode_mat的轮廓,结果存在contours里面
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(erode_mat, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
     //遍历所有轮廓,绘制缺陷轮廓
    for (int i = 0; i < contours.size(); i++)
    {
    
    
		int aero=contourArea(contours[i]);//计算轮廓面积
		if (aero > 1000) {
    
    
			//绘制轮廓  
			drawContours(img2, contours, i, Scalar(0,0,255), -1, 8, hierarchy);
			cout << i << "  aero:" << aero<<endl;
		}
    }
    imshow("05.Contours Image", img2); //轮廓  
    waitKey(0);
    return 0;
	 
	 
}

猜你喜欢

转载自blog.csdn.net/m0_74259636/article/details/128592257