一、检测需求
对某工业产品进行缺陷检测,图像示例如下所示,其缺陷为图中的大面积黑色区域
二、问题分析
上图为灰度图,由网格状排列黑点和大面积的黑点区域(即缺陷)组成,具体缺陷类型为粘连,其形态学特征为 连通域面积较大。
查找图中缺陷(大面积的黑点)算法的核心思想为:遍历所有的轮廓,根据面积判断缺陷,当连通域面积大于一定的值(面积比普通的黑点大),即判断为缺陷,并在原图上标出缺陷轮廓。
三、基本实现步骤
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);
代码运行效果如下所示:
颜色翻转之后,二值化后黑色的大面积连通区域(缺陷)就变为了白色。
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>usingnamespace std;usingnamespace cv;intmain(){/*进行基本缺陷检测,具体缺陷类型为粘连,具体形态学特征为 连通域面积较大
核心思想: 遍历所有的轮廓,根据面积判断缺陷
基本步骤:
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);return0;}
版权归原作者 摸鱼的机器猫 所有, 如有侵权,请联系我们删除。