image - Algorithms: Ellipse matching


Keywords:image 


Question: 

I have many images like the following (only white and black):

enter image description here

My final problem is to find well matching ellipses. Unfortunately the real used images are not always that nice like this. They could be deformed a bit, which makes ellipse matching probably harder.

My idea is to find "break points". I markes them in the following picture:

enter image description here

Maybe these points could help to make a matching for the ellipses. The end result should be something like this:

enter image description here

Has someone an idea what algorithm may be used to find these break points? Or even better to make good ellipse matching?

Thank you very much


3 Answers: 

  1. Sample the circumference points

    Just scan your image and select All Black pixels with any White neighbor. You can do this by recoloring the remaining black pixels to any unused color (Blue).

    After whole image is done you can recolor the inside back from unused color (Blue) to white.

  2. form a list of ordered circumference points per cluster/ellipse

    Just scan your image and find first black pixel. Then use A* to order the circumference points and store the path in some array or list pnt[] and handle it as circular array.

  3. Find the "break points"

    They can be detect by peak in the angle between neighbors of found points. something like

    float a0=atan2(pnt[i].y-pnt[i-1].y,pnt[i].x-pnt[i-1].x);
    float a1=atan2(pnt[i+1].y-pnt[i].y,pnt[i+1].x-pnt[i].x);
    float da=fabs(a0-a1); if (da>M_PI) da=2.0*M_PI-da;
    if (da>treshold) pnt[i] is break point;
    

    or use the fact that on break point the slope angle delta change sign:

    float a1=atan2(pnt[i-1].y-pnt[i-2].y,pnt[i-1].x-pnt[i-2].x);
    float a1=atan2(pnt[i  ].y-pnt[i-1].y,pnt[i  ].x-pnt[i-1].x);
    float a2=atan2(pnt[i+1].y-pnt[i  ].y,pnt[i+1].x-pnt[i  ].x);
    float da0=a1-a0; if (da0>M_PI) da0=2.0*M_PI-da0; if (da0<-M_PI) da0=2.0*M_PI+da0;
    float da1=a2-a1; if (da1>M_PI) da1=2.0*M_PI-da1; if (da1<-M_PI) da1=2.0*M_PI+da1;
    if (da0*da1<0.0) pnt[i] is break point;
    
  4. fit ellipses

    so if no break points found you can fit the entire pnt[] as single ellipse. For example Find bounding box. It's center is center of ellipse and its size gives you semi-axises.

    If break points found then first find the bounding box of whole pnt[] to obtain limits for semi-axises and center position area search. Then divide the pnt[] to parts between break points. Handle each part as separate part of ellipse and fit.

    After all the pnt[] parts are fitted check if some ellipses are not the same for example if they are overlapped by another ellipse the they would be divided... So merge the identical ones (or average to enhance precision). Then recolor all pnt[i] points to white, clear the pnt[] list and loop #2 until no more black pixel is found.

  5. how to fit ellipse from selection of points?

    1. algebraically

      use ellipse equation with "evenly" dispersed known points to form system of equations to compute ellipse parameters (x0,y0,rx,ry,angle).

    2. geometrically

      for example if you detect slope 0,90,180 or 270 degrees then you are at semi-axis intersection with circumference. So if you got two such points (one for each semi-axis) that is all you need for fitting (if it is axis-aligned ellipse).

      for non-axis-aligned ellipses you need to have big enough portion of the circumference available. You can exploit the fact that center of bounding box is also the center of ellipse. So if you got the whole ellipse you know also the center. The semi-axises intersections with circumference can be detected with biggest and smallest tangent change. If you got center and two points its all you need. In case you got only partial center (only x, or y coordinate) you can combine with more axis points (find 3 or 4)... or approximate the missing info.

      Also the half H,V lines axis is intersecting ellipse center so it can be used to detect it if not whole ellipse in the pnt[] list.

      non-axis-aligned ellipse fit

    3. approximation search

      You can loop through "all" possible combination of ellipse parameters within limits found in #4 and select the one that is closest to your points. That would be insanely slow of coarse so use binary search like approach something like mine approx class. Also see

      on how it is used for similar fit to yours.

    4. hybrid

      You can combine geometrical and approximation approach. First compute what you can by geometrical approach. And then compute the rest with approximation search. you can also increase precision of the found values.

    In rare case when two ellipses are merged without break point the fitted ellipse will not match your points. So if such case detected you have to subdivide the used points into groups until their fits matches ...

This is what I have in mind with this:

overview

 

You probably need something like this:

Your edge points are simply black pixels with at least one white 4-neighbor.

Unfortunately, though, you say that your ellipses may be “tilted”. Generic ellipses are described by quadratic equations like

x² + Ay² + Bxy + Cx + Dy + E = 0

with B² < 4A (⇒ A > 0). This means that, compared to the circle problem, you don't have 3 dimensions but 5. This causes the Hough transform to be considerably harder. Luckily, your example suggests that you don't need a high resolution.


See also: algorithm for detecting a circle in an image


EDIT

The above idea for an algorithm was too optimistic, at least if applied in a straightforward way. The good news is that it seems that two smart guys (Yonghong Xie and Qiang Ji) have already done the homework for us:

 

I'm not sure I would create my own algorithm. Why not leverage the work other teams have done to figure out all that curve fitting of bitmaps?


INKSCAPE (App Link)

Inkscape is an open source tool which specializes in vector graphics editing with some ability to work with raster (bitmap) parts too.

Here is a link to a starting point for Inkscape's API:

It looks like you can script within Inkscape, or access Inkscape via external scripts.

You also may be able to do something with zero scripting, from the inkscape command line interface:


COREL DRAW (App Link)

Corel Draw is recognized as the premier industry solution for vector graphics, and has some great tools for converting rasterized images into vector images.

Here's a link to their API:

Here's a link to Corel Draw batch image processing (non-script solution):