Mac.
Mac.

Reputation: 303

Create a one-sided distance map

I create with this code a black square of zeros with a white vertical line of ones at the middle and I want to create a distance map with respect to this line but only at the left side of the vertical line. How can I do this?

The following code yields a distance map on both sides of the line.

c=zeros(500,500);
c(:,250)=1;
figure, imshow(c)

[D, idx]= bwdist(c,'euclidean')

Upvotes: 1

Views: 169

Answers (2)

Ozcan
Ozcan

Reputation: 726

Actually, this question could have been asked in a different and challenging way. What if I had a different input shape (not a single column line) and what if I wanted to find the distance map in a specific angle interval(not just the left side). Here is my solution. Find the (x,y) coordinates of the input shape and then for each of the pixel find a mask in a specific direction + direction interval. Here is the function.

function mask = directional_mask(im, mainDirection, dirInterval)

% im: BW input image
% mainDirection : mask direction (in degrees)
% dirInterval:  mask direction interval (from dirMask-dirInterval to dirMask+dirInterval)

[Ys, Xs] = find(im);

[sizeX, sizeY] = size(im);

[X, Y] = meshgrid(1:sizeX,1:sizeY);

mask = im * 0;

for i = 1 : numel(Xs)

    refX = Xs(i);
    refY = Ys(i);

    [theta, ~] = cart2pol(X-refX, Y-refY);

    % adding pi/2 so that north angle is 0 degree
    dirmat = wrapTo2Pi(theta + pi/2);
    dirmat = rad2deg(dirmat);

    % upper and lower direction intervals
    thetaUp = mainDirection + dirInterval;
    thetaDown = mainDirection - dirInterval;

    dirmat2 = dirmat(:);

    % finding indices of the angle intervals
    thetas = [thetaUp, thetaDown];
    if thetaUp >= 360
        thetaUp = thetas(1) - 360;
        thetaDown = thetas(2);
        dirmat2((dirmat2>thetaUp) & (dirmat2<thetaDown)) = nan;
    elseif thetaDown < 0
        thetaUp = thetas(1);
        thetaDown = thetas(2) + 360;
        dirmat2((dirmat2>thetaUp) & (dirmat2<thetaDown)) = nan;
    else
        dirmat2((dirmat2>thetaUp) | (dirmat2<thetaDown)) = nan;
    end

    % final mask
    tmp = im*0;
    tmp(~isnan(dirmat2)) = 1;

    mask = mask | tmp;

end

mask = double(mask);

Then let's say I have an input image like the one below and I want to calculate the distance map towards 45 degrees.

im=zeros(100);
for i=35:65; im(i,i)=1; end
im2=imrotate(im,60); im=imresize(im2,size(im)); im=im~=0;

mainDirection = 45;
dirInterval = 5;
[mask] = directional_mask(im, mainDirection, dirInterval);

% original distance map
d = bwdist(im);

% directional distance map
d2 = mask.*d;

figure;
subplot(131); imagesc(mask+2*im), axis image; colorbar; title('Mask + Orig. Input')
subplot(132); imagesc(d), axis image;  colorbar; title('Initial Distance Map')
subplot(133); imagesc(d2), axis image;  colorbar; title('Directional Distance Map')
set(findall(gcf,'-property','FontSize'),'FontSize',16)

enter image description here

Let's say I wanted the distance map towards 180 degrees. Just change the "mainDirection"

mainDirection = 180;

enter image description here

Let's try it on different shapes.

im=zeros(100);
im(40:60,40:60)=1; im2=imrotate(im,30);im=imresize(im2,size(im)); im=im~=0;

mainDirection = 180;
dirInterval = 5;

enter image description here

If you want a mask in a specific direction interval (theta+-interval), just change the "dirInterval". Here is an example

mainDirection = 180;
dirInterval = 30;

enter image description here

In the original question, @Mac wanted to mask the distance map towards the left side. Then:

im=zeros(100); im(:,50)=1;

mainDirection = 270;
dirInterval = 90;

enter image description here

Upvotes: 0

Suever
Suever

Reputation: 65460

You can compute the distance map for the entire image and then just zero-out (or set the values to NaN) the side that you aren't interested in

D = bwdist(c, 'euclidean'); 
D(:,251:end) = NaN;

A more robust way (without hard-coding any columns) would be to modify c before calling bwdist by setting anything to the right of the line to 1 so that the resulting distance for each of those pixels is 0. You could do this by computing the cumulative sum across the rows

D = bwdist(cumsum(c, 2) > 0, 'euclidean');

enter image description here

Upvotes: 2

Related Questions