I need to create a GUI which 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 hitting "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
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.
Set the ButtonDownFcn
for the plot object to trigger a callback function
Within this function find the point on the plot that is closest to the clicked point.
Keep track of this index and set the WindowButtonMotionFcn
so that whenever you move the mouse, THAT point is moved to that location.
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