基于opencv的纸张表面质量检测算法中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于opencv的纸张表面质量检测算法中相关的知识,希望对你有一定的参考价值。

用c++编程……opencv里面的什么东西可以实现纸张表面质量检测呢?包括(空洞,褶皱,划痕,斑点……)有没有可以模仿的例子呢?……这个算法设计的主要步骤是哪些?

opencv里面是没有那种算法的,它只是提供一些常用的计算函数。具体的算法,由于你的需求比较特殊,相信应该没有现成的瑕疵检测算法,好在你的需求难度应该不大,通过常用的图像识别算法,比如纹理算法(Gabor算法)、SURF算法就可以找到白纸上瑕疵,这些瑕疵都是相当于一张白纸的特征点嘛!基本思想就是借用图像识别、匹配过程的思想——找图像上的特征点。白纸一般是提取不出特征点的,要是提取出来了,那就说明白纸上有东西(洞、褶皱或者异物)。 参考技术A 根据不同的需求来进行不同的处理
1 空洞 这个肯定是像素颜色和周边的不同 建议用阈值分割 然后轮廓检测
2 褶皱 这个褶皱肯定会有梯度的变化 建议检测边缘 再计算褶皱的梯度信息
3 划痕 这个和上一个问题相似 但是也有不同 应该是梯度的方向和强度不同(一个是凹一个是凸)
4 斑点 如果只是点点星星的 opencv里也有很多角点检测算法 比如 surf fast ORB等

但是也不是每个必须独立对应着相应的方法,比如求边缘梯度的时候可以一次性处理处理好多信息。你往下做,还有疑问在这里提问就行,不用另开问题了。追问

老师说用到一种污点算法,具体不清楚。。。还请回答有关这个的吧。

另外我的之前问的有一个关键的是,步骤,,,就是设计程序的步骤。
就是,灰度处理,等等后面的

追答

污点算法?这个具体我不清楚,我觉得污点不也是角点吗?至少也是特征点 keypoints, 都差不多。只要有检测特征点的算法都能检测,而且SURF算法对Blur Block就是污点块比较敏感,可以一试。

步骤嘛!这个我真不应该跟你说的很详细,因为图像处理的基本步骤都差不多,先预处理再滤波形态学然后梯度等,我真心希望你能自己试验一下,比如看一下网上的程序自己学习操作一下什么的。

本回答被提问者采纳

从纸张目标中检测圆圈和镜头

我正在做一个小项目,我必须检测从给定纸张目标图像得分。类似于iPhone的TargetScan应用程序。

我正在使用openCV处理图像,基本上我有两个部分,一个是检测目标中的圆圈(使用Hough Circle变换效果很好),第二部分是检测镜头。我需要一些想法如何从给定图像中检测这些镜头。以下是圆形检测ON的示例图像(检测到圆圈的绿线和中心的红点)。 openCV的哪些算法可用于检测那些枝条?

这是另一个示例图像

答案

东西:

  1. 创建/清除图像掩码
  2. 二值化图像(通过一些强度阈值对黑白图像)
  3. 处理所有像素
  4. 计算在x,y方向上有多少相同颜色的像素 叫它wx,wy
  5. 检测圈子,镜头和中段 圆圈很薄所以wxwy应该小于薄门槛而另一个应该更大。射击比较大所以展位wxwy必须在射击直径范围内。中段是黑色和展位wx,wy高于所有阈值(你可以在这里计算平均点)。将此信息存储到掩码中
  6. 用面具信息重新着色图像
  7. 从找到的点计算圆心和半径 center是中段区域的平均点,现在处理所有绿点并计算半径。对所有找到的半径进行直方图,并按计数降序对其进行排序。如果不忽略这些点,计数应该与2*PI*r一致。
  8. 小组一起拍摄像素 因此分段或洪水填充重新着色每次击中以避免多次计算单次击球

我编写#1 ..#6以获得C ++的乐趣,这里是代码:

    picture pic0,pic1,pic2;
        // pic0 - source
        // pic1 - output
        // pic2 - mask
    int x,y,i,n,wx,wy;
    int r0=3;           // thin curve wide treshod [pixels]
    int r1a=15;         // shot diameter min treshod [pixels]
    int r1b=30;         // shot diameter max treshod [pixels]
    int x0,y0;          // avg point == center
    // init output as source image but in grayscale intensity only
    pic1=pic0;
    pic1.rgb2i();
    // init mask (size of source image)
    pic2.resize(pic0.xs,pic0.ys);
    pic2.clear(0);
    // binarize image and convert back to RGB
    for (y=r0;y<pic1.ys-r0-1;y++)
     for (x=r0;x<pic1.xs-r0-1;x++)
      if (pic1.p[y][x].dd<=500) // Black/White treshold <0,765>
           pic1.p[y][x].dd=0x00000000; // Black in RGB
      else pic1.p[y][x].dd=0x00FFFFFF; // White in RGB
    // process pixels
    x0=0; y0=0; n=0;
    for (y=r1b;y<pic1.ys-r1b-1;y++)
     for (x=r1b;x<pic1.xs-r1b-1;x++)
        {
        wy=1;   // count the same color pixels in column
        for (i=1;i<=r1b;i++) if (pic1.p[y-i][x].dd==pic1.p[y][x].dd) wy++; else break;
        for (i=1;i<=r1b;i++) if (pic1.p[y+i][x].dd==pic1.p[y][x].dd) wy++; else break;
        wx=1;   // count the same color pixels in line
        for (i=1;i<=r1b;i++) if (pic1.p[y][x-i].dd==pic1.p[y][x].dd) wx++; else break;
        for (i=1;i<=r1b;i++) if (pic1.p[y][x+i].dd==pic1.p[y][x].dd) wx++; else break;
        if ((wx<r0)||(wy<r0))       // if thin
         if ((wx>=r0)||(wy>=r0))    // but still line
            {
            pic2.p[y][x].dd=1;      // thin line
            }
        if (pic1.p[y][x].dd==0)     // black
         if ((wx>=r0)&&(wy>=r0))    // and thick in both axises
            {
            pic2.p[y][x].dd=2;      // middle section
            x0+=x; y0+=y; n++;
            }
        if (pic1.p[y][x].dd)        // white (background color)
        if ((wx>r1a)&&(wy>r1a))     // size in range of shot
         if ((wx<r1b)&&(wy<r1b))
            {
            pic2.p[y][x].dd=3;      // shot
            }
        }
     if (n) { x0/=n; y0/=n; }

    // add mask data (recolor) to output image
//  if (0)
    for (y=0;y<pic1.ys;y++)
     for (x=0;x<pic1.xs;x++)
        {
        if (pic2.p[y][x].dd==1) pic1.p[y][x].dd=0x0000FF00; // green thin line
        if (pic2.p[y][x].dd==2) pic1.p[y][x].dd=0x000000FF; // blue midle section
        if (pic2.p[y][x].dd==3) pic1.p[y][x].dd=0x00FF0000; // red shots
        }

    // Center cross
    i=25;
    pic1.bmp->Canvas->Pen->Color=0x0000FF;
    pic1.bmp->Canvas->MoveTo(x0-i,y0);
    pic1.bmp->Canvas->LineTo(x0+i,y0);
    pic1.bmp->Canvas->MoveTo(x0,y0-i);
    pic1.bmp->Canvas->LineTo(x0,y0+i);

我使用自己的图片类图片,所以一些成员是:

xs,ys图像大小(以像素为单位) p[y][x].dd(x,y)位置的像素,为32位整数类型 clear(color) - 清除整个图像 resize(xs,ys) - 将图像调整为新分辨率

这是重新着色的结果

  • 绿色 - 薄圈
  • 蓝色中段
  • 红十字会(圆心)
  • 红色 - 射击

你可以看到它需要从子弹#7,#8进一步处理,而且你的图像在中段以外没有射击所以可能需要在中段以外进行射击检测的一些调整

[edit1]半径

// create & clear radius histogram
n=xs; if (n<ys) n=ys;
int *hist=new int[n];
for (i=0;i<n;i++) hist[i]=0;
// compute histogram
for (y=0;y<pic2.ys;y++)
 for (x=0;x<pic2.xs;x++)
  if (pic2.p[y][x].dd==1)   // thin pixels
    {
    i=sqrt(((x-x0)*(x-x0))+((y-y0)*(y-y0)));
    hist[i]++;
    }
// merge neigbour radiuses
for (i=0;i<n;i++)
 if (hist[i])
    {
    for (x=i;x<n;x++) if (!hist[x]) break;
    for (wx=0,y=i;y<x;y++) { wx+=hist[y]; hist[y]=0; }
    hist[(i+x-1)>>1]=wx; i=x-1;
    }
// draw the valid circles
pic1.bmp->Canvas->Pen->Color=0xFF00FF;  // magenta
pic1.bmp->Canvas->Pen->Width=r0;
pic1.bmp->Canvas->Brush->Style=bsClear;
for (i=0;i<n;i++)
 if (hist[i])
    {
    float a=float(hist[i])/(2.0*M_PI*float(i));
    if ((a>=0.3)&&(a<=2.1))
     pic1.bmp->Canvas->Ellipse(x0-i,y0-i,x0+i,y0+i);
    }
pic1.bmp->Canvas->Brush->Style=bsSolid;
pic1.bmp->Canvas->Pen->Width=1;
delete[] hist;

检测到的圈子都在洋红色......我觉得还不错。中段拧了一下。您可以计算平均半径步长并插入缺失的圆圈......

以上是关于基于opencv的纸张表面质量检测算法中的主要内容,如果未能解决你的问题,请参考以下文章

从纸张目标中检测圆圈和镜头

学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

OpenCV Java 实现票据纸张的四边形边缘检测与提取摆正

检测照片中纸张角落的算法

OpenCV与EmguCV中的图像轮廓提取

缺陷识别基于支持向量机算法实现金属表面缺陷检测