opencv缺陷检测

这篇具有很好参考价值的文章主要介绍了opencv缺陷检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

用传统算法,根据实际工程项目,手把手教你做一个最典型的产品缺陷检测项目案例,虽然这个案例与实际生产还存在一定的差距,但是这个检测流程已经很接近实际生产了。

我们先看一下测试结果:

opencv 缺陷检测,人工智能,人工智能

这个检测的主要需求就是,根据视频流中流水线上的产品,通过每一帧图像,检测出每个产品的缺陷属性,并把有缺陷的产品给标注出来,并注明缺陷类型。

在项目开始之前,我们先思考一下整个检测流程的框架:

1,首先我们要抓取视频流中的每一帧图像

2,在抓取得每一张图像中,首先要定位出这张图片中的每一个产品,找出这件产品的边缘

3,分析所抓取每个产品的属性,分析其缺陷类型的特征,通过算法形式来对缺陷进行归类。

上面就是整个检测的基本流程,其实,在利用传统算法进行检测的时候,基本流程不会差别太大,所用算子也基本大致相同。在讲解这个检测方法之前,我先来讲解几个我们经常用到的算子:

findContours():

这个函数是查找整张图片中所有轮廓的函数,这个函数很重要,在处理图像分割尤其是查找整个图像中边缘分割时候少不了它,所以我重点说明一下,首先它的函数原型是这样的:

// 查找整张图片的所有轮廓findContours(InputOutputArray image,     OutputArrayOfArrays contours,    OutputArray hierarchy,     int mode,    int method,     Point offset=Point());

我先来讲解一下这个函数的主要参数:

1),image代表输入的图像矩阵;

2),第二个参数contours代表输出的整张图片的所有轮廓,由于轮廓坐标是一组二维坐标构成的一组数据集,因此,它的声明是一个嵌套了一层坐标数据集向量的向量:

//参数contours的声明vector<vector<Point>> contours;

3),第三个参数hierarchy顾名思义,字面的意思是层级关系,它代表各个轮廓的继承关系,也是一个向量,长度和contours相同,每个元素和contours的元素相对应,hierarchy的每一个元素是一个包含四个整形数的向量,也即:​​​​​​​

//参数hierarchy的声明//Vec4i 代表包含四个元素的整形向量vector<Vec4i> hierarchy;  

那么这里的hierarchy究竟代表什么意思呢,其实对于一张图片,findContours()查找出所有的  个轮廓后,每个轮廓都会有自己的索引,  ,而hierarchy[i]里面的四个元素  分别代表第  个轮廓:后一个轮廓的序号、前一个轮廓的序号、子轮廓的序号、父轮廓的序号,有严格的顺序。

为了更加直观说明,请看下面一张图片:

opencv 缺陷检测,人工智能,人工智能

上面图片中,是一张图片中的所有轮廓,分别用序号0、1、2、3来表示,其中0有两个子轮廓,分别是1和3,而1则有一个父轮廓也有一个子轮廓,分别是0与2,它们的继承关系基本上就是这样,我们再做进一步的分析:

opencv 缺陷检测,人工智能,人工智能

4),第四个参数mode,代表定义轮廓的检索方式:

取值一:CV_RETR_EXTERNAL,只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略。

取值二:CV_RETR_LIST,检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1.

取值三:CV_RETR_CCOMP,检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层。

取值四:CV_RETR_TREE,检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。

5),第五个参数method,用来定义轮廓的近似方法:

取值一:CV_CHAIN_APPROX_NONE,保存物体边界上所有连续的轮廓点到contours向量内。

取值二:CV_CHAIN_APPROX_SIMPLE,仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留。

取值三:CV_CHAIN_APPROX_TC89_L1;

取值四:CV_CHAIN_APPROX_TC89_KCOS,取值三与四两者使用teh-Chinl chain 近似算法。

6),第六个参数,Point类型的offset参数,这个参数相当于在每一个检测出的轮廓点上加上该偏移量,而且Point还可以是负数。

在实际使用中,我们需要根据实际情况来选定合适的参数,比如第五个参数,如果你使用CV_CHAIN_APPROX_SIMPLE这个参数,那么返回的坐标向量集是仅包含拐点信息的,为了得到轮廓的完整坐标数据,我必须使用CV_CHAIN_APPROX_NONE参数。请大家在实际使用过程中根据自己的实际情况来选择合适的参数

