Search code examples
matlabvectororthogonal

vectors on an image in matlab


how are you? I need help. I read an image and then display it, then click two points on the image say: p1 and p2. Now I want to draw lines (arrows if possible) showing that these are vectors orthogonal to the ground plane. Then draw lines parallel to the y-axis and each of these points say l1 and l2 and finally calculate the shortest distance between these lines. I have gotten the points, drawn the lines but am not sure how to get the distance. Also I have observed that for one line it works fine but for two lines, they are drawn in different locations, I dont know why. I have been trying to do this for about three days but the results I get are far different from what I want. As for some parts am not sure how to do it. Below is the code I have currently. I have also attached an image demonstrating what am trying to achieve. I hope its understandable. I removed the part where I try to get the distance because even if I know that I need four points from these lines to estimate the shortest distance between them, I don't know how to get these points :( - am open to suggestions. [![enter image description here][1]][1]

Thanks for the help. PS. let me know if what am trying to do is impossible. It seemed logical to me though when i set out to do it.

Below is my current code

% Read and display image
i = imread('sample.jpg');
im = i;
f = figure;
imshow(im);
% Get user clicked points
[p1 p2] = getpts(f);
% Draw parallel vertical lines at given pts. parallel to the y-axis/post
hold on;
line([p1(1) p1(1)], get(gca, 'ylim'));
line([p2(1) p2(1)], get(gca, 'ylim'));

% Calculate shortest distance between these two lines 
% - not sure how to proceed with this because as far as i know I need at
% least 4 points to determine where they meet :(


% Draw vector symbols at points
% 1. draw x component arrow/line - parallel to the x-axis of image 
% (or perpendicular to y-axis??) but must be perpendicular to ground plane
  % Slope of current line
    m = (diff(p1)/diff(get(gca, 'ylim')));
    % Slope of new line
    Li = 10 ;
    minv = -1/m;
    line([mean(p1) mean(p1)+Li],[mean(get(gca, 'ylim')) mean(get(gca, 'ylim'))+Li*minv],'Color','r')
% 2. draw y component arrow/line - parallel to the y-axis of image
    % Slope of current line
    m = (diff(p2)/diff(get(gca, 'ylim')));
    % Slope of new line
    Li = 10 ;
    minv = -1/m;
    line([mean(p2) mean(p2)+Li],[mean(get(gca, 'ylim')) mean(get(gca, 'ylim'))+Li*minv],'Color','k')
axis equal;

Solution

  • Please have a look at the documentation of getpts, it returns [X,Y], with Point_i=[X(i), Y(i)].

    Since the two lines are parallel in your case, they do not intersect and d is therefore the x difference of the two selected points. Or was this just a special case?

    A first draft would look like this:

    % Read and display image
    i = imread('Sample.jpg');
    im = i;
    f = figure;
    imshow(im);
    % Get user clicked points
    [X, Y] = getpts(f);
    % Draw parallel vertical lines at given pts. parallel to the y-axis/post
    hold on;
    line([X(1) X(1)], get(gca, 'ylim'));
    line([X(2) X(2)], get(gca, 'ylim'));
    
    d=X(2)-X(1);
    

    For the rest of the code, please be more specific. Since you want to show the normal vector of the picture, do you want to plot the whole thing in a 3D plot?

    EDIT: Regarding the comments, the final code has been modified to show a 2D image in a 3D plot. Further imporvement can be done, but should be rather easy (e.g. have a look at this or this for arrows)

    % Read and display image
    myImg = imread('Sample.jpg');
    f1 = figure;
    imshow(myImg);
    imSize=size(myImg);
    % Get user clicked points
    [X, Y] = getpts(f1);
    xLim=get(gca, 'xlim');
    yLim=get(gca, 'ylim');
    close(f1);
    
    % Draw parallel vertical lines at given pts. parallel to the y-axis/post in the image
    lWidth = 5; %width of line in Pixel, should be odd
    lColor = [255,0,0]; %Linecolor in RGB
    pColor = [0,255,0]; %Pointcolor in RGB
    vColor = [0,0,255]; %Vectorcolor in RGB
    
    % image positions of points in pixel
    xP1=int16((X(1)-xLim(1))/(xLim(2)-xLim(1))*imSize(2));
    xP2=int16((X(2)-xLim(1))/(xLim(2)-xLim(1))*imSize(2));
    yP1=int16((Y(1)-yLim(1))/(yLim(2)-yLim(1))*imSize(1));
    yP2=int16((Y(2)-yLim(1))/(yLim(2)-yLim(1))*imSize(1));
    
    % Draw lines in image
    for xLine = [xP1,xP2]
        for i = max([1,xLine-(lWidth-1)/2]):min([imSize(2),xLine+(lWidth-1)/2])
            for j=1:imSize(1)
                myImg(j,i,1:3)=lColor;
            end
        end
    end
    
    %mark Points
    Points=[[xP1,yP1];[xP2,yP2]];
    for k = 1:2
        Pos=Points(k,:);
        for i = max([1,Pos(1)-(lWidth-1)/2]):min([imSize(2),Pos(1)+(lWidth-1)/2])
            for j = max([1,Pos(2)-(lWidth-1)/2]):min([imSize(1),Pos(2)+(lWidth-1)/2])
                myImg(j,i,1:3)=pColor;
            end
        end
    end
    
    %3D plot - Some rotations required to get a nice axisvalue alignment
    g = hgtransform('Matrix',makehgtform('translate',[0,imSize(1),0])*makehgtform('axisrotate',[0,1,0],pi)*makehgtform('zrotate',pi));
    f2 = image(g,myImg);
    axis([0,imSize(2),0,imSize(1),-0.1,1.1]) %axis range
    view(40,30) %view point
    
    %add normal vectors
    hold on
    r=(lWidth-1)/2;
    [X,Y,Z] = cylinder(r);
    xC1=X+double(xP1);
    xC2=X+double(xP2);
    yC1=imSize(1)-Y-double(yP1);
    yC2=imSize(1)-Y-double(yP2);
    mesh(xC1,yC1,Z,'facecolor',vColor/255,'edgecolor',vColor/255);
    mesh(xC2,yC2,Z,'facecolor',vColor/255,'edgecolor',vColor/255);