Matlab: how to avoid ellipses overlapping in image?

前端 未结 3 620
北恋
北恋 2020-12-21 22:35

I\'ve been using a function file [ret]=drawellipse(x,y,a,b,angle,steps,color,img). Calling the function through a script file to draw random ellipses in image.

相关标签:
3条回答
  • 2020-12-21 23:13

    One option is to keep track of all the ellipses already drawn, and to make sure the next set of [x,y,a,b] does not produce a new ellipse which intersects with the existing ones. You can either invoke random numbers until you come up with a set that fulfills the condition, or once you have a set which violates the condition, decrease the values of a and/or b until no intersection occurs.

    0 讨论(0)
  • 2020-12-21 23:18

    Assuming you are drawing the ellipses into a raster graphics image, you could calculate the pixels you would have to draw for an ellipse, check whether these pixels in the image are still of the background color, and draw the ellipse only if the answer is yes, otherwise reject it (because something else, i.e. another ellipse, is in the way) and try other x,y,a and b.

    Alternatively, you could split your image into rectangles (not neccessarily of equal size) and place one ellipse in each of those, picking x,y,a,b such that no ellipse exceeds its rectangle - then the ellipses cannot overlap either, but it depends on how much "randomness" your ellipse placing should have whether this suffices.

    The mathematically rigorous way would be to store x,y,a,b of each drawn ellipse and for each new ellipse, do pairwise checks with each of those whether they have common points by solving a system of two quadratic equations. However, this might be a bit complicated, especially once the angle is not 0.

    Edit in response to the added code: Instead of fixing all x's and y's before the loop, you can determine them inside the loop. Since you know how many ellipses you want, but not how many you have to sample, you need a while loop. The test loop you give may come in handy, but you need to compare all previous ellipses to the one created in the loop iteration, not the first one.

    i=1;
    while (i<=4) %# or length(a), or, more elegantly, some pre-defined max
        x(i) = rand*400; y(i) = rand*400; %# or take x and y as givren and decrease a and b
        %# now, check overlap for given center
        overlap = false;
        for k=1:(i-1)
           overlap = overlap || overlap_ellipses(x(i),y(i),a(i),b(i),angle(i),x(k),y(k),a(k),b(k),angle(k))
        end
        if (~overlap)
            img = drawellipse(x(i),y(i),a(i),b(i),angle(i),steps,color,img);
            i = i+1; %# determine next ellipse
        end %# else x(i) and y(i) will be overwritten in next while loop iteration
    end
    

    Of course, if a and b are fixed, it may happen that no ellipse fits the image dimensions if the already present ones are unfortunately placed, resulting in an infinite loop. Regarding your plan of leaving the center fixed and decreasing the ellipse's size until it fits: where does your overlap_ellipses method come from? Maybe itcan be adapted to return a factor by which one ellipse needs to be shrinked to fit next to the other (and 1 if it fits already)?

    0 讨论(0)
  • 2020-12-21 23:19

    The solution proposed by @arne.b (the first one) is a good way to rasterize non-overlapping ellipses.

    Let me illustrate that idea with an example. I will be extending my previous answer:

    %# color image
    I = imread('pears.png');
    sz = size(I);
    
    %# parameters of ellipses
    num = 7;
    h = zeros(1,num);
    clr = lines(num);             %# color of each ellipse
    x = rand(num,1) .* sz(2);     %# center x-coords
    y = rand(num,1) .* sz(1);     %# center y-coords
    a = rand(num,1) .* 200;       %# major axis length
    b = rand(num,1) .* 200;       %# minor axis length
    angle = rand(num,1) .* 360;   %# angle of rotation
    
    %# label image, used to hold rasterized ellipses
    BW = zeros(sz(1),sz(2));
    
    %# randomly place ellipses one-at-a-time, skip if overlaps previous ones
    figure, imshow(I)
    axis on, hold on
    for i=1:num
        %# ellipse we would like to draw directly on image matrix
        [ex,ey] = calculateEllipse(x(i),y(i), a(i),b(i), angle(i), 100);
    
        %# lets plot the ellipse (overlayed)
        h(i) = plot(ex,ey, 'LineWidth',2, 'Color',clr(i,:));
    
        %# create mask for image pixels inside the ellipse polygon
        mask = poly2mask(ex,ey,sz(1),sz(2));
    
        %# get the perimter of this mask
        mask = bwperim(mask,8);
    
        %# skip if there is an existing overlapping ellipse
        if any( BW(mask)~=0 ), continue, end
    
        %# use the mask to place the ellipse in the label image
        BW(mask) = i;
    end
    hold off
    legend(h, cellstr(num2str((1:num)','Line%d')), 'Location','BestOutside')    %'
    
    %# set pixels corresponding to ellipses using specified colors
    clr = im2uint8(clr);
    II = I;
    for i=1:num
        BW_ind = bsxfun(@plus, find(BW==i), prod(sz(1:2)).*(0:2));
        II(BW_ind) = repmat(clr(i,:), [size(BW_ind,1) 1]);
    end
    figure, imshow(II, 'InitialMagnification',100, 'Border','tight')
    

    all_overlayed_ellipses rasterized_nonoverlapping_ellipses

    Note how the overlap test is performed in the order the ellipses are added, thus after Line1 (blue) and Line2 (green) are drawn, Line3 (red) will be skipped because it overlaps one of the previous ones, and so on for the rest...

    0 讨论(0)
提交回复
热议问题