再来说下moments这个函数,其实moment在物理学中表示“力矩”的感念,“矩”在物理学中是表示距离和物理量乘积的物理量,表示物体的空间分布(至于汉语为什么把它翻译成矩这个字,我也不太明白,不知道是不是李善兰翻译的)。而在数学中,“矩”是概率论中的一个名词,它的本质是数学期望,我们从它的定义中就可以看出:

 opencv 缺陷检测,人工智能,人工智能

opencv 缺陷检测,人工智能,人工智能  在opencv中,我们看下这个函数的原型:​​​​​​​

Moments moments(     InputArray array,     bool binaryImage = false     );

第一个参数是输入一个数组,也就是我们上面计算出来的contours向量,第二个参数默认为false.

我们再来看整个程序的编写方法:

首先我们使用opencv中的VideoCapture类来进行读取视频流,并抓取视频中的每一帧图像:​​​​​​​

Mat img; //定义图像矩阵VideoCapture cap("1.mp4");cap.read(img);

这样我们便把图像读取到img变量中了,当然,为了叙述方便,这只是其中的部分代码,实际你在运行过程中为了不断读取,外面还要嵌套个while(true)的循环。

读取到一帧图像后,我们需要对这张图像进行一些预处理,一般情况下,无论是传统算法还是深度学习算法,预处理的方法基本上都是一样的,比如灰度转换,图像滤波,二值化处理,边缘提取等等。在这里也一样,我们先对抓取到的图像进行灰度转换,灰度图像有诸多好处,比如它只包含亮度特征,而且一般情况下它是单通道的,256色调色板,一个像素占只用一个字节,储存起来非常整齐等等。

我们最终要的预处理结果是将其转化为二值化图像,二值化图像是灰度图像的一种特殊情况,它的像素亮度只有0与255两种情况,也就是非黑既白,在图像处理中,二值图像占有非常重要的地位,比如,图像的二值化有利于图像的进一步处理,使图像变得简单,使后面的计算量大大减少,而且还能能凸显出感兴趣的目标的轮廓。

灰度处理的算子接口为:​​​​​​​

void cv::cvtColor      (InputArray src,      OutputArray dst,      int code,      int dstCn = 0)

这个函数第一个参数src为输入图像,第二个参数dst为输出图像,第三个参数为需要转换的色彩空间,一般我们选取CV_BGR2GRAY即可,第四个参数默认为0.

灰度转化后,我们再进行二值化处理,这个算子比较简单,函数原型为:​​​​​​​

void cv::threshold     (InputArray src,      OutputArray dst,      double thresh,      double maxval,      int type)

同样,这个函数前两个参数分别为输入、输出参数;第三个参数thresh为设定的阈值;第四个参数maxval为设置的最大值,一般选取255;第五个参数type为阈值类型,表示当灰度值大于(或小于)阈值时将该灰度值赋成的值,其中最常用的有两个,分别是THRESH_BINARY,THRESH_BINARY_INV:

如果是THRESH_BINARY的话,表示当图像亮度值大于阈值thresh的话,将其设置为maxval,否则设置为0: 

opencv 缺陷检测,人工智能,人工智能我们再回到视频中,先截取一张图片,我们使用下面梁行代码先后对其进行灰度、二值化处理:​​​​​​​

//灰度处理cvtColor(img, grayImage, CV_BGR2GRAY);   //二值化处理threshold(grayImage, binImage,     128, 255, CV_THRESH_BINARY); 

下面第二、第三分别是灰度、二值化处理后的结果,可见当原图经过二值化分割后,图像增强明显,明暗分离,更重要的是原本模糊的划痕变得非常清晰,特征非常明显,这对我们下一步提取划痕轮廓从而做进一步的分析带来非常大的方便:

opencv 缺陷检测,人工智能,人工智能经过预处理后,下面我们就要想办法如何判定一件产品是具有划痕或者某种缺陷的,观察上面第三章图片,最直观的区别就是不良的产品中附带黑色长条斑点,如果我们对整个圆区域进行轮廓查找的话,它的轮廓数量应该大于0才对,反之等于0. 但是首先我们要知道如何定位每一个产品的位置,并找出它的轮廓,所以,我们先对每一张预处理后的binImage图像进行轮廓查找:​​​​​​​

//定义轮廓点集vector<vector<Point>> contours;//定义继承关系vector<Vec4i> hierarchy;//进行轮廓查找findContours(binImage,     contours,     hierarchy,     CV_RETR_EXTERNAL,     CV_CHAIN_APPROX_NONE,     Point(0, 0));

注意,在首次查找的时候,我们关心的是整个产品的轮廓,或者产品的质心坐标在哪里,所以我们只需要抓取最外轮廓即可,所以第四个参数我们设置为CV_RETR_EXTERNAL,上面已经解释过了,意为只检查最外围轮廓,目的是为了方面后面从原图中截取产品轮廓。为了方便后面计算,也为了计数方便,我先定义了一个产品类型的结构体myproduct,里面包含外接Rect,质心cx,xy,还有对应索引index. 为了去除重复,每次计算每个轮廓的位置,再根据当前帧里面的所有产品坐标与上一帧图像中产品里面的坐标进行对比,如果有两个产品在上下两帧中偏移的距离很小,那么我们可以认为它是同一件产品,否则就是新出现的产品,就需要放入我们的product容器里面,这其实在实际抓拍检测过程中,比较常用的去重方法:​​​​​​​

for (int i = 0; i < contours.size(); i++){  double area = contourArea(contours[i]);  //小于18000我们认为是干扰因素  if (area > 18000)  {    Moments M = moments(contours[i]);  //计算矩    double center_x = M.m10 / M.m00;    double center_y = M.m01 / M.m00;    Rect rect = boundingRect(contours.at(i));    bool isNew = true;    //必须保证产品完全出来    if (center_x > 100)    {      for (int i = 0; i < product.size(); i++)      {        double h = abs(center_x - product[i].cx);        double v = abs(center_y - product[i].cy);        if(h < 25 && v < 25)        {          isNew = false;          //说明不是新的,那就要更新一下          product[i].cx = center_x;          product[i].cy = center_y;          product[i].rect = rect;        }      }      if (isNew)      {        myproduct p;        p.cx = center_x;        p.cy = center_y;        p.rect = rect;        idx++;        p.index = idx;        product.push_back(p);      }    }  }

函数计算后,product里面就包含了我们所要当前帧中的所有产品对象,包括质心、外接矩形等等,然后根据最大外接矩形的坐标,再回到原图中img中,把这个矩形包含的产品轮廓给裁剪出来,做进一步分析,裁剪的方法很简单,我们根据上面程序返回的rect,直接在原图像img中进行裁剪即可,即可得到右边小图像:

Mat roi = img(rect);

opencv 缺陷检测,人工智能,人工智能

拿到上图右边截取的小图像roi, 对其再做进一步的分析,从而能够抓取到缺陷划痕的轮廓,方法还是先灰度处理再二值化操作,然后查找轮廓。但注意,这次查找轮廓的对象是我们截取的roi区域,为了分析roi区域内所有的缺陷,我们必须要找出对象中的所有轮廓,所以findcontours参数中mode参数我们就不能使用CV_RETR_EXTERNAL了,而要改用CV_RETR_TREE:​​​​​​​

  Mat grayImage;  Mat binImage;  cvtColor(roi, grayImage, CV_BGR2GRAY);  //灰度处理  threshold(grayImage,       binImage,       128, 255,       CV_THRESH_BINARY);  //二值化处理  vector<vector<Point>> contours;  vector<Vec4i> hierarchy;  //检测出roi内所有轮廓  findContours(binImage, contours,       hierarchy,       CV_RETR_TREE,       CV_CHAIN_APPROX_NONE,       Point(0, 0));

这次返回的contours其实还包含单个产品的最外轮廓,显然不是我们想要的,对其进行适当过滤,过滤的方法很简单,还是根据面积来进行判断,进而再把缺陷部分给提取出来,我们可以用下面两行代码,将提取到的轮廓全部绘制出来:​​​​​​​

//最后一个参数如果为负值CV_FILLED则为填充内部//第三个参数如果为-1则绘制所有的轮廓drawContours(roi,   contours,   -1,   Scalar(0, 0, 255), 0);  

opencv 缺陷检测,人工智能,人工智能下一步我们就要想办法把产品内部的一个划痕轮廓给单独提取出来,也就是找一把“剪刀”,将它最大外接矩形给剪切出来,同时为了防止划痕周围颜色的干扰,我们还需要将剩余部分涂成黑色,方法很简单,我们需要单独定义一个mask掩模,再使用fillPoly函数将这块区域填充到我们的mask上面即可。我们看一下这个函数的原型:​​​​​​​

//填充多边形函数void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType = LINE_8, int shift = 0,Point offset = Point());

第一个参数img是输入的参数,也就是我们的mask, 第二个参数是轮廓点数据集,第三个参数为填充的颜色。但是这里边需要注意,第二个参数如果我们直接把上面那张提取轮廓得到的划痕轮廓数据集contours[index]输入进去是不行的,会报错,我尝试了多次,发现可能fillPoly函数第二个参数只接收vector<vector<Point>>类型的数据集,所以我们在使用之前需要把划痕的最大外接矩形使用findContours函数再做一次轮廓查找,得到缺陷轮廓contours_defect,方法跟上面的一样,事先先灰度处理,再阈值分割。​​​​​​​

//定义掩膜,CV_8UC1代表单通道Mat mask = Mat::zeros(grayImage.size(), CV_8UC1);//把缺陷轮廓填充掩膜fillPoly(mask, contours_defect, Scalar(255, 255, 255));

这里面在定义mask的时候,尽量避免使用白色背景,因为我发现在白色背景使用findContours的时候会把整个背景图片的外框也当成一个轮廓,无形之中给我们带来了不必要的麻烦。填充后的mask我们再与原图中的缺陷外接矩形轮廓做位与运算,最终将原图中的缺陷轮廓抠出来:​​​​​​​

//图像按位与运算bitwise_and(grayImage, mask, result);

 opencv 缺陷检测,人工智能,人工智能

上图中第三幅就是我们要的抠图效果,里面的灰色图案就是划痕形状图像背景是纯黑色,为我们下一步分析免去了诸多干扰。

接下来就是如何分析这张缺陷了,并把缺陷类型给标注出来。我们再看一下另外一种缺陷,比如掉漆的缺陷:

opencv 缺陷检测,人工智能,人工智能 

根据肉眼判断,显然左侧的掉漆缺陷背景颜色更黑一点,这是他们两种缺陷的最大区别,所以我们可以采用灰度直方图的算法对其进行分析,从而判断是何种类型。所谓灰度直方图,就是以横坐标为像素的亮度,纵坐标为对应像素的数量,将整张图片对应的像素分布给计算出来,显然,如果是掉漆缺陷的话,它的低亮度像素值(偏向黑色)占的比重更多一些,而如果是划痕的话,整体像素亮度区间会分布的高一些,我们就按照这个方法来定义缺陷的类型。在opencv中计算灰度直方图的算法已经给我们封装好了,我们来看一下函数的原型:​​​​​​​

//计算灰度直方图void calcHist(const Mat* images, //输入图像指针int nimages,  //输入图像的个数const int* channels, //需要统计的第几通道InputArray mask, //掩膜OutputArray hist, //输出的直方图数组int dims, //需要统计直方图通道的个数const int* histSize, //直方图分成区间个数指针const float** ranges, //统计像素值的区间bool uniform = true, //是否对得到的直方图数组进行归一化处理bool accumulate = false); //在多个图像时,是否累计计算像素值得个数

用这个函数计算后,我们需要稍微再加一点分析,将分布直方图对应像素出现的概率给计算出来即可:  whaosoft aiot http://143ai.com ​​​​​​​

MatND hist;//256个,范围是0,255.const int histSize = 256;float range[] = { 0, 255 };const float *ranges[] = { range };const int channels = 0;calcHist(&result, 1, &channels, cv::Mat(), hist, 1, &histSize, &ranges[0]);float *h = (float*)hist.data;double hh[256];double sum = 0;for (int i = 0; i < 256; ++i) {  hh[i] = h[i];  sum += hh[i];}

最后根据出现的概率区间来对缺陷进行类型定义,值得一提的是,下面两个阈值需要根据实际情况进行调整:​​​​​​​

double hist_sum_scratch = 0;double hist_sum_blot = 0;for (int i = 90; i < 135; i++){  hist_sum_scratch += hh[i];}hist_sum_scratch /= sum;for (int i = 15; i < 90; i++){  hist_sum_blot += hh[i];}hist_sum_blot /= sum;int type = 0;if (hist_sum_scratch > 0.1){  type = 1;  //划痕类型}if (hist_sum_blot > 0.3){  type = 2;  //掉漆类型}

好了,上面就是整个项目的检测流程,在这里我们使用的是传统算法,其实在利用传统算法进行缺陷检测基本流程都差不多,最终无非是根据像素的分布的特征进行分类,在实际场景比较单一的情况下使用起来它的鲁棒性还算可以,比如这个视频里面,流水线颜色背景是黑色的,场景模式也比较单一,用起来不会出大问题。但是如果一旦遇到实际场景比较复杂的情况下,传统算法用起来就它的局限性就非常大,举个例子,你敢保证所有的缺陷都是这两种,你敢保证实际生产情况下所有缺陷类型直方图分布严格按照自己规定的阈值进行的?显然实际场景的复杂程度要远远超过我们的所能想到的,这个时候就要用到深度学习算法进行检测了,深度学习算法相比传统算法有诸多优点,诸如它抛开了像素层面的繁琐分析,只要前期数据量够大,它就能适应各种复杂的环境等等。

 文章来源地址https://www.toymoban.com/news/detail-744400.html

到了这里,关于opencv缺陷检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 人工智能安全实验一 入侵检测

    实验         一             项目名称:          入侵检测          一、实验目的    对数据集进行数据处理,使用信息增益方法来选取特征,产生训练集和测试集,并对数据进行归一化,构建模型,并对模型进行训练,得到函数的系数。构建分类器,最大化

    2024年01月22日
    浏览(32)
  • 基于人工智能的苹果成熟度检测

    一、 选题的背景 苹果在采摘期被采摘后,需要工人进行手工对苹果的成熟度进行分类,这耗费了大量的人力与物力,而且相近成熟度难以区分,存在分类颗粒度过粗,分类过程存在较为强烈的主观因素等问题。 在这里,我们提出了基于深度学习的苹果成熟度识别方案,这是

    2024年04月13日
    浏览(45)
  • 人工智能|机器学习——基于机器学习的舌苔检测

    基于深度学习的舌苔检测毕设留档.zip资源-CSDN文库 目前随着人们生活水平的不断提高,对于中医主张的理念越来越认可,对中医的需求也越来越多。在诊断中,中医通过观察人的舌头的舌质、苔质等舌象特征,了解人体内的体质信息从而对症下药。 传统中医的舌诊主要依赖

    2024年02月22日
    浏览(50)
  • 迈向多模态AGI之开放世界目标检测 | 人工智能

    作者: 王斌 谢春宇 冷大炜 引言 目标检测是计算机视觉中的一个非常重要的基础任务,与常见的的图像分类/识别任务不同,目标检测需要模型在给出目标的类别之上,进一步给出目标的位置和大小信息,在CV三大任务(识别、检测、分割)中处于承上启下的关键地位。当前

    2024年02月16日
    浏览(34)
  • 面向人工智能的自动化安全检测与漏洞挖掘

    作者:禅与计算机程序设计艺术 《面向人工智能的自动化安全检测与漏洞挖掘》 1.1. 背景介绍 随着人工智能技术的快速发展,各种网络安全威胁也随之而来。为了保障国家的网络安全,人工智能安全检测与漏洞挖掘技术应运而生。人工智能安全检测与漏洞挖掘技术,可以通

    2024年02月14日
    浏览(37)
  • 人工智能生成文本检测在实践中使用有效性探讨

    人工智能辅助撰写文章的技术现在无处不在!ChatGPT已经解锁了许多基于语言的人工智能应用程序,人工智能在任何类型的内容生成中的使用都已经达到了以前前所未有的高度。 在诸如创意写作之类的工作中,人们被要求创造自己的内容。但是由于人工智能在这些任务中的普及

    2024年02月04日
    浏览(30)
  • 人工智能 - 目标检测:发展历史、技术全解与实战

    本文全面回顾了目标检测技术的演进历程,从早期的滑动窗口和特征提取方法到深度学习的兴起,再到YOLO系列和Transformer的创新应用。通过对各阶段技术的深入分析,展现了计算机视觉领域的发展趋势和未来潜力。 关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架

    2024年02月05日
    浏览(29)
  • 基于深度学习的人工智能安全:威胁检测、攻击防御和安全评估

    作者:禅与计算机程序设计艺术 随着人工智能技术的不断发展,给社会带来的影响越来越大。越来越多的企业和个人都依赖于AI产品或服务,同时也面临着各种各样的安全风险,比如身份验证缺失、数据泄露、恶意软件等。如何保障AI产品及服务的安全,成为当前和未来的重

    2024年02月13日
    浏览(42)
  • 人工智能TensorFlow PyTorch物体分类和目标检测合集【持续更新】

    1. 基于TensorFlow2.3.0的花卉识别 基于TensorFlow2.3.0的花卉识别Android APP设计_基于安卓的花卉识别_lilihewo的博客-CSDN博客 2. 基于TensorFlow2.3.0的垃圾分类 基于TensorFlow2.3.0的垃圾分类Android APP设计_def model_load(img_shape=(224, 224, 3)_lilihewo的博客-CSDN博客   3. 基于TensorFlow2.3.0的果蔬识别系统的

    2024年02月09日
    浏览(37)
  • AI一叶知秋:从目标检测部署浅谈人工智能发展

    笔者写这篇文章也有讨巧之嫌,仅以个人视角分享一些看法,主要从实践部署来谈谈近两年来计算机视觉模型的变化,不过AI是一个宏大的话题,每个人定义的人工智能就不一样,我们先来探讨一下何为人工智能。百度百科中是这样定义的: 人工智能是研究、开发用于模拟、

    2024年02月02日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包