Blog Archive

Monday, January 11, 2016

Finding the points inside an ellipse, a utility function to be used with matlab regionprops




% borrowed the idea from Steve's blog 
% and wrote the function I needed, here is a link to Steve's blog

url = 'http://blogs.mathworks.com/images/steve/2010/rice_binary.png';
bw = imread(url);

dataArray = zeros(size(bw));
dataArray = rand(size(bw));
s = regionprops(bw, 'Orientation', 'MajorAxisLength', ...
    'MinorAxisLength', 'Eccentricity', 'Centroid');
imagesc(bw)
hold on

phi = [0,pi/2, pi, 2*pi*3/4.0];
cosphi = cos(phi);
sinphi = sin(phi);
for k = 1:length(s)
    xbar = s(k).Centroid(1);
    ybar = s(k).Centroid(2);

    a = s(k).MajorAxisLength/2;
    b = s(k).MinorAxisLength/2;

    theta = pi*s(k).Orientation/180;   
    R = [ cos(theta)   sin(theta)
         -sin(theta)   cos(theta)];
    xy = [a*cosphi; b*sinphi];
    xy = R*xy;
    x = xy(1,:) + xbar;
    y = xy(2,:) + ybar;
    plot(x,y,'*g'); 
    [avg, totalElem, jx, jy] = avgInEllipse(xbar, ybar, a, b,...
        s(k).Orientation, bw, dataArray);
    xvec = zeros(jx.size(),1);
    yvec = zeros(jy.size(),1);
    for tt = 0:jx.size()-1
        xvec(tt+1) = jx.elementAt(tt);
        yvec(tt+1) = jy.elementAt(tt);
    end
    plot(xvec, yvec, '.m')
    disp(['total no of interior points :' num2str(totalElem)]);
    disp(['Average :' num2str(avg)]);     
    
end



% this part is directly copied from Steve's blog, I just inserted comments

% create 50 points around the circumference of the unit circle
phi = linspace(0,2*pi,50);
cosphi = cos(phi);
sinphi = sin(phi);

for k = 1:length(s)
    xbar = s(k).Centroid(1);
    ybar = s(k).Centroid(2);
    % get radii of the two circles centered at (0,0)
    a = s(k).MajorAxisLength/2;
    b = s(k).MinorAxisLength/2;
    % convert Orientation angle to radian value
    theta = pi*s(k).Orientation/180;
    
    % rotation matrix
    R = [ cos(theta)   sin(theta)
         -sin(theta)   cos(theta)];
    % a*cosphi gives points on the x-axis of a circle
    % drawn around (0,0) point with a radius of 'a'
    % b*sinphi gives points on the y-axis of a circle
    % drawn around (0,0) point with a radius of 'b'    
    xy = [a*cosphi; b*sinphi];
    % rotate the points to match orientation
    xy = R*xy;
    % translate the points that were generated around (0,0) point
    % to the new center (xbar, ybar) aka centroid
    x = xy(1,:) + xbar;
    y = xy(2,:) + ybar;

    plot(x,y,'r','LineWidth',2);    
end

hold off
Input Image
output image, enclosed points drawn in purple

output image, two elements are zoomed in





function [avg, totalElem, jvector_x, jvector_y] = avgInEllipse(cx, cy, a, b,...
    orientation, bw, dataArray)
    % Author : Mohammad A. Khan
    % =======================  inputs ==========================
    % this function is to be used in conjunction with regionprops
    % cx, cy are the x and y coordinated of the centroid
    % a, b are the 1/2 lengths of the major and minor axes of the 
    % ellipse returned by regionprops, orientation is the orientation
    % returned by regionprops, which is the degree of angle between
    % ellipse's major axis and x-axis, bw is the binary array where
    % elements were detected, it can also be though of the mask array
    % against the dataArray, this dataArray is the actual scalar
    % array on which the averaging over ellipsoidal area is expected
    % ====================  outputs =============================
    % avg is the average over ellipse area calculated from dataArray
    % totalElem is the total number of pixels in ellipse
    % jvector_x, jvector_y are java Vectors of x,y coordinates
    % of all the interior points of the ellipse
    
    jvector_x = java.util.Vector;
    jvector_y = java.util.Vector;    
    phi = [0,pi/2, pi, 2*pi*3/4.0];
    cosphi = cos(phi);
    sinphi = sin(phi);
    theta = pi* orientation/180;   
    R = [ cos(theta)   sin(theta)
         -sin(theta)   cos(theta)];
    % calculate the four end points of major and minor axes 
    xy = [a*cosphi; b*sinphi];
    % generate points on major axis
    xx = ceil(min(xy(1,:))):floor(max(xy(1,:)));
    totalElem = 0;
    sumTotal = 0;
    % for each point on major axis calculate all possible
    % y locations that fall within ellipse
    for i = xx
        proot = [-sqrt((1-i*i/a/a)*b*b), sqrt((1-i*i/a/a)*b*b)];
        yy = real((min(proot))):real((max(proot)));
        xcopy = ones(1,length(yy)).*i;
        % rotate the ellipse that was generated around (0,0) point 
        % to match the oreintation given and translate the ellipse  to the
        % centroid location
        rtxy = R*[xcopy;yy];
        xcor = (rtxy(1,:)+cx);
        ycor = (rtxy(2,:)+cy);
          % establish bound check
        xout1 = find(xcor < 1);
        xout2 = find(xcor > size(bw,2));
        xcor([xout1, xout2]) = [];
        ycor([xout1, xout2]) = [];
        yout1 = find(ycor < 1);
        yout2 = find(ycor > size(bw,1));
        xcor([yout1, yout2]) = [];
        ycor([yout1, yout2]) = [];
        xcor = round(xcor);
        ycor = round(ycor);
        % delete all the points that fall on the background
        % of the binary mask image
        if ~isempty(xcor)
            ii = length(xcor);
            jj = 0;
            while ii  % pseudo condition
                jj = jj + 1;
                if(jj > ii), break; end
                if(bw(ycor(jj),xcor(jj)) < 1)
                    xcor(jj) = [];
                    ycor(jj) = [];
                    ii = ii - 1;
                end            
            end
        end
        if ~isempty(xcor)
            totalElem = totalElem + numel(xcor);
            for ii = 1:length(xcor)
                % xcor has been calculated so far in column direction
                % ycor has been calcuated in row direction
                % remeber graph x direction is actually column direction
                % and graph y direction is row direction 
                sumTotal = sumTotal + dataArray(ycor(ii),xcor(ii));
                jvector_x.addElement(xcor(ii));
                jvector_y.addElement(ycor(ii));
            end
        end
    end
    avg = sumTotal/totalElem;
    totalElem = round(pi*a*b);
end


No comments:

Post a Comment