Paper circles and frames detection

I am doing a small project where I have to detect glasses obtained from a given image of a paper target. Something similar to the TargetScan app for iPhone.

I use openCV for image processing, and basically I have two parts for this: I need to detect circles from the target (which works very well with the Hough Circle Transform), and the second part is for detecting pictures. I need some ideas on how to detect these snapshots from a given image. Here is an example of an image with circle detection ON (green line for detected circles and red dot for center). What openCV algorithms can be used to detect these shoots? enter image description here

Here is another example image enter image description here

+2
source share
1 answer

Algo:

  • create / clear image mask
  • binarize the image (black and white with a certain intensity threshold)
  • handle all pixels
  • count the number of pixels of the same color in the x,y directions

    name it wx,wy

  • detection of a circle, shot and middle part

    circles are thin, so wx or wy should be less than a thin threshold, and the other should be larger. The shots are large, so the stand wx and wy should be in the range of shot diameters. The middle section is black and the stand wx,wy above all threshold values ​​(here you can calculate avg). Save this information in a mask

  • re-color image with mask information

  • computer center and circle radii from found points

    center - the midpoint of the middle area, now process all green points and calculate the radius for it. Make a histogram for all the radii found and sort it in descending order. The counter must correspond to 2*PI*r , if you do not ignore such points.

  • group shots together

    therefore, segmentation or pouring of the fill repeats each hit to avoid multiple accounting for a single shot

I encoded # 1 .. # 6 for fun in C ++, here is the code:

  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[yi][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][xi].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); 

I use my own image class for images, so some members:


xs,ys image size in pixels
p[y][x].dd - pixel at position (x,y) as a 32-bit integer type
clear(color) - clears the entire image
resize(xs,ys) - resize the image in a new resolution

This is a repainted result.

example

  • green - thin circles
  • blue middle part
  • red cross (center of circles)
  • red - pictures

since you can see that he needs further processing with bullets # 7, # 8, and also your image does not have any picture outside the middle part, so some adjustment may be required to detect a shot outside the middle part.

[edit1] radiuses

 // 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; 

radius circles

circles found in Magenta ... pretty good, I think. The middle part is screwed in a little. You can calculate the average radius step and interpolate the missing circles ...

+3
source

Source: https://habr.com/ru/post/1262276/


All Articles