Search code examples
matlabmatlab-figurematlab-guide

Customize get pixel coordinate function in MATLAB


I ned to create a GUI wich shows an image and the user must be able to perform the following:

1 - Select several points using the mouse;

2 - When the user is done, hit "RETURN"*;

3 - After hiting "RETURN", IF the user wants to edit the one of the points, he/she must click over the desired point and drag it to where he/she wants.

I created this function:

function [x, y] = test(img)

[lin, col] = size(img);
fig = figure('WindowButtonDownFcn', {@func, lin, col}, 'KeyPressFcn', @keyfunc);
imshow(img, []);
% axs = axes('position', [1 col 1 lin]);
set(gca, 'Ydir', 'reverse');
x = [];
y = [];
uiwait(fig);

      function func(src, callback, lin, col)
          seltype = get(fig, 'SelectionType');
          set(gca, 'Ydir', 'reverse');
          if strcmp(seltype, 'normal')
              set(fig, 'Pointer', 'circle');
              cp = get(fig, 'CurrentPoint');
              xinit = cp(1, 1);
              yinit = cp(1, 2);
              x = [x, xinit];
              y = [y, yinit];
              hl = line('XData', xinit, 'YData', yinit, 'color', 'b', 'Marker', '.');
              set(fig, 'WindowButtonMotionFcn', {@moveMouse, lin, col});
              set(fig, 'WindowButtonUpFcn', @mouseRelease);
          end

          function moveMouse(src, callback, lin, col)
              cp = get(fig, 'CurrentPoint');
              xdata = [xinit, cp(1, 1)];
              ydata = [yinit, cp(1, 2)];
              set(hl, 'XData', xdata);
              set(hl, 'YData', ydata);
              drawnow;
          end

          function mouseRelease(src, callback)
              last_selection = get(fig, 'SelectionType');
              if strcmp(last_selection, 'alt')
                  set(fig, 'Pointer', 'arrow');
                  set(fig, 'WindowButtonMotionFcn','');
                  set(fig, 'WindowButtonUpFcn','');
              else
                  return;
              end
          end        
      end

      function keyfunc(src, callback)
          keypressed = get(fig, 'CurrentCharacter');
          if keypressed == 13
              uiresume(fig);
          end
      end

end

Q1 - It can plot the image but the coordinate system has its zero at the top-left edge of the figure. How can I move it to the left-top of the image?

Q2 - How can I implement the item number 3 (IF the user wants to edit the one of the points, he/she must click over the desired point and drag it to where he/she wants)?

Thank you all in advance,


Solution

  • Rather than getting the CurrentPoint of the figure, you'll want to get the CurrentPoint of the axes object.

    cp = get(gca, 'CurrentPoint');
    
    % Then get just the x/y position
    cp = cp(1,1:2);
    

    For the second part of your question about dragging a point. You'll probably want to do something like the following.

    1. Set the ButtonDownFcn for the plot object to trigger a callback function

    2. Within this function find the point on the plot that is closest to the clicked point.

    3. Keep track of this index and set the WindowButtonMotionFcn so that whenever you move the mouse, THAT point is moved to that location.

    4. Set the WindowButtonUpFcn so that when you release the mouse button, the WindowButtonMotionFcn is reset.

    Something like this should give you an idea.

    set(hl, 'ButtonDownFcn', @(src,evnt)clickedLine(src))
    
    
    function clickedLine(src, evnt)     
        cp = get(ancestor(src, 'axes'), 'CurrentPoint');
    
        xdata = get(src, 'XData');
        ydata = get(src, 'YData');
    
        % Find the index of the closest point
        [~, ind] = min((xdata - cp(1,1)).^2 + (ydata - cp(1,2)).^2);
    
    
        hfig = ancestor(src, 'figure');
    
        switch get(hfig, 'SelectionType')
            case 'alt'
                % Right click deletes a point
                xdata(ind) = [];
                ydata(ind) = [];
    
                set(src, 'XData', xdata, 'YData', ydata);
            otherwise
                % Set the WindowMotionFcn callback to track this point
                set(hfig, 'WindowButtonMotionFcn', @(s,e)dragPoint(src,ind), ...
                          'WindowButtonUpFcn', @(s,e)stopDrag(s));
        end
    end
    
    function dragPoint(plt, index)
        xdata = get(plt, 'xdata');
        ydata = get(plt, 'ydata');
    
        % Get the current point
        cp = get(ancestor(plt, 'axes'), 'CurrentPoint');
    
        xdata(index) = cp(1,1);
        ydata(index) = cp(1,2);
    
        % Update the data and refresh
        set(plt, 'XData', xdata, 'YData', ydata);
    
        drawnow
    end
    
    function stopDrag(hfig)
        set(hfig, 'WindowButtonMotionFcn', '', ...
                  'WindowButtonUpFcn', '');
    end