Find the target of archery in the image of different points of view

I am trying to find a way to identify the target of archery and all its rings in a photograph that can be taken from different angles:
enter image description here

My goal is to determine the goal, and then also, when the arrows hit the target, to automatically calculate their score. Assumptions are as follows:

  • The camera position is not fixed and may change
  • The archery target can also move or rotate slightly
  • The target can be of different sizes and have a different number of circles.
  • There may be many holes in the object (sometimes large scratches).

I already tried OpenCV to search for contours, but even with preprocessing (grayscale β†’ blur (-> threshold) β†’ edge detection) I still find some closed contours that are all distracted by arrows or other obstacles (holes) on the target, so it's impossible find a good circular line. Using Hough to find circles doesn't work, as it will give me results when Hough finds only perfect circles, not ellipses.

With image preprocessing, this is my best result:

pre-processed image

I thought about the ellipse and the circle fit, but since I don’t know the radius, position and position of the target, this can be a very difficult task. Another thought was to use pattern recognition, but the position and rotation of the target often change.

Now I have an idea to follow each line in the image to check if it is a curve, and then guess which curves belong together to form a circle / ellipse (ellipse due to perspective). The problem is that the lines can be crossed by arrows or holes at a short distance so that the line is too short to check if it is a curve. With smaller circles on the target, the chance is high that it is not recognized at all. In addition, as you can see, circles 8, 7 and 6 do not have a clear line on the left side.

I think that in order to achieve this, it is not necessary to carry out a perspective correction if I can clearly identify all the rings in the goal.

I searched Google for a long time and found a thesis that is not completely focused on this particular task, and is also too mathematical to understand.

Is it possible to achieve this goal? Could you share with me an idea how to solve this problem? Everything is much appreciated.

I do this in Java, but the programming language is secondary. Please let me know if you need more information.

0
source share
1 answer

for starters see

If you use a standardized target as in the image (by the way, I also use the same for the bow :)), then do not turn off the color. You can select areas of blue red and yellow pixels to facilitate detection. cm:

From this you need to put circles. But since you have a perspective, objects are not circles or ellipses. You have 2 options:

  • Perspective correction

    Use the rectangular area of ​​the lower right table as a marker (or target target). This is a rectangle with a known aspect ratio. so measure it on the image and build a transformation that will change the image so that it becomes a rectangle again. There are many things about this: 3D scene reconstruction , so google / read / implement. The base ones are based only on deformation + scaling.

  • Rough circles on ellipses (not oriented along the axis!)

    so set the ellipses to the edges found instead of circles. It will not be so accurate, but still close enough. cm:

[Edit1] Sorry, I did not have time / mood for a while

Since you could not adapt my approach on your own, this is:

  • remove noise

    you need to repaint your image to remove noise in order to facilitate relaxation ... I convert it to HSV and detect 4 colors (circles + paper) using simple tresholding and repaint the image in 4 colors (circles, paper, background) back to space RGB

    result

  • fill the gaps

    in some temporary image I fill in the blanks in circles created by arrows, etc. Just scan pixels from opposite sides of the image (in each line / line) and stop if you hit the selected color of the circle (you need to switch from the outer circles to the inner one so as not to overwrite the previous ones). Now just fill the space between the two points with the selected circle color. (I start with paper, then blue, red and yellow):

    result

  • you can now use a related approach

    So, find the avg point for each color, i.e. the approximate center of the circle. Then follow the histogram of the radii and select the largest. From here, just pull the lines out of the circle and find where the circle really stops and calculates the elliptical half-axes from it, and also updates the center (which handles perspective distortions). To visually check, I make a cross and a circle for each circle in the image from # 1 :

    result

    As you can see, this is pretty close. If you need an even better match, then type more lines (and not just 90 degrees H, V lines) to get more points and calculate the ellipse algebraically or place it by approximation (second link)

C ++ - code (for an explanation see the first link):

picture pic0,pic1,pic2; // pic0 - source // pic1 - output // pic2 - temp DWORD c0; int x,y,i,j,n,m,r,*hist; int x0,y0,rx,ry; // ellipse const int colors[4]=// color sequence from center { 0x00FFFF00, // RGB yelow 0x00FF0000, // RGB red 0x000080FF, // RGB blue 0x00FFFFFF, // RGB White }; // init output as source image and resize temp to same size pic1=pic0; pic2=pic0; pic2.clear(0); // recolor image (in HSV space -> RGB) to avoid noise and select target pixels pic1.rgb2hsv(); for (y=0;y<pic1.ys;y++) for (x=0;x<pic1.xs;x++) { color c; int h,s,v; c=pic1.p[y][x]; h=c.db[picture::_h]; s=c.db[picture::_s]; v=c.db[picture::_v]; if (v>100) // bright enough pixels? { i=25; // treshold if (abs(h- 40)+abs(s-225)<i) c.dd=colors[0]; // RGB yelow else if (abs(h-250)+abs(s-165)<i) c.dd=colors[1]; // RGB red else if (abs(h-145)+abs(s-215)<i) c.dd=colors[2]; // RGB blue else if (abs(h-145)+abs(s- 10)<i) c.dd=colors[3]; // RGB white else c.dd=0x00000000; // RGB black means unselected pixels } else c.dd=0x00000000; // RGB black pic1.p[y][x]=c; } pic1.save("out0.png"); // fit ellipses: pic1.bmp->Canvas->Pen->Width=3; pic1.bmp->Canvas->Pen->Color=0x0000FF00; pic1.bmp->Canvas->Brush->Style=bsClear; m=(pic1.xs+pic1.ys)*2; hist=new int[m]; if (hist==NULL) return; for (j=3;j>=0;j--) { // select color per pass c0=colors[j]; // fill the gaps with H,V lines into temp pic2 for (y=0;y<pic1.ys;y++) { for (x= 0;(x<pic1.xs)&&(pic1.p[y][x].dd!=c0);x++); x0=x; for (x=pic1.xs-1;(x> x0)&&(pic1.p[y][x].dd!=c0);x--); for (;x0<x;x0++) pic2.p[y][x0].dd=c0; } for (x=0;x<pic1.xs;x++) { for (y= 0;(y<pic1.ys)&&(pic1.p[y][x].dd!=c0);y++); y0=y; for (y=pic1.ys-1;(y> y0)&&(pic1.p[y][x].dd!=c0);y--); for (;y0<y;y0++) pic2.p[y0][x].dd=c0; } if (j==3) continue; // do not continue for border // avg point (possible center) x0=0; y0=0; n=0; for (y=0;y<pic2.ys;y++) for (x=0;x<pic2.xs;x++) if (pic2.p[y][x].dd==c0) { x0+=x; y0+=y; n++; } if (!n) continue; // no points found x0/=n; y0/=n; // center // histogram of radius for (i=0;i<m;i++) hist[i]=0; n=0; for (y=0;y<pic2.ys;y++) for (x=0;x<pic2.xs;x++) if (pic2.p[y][x].dd==c0) { r=sqrt(((x-x0)*(x-x0))+((y-y0)*(y-y0))); n++; hist[r]++; } // select most occurent radius (biggest) for (r=0,i=0;i<m;i++) if (hist[r]<hist[i]) r=i; // cast lines from possible center to find edges (and recompute rx,ry) for (x=x0-r,y=y0;(x>= 0)&&(pic2.p[y][x].dd==c0);x--); rx=x; // scan left for (x=x0+r,y=y0;(x<pic2.xs)&&(pic2.p[y][x].dd==c0);x++); // scan right x0=(rx+x)>>1; rx=(x-rx)>>1; for (x=x0,y=y0-r;(y>= 0)&&(pic2.p[y][x].dd==c0);y--); ry=y; // scan up for (x=x0,y=y0+r;(y<pic2.ys)&&(pic2.p[y][x].dd==c0);y++); // scan down y0=(ry+y)>>1; ry=(y-ry)>>1; i=10; 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); //rx=r; ry=r; pic1.bmp->Canvas->Ellipse(x0-rx,y0-ry,x0+rx,y0+ry); } pic2.save("out1.png"); pic1.save("out2.png"); pic1.bmp->Canvas->Pen->Width=1; pic1.bmp->Canvas->Brush->Style=bsSolid; delete[] hist; 
+1
source

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


All Articles