wrek
wrek

Reputation: 309

Change ginput crosshair appearance - Matlab

How can I change the cross-hair to a circle with the same r (20)?

Code:

clc;
clear;
I = imread('peppers.png');
imshow(I); 
colorCode = [0.6 0.8 0.5] *255;

r=20;
button = 1;
 while sum(button) <=1    
    [x,y,button] = ginput(1)
    I= insertShape(I,'FilledCircle',[x y r],'LineWidth',1, 'Color', colorCode,  'Opacity', 1);
    imshow(I); 
 end

Upvotes: 3

Views: 971

Answers (1)

Yvon
Yvon

Reputation: 2993

I am using Matlab R2015b and I do not know if ginput has been modified since then. In the particular version that I have, ginput has its crosshair code mainly in two functions:

function updateCrossHair(fig, crossHair)
% update cross hair for figure.
gap = 3; % 3 pixel view port between the crosshairs
cp = hgconvertunits(fig, [fig.CurrentPoint 0 0], fig.Units, 'pixels', fig);
cp = cp(1:2);
figPos = hgconvertunits(fig, fig.Position, fig.Units, 'pixels', fig.Parent);
figWidth = figPos(3);
figHeight = figPos(4);

% Early return if point is outside the figure
if cp(1) < gap || cp(2) < gap || cp(1)>figWidth-gap || cp(2)>figHeight-gap
    return
end

set(crossHair, 'Visible', 'on');
thickness = 1; % 1 Pixel thin lines. 
set(crossHair(1), 'Position', [0 cp(2) cp(1)-gap thickness]);
set(crossHair(2), 'Position', [cp(1)+gap cp(2) figWidth-cp(1)-gap thickness]);
set(crossHair(3), 'Position', [cp(1) 0 thickness cp(2)-gap]);
set(crossHair(4), 'Position', [cp(1) cp(2)+gap thickness figHeight-cp(2)-gap]);
end


function crossHair = createCrossHair(fig)
% Create thin uicontrols with black backgrounds to simulate fullcrosshair pointer.
% 1: horizontal left, 2: horizontal right, 3: vertical bottom, 4: vertical top
for k = 1:4
    crossHair(k) = uicontrol(fig, 'Style', 'text',...
                             'Visible', 'off',...
                             'Units', 'pixels',...
                             'BackgroundColor', [1 0 0],...
                             'HandleVisibility', 'off',...
                             'HitTest', 'off'); %#ok<AGROW>
end

end

It is interesting to see that

  1. People are working around the limit of drawing functions such as insertShape found in a toolbox, which is the fact that the circle is burnt into the image and there is no easy way to "move" it.
  2. An undocumented function hgconvertunits is used to ensure the units are of desired type.

What I have found that can move is annotation. Here is some example code that moves the ellipse following the mouse pointer. Since ginput is not editable, I copied all content into a function, and changed the call to ginput to the new function instead. Below is the modification to ginput.

function updateCrossHair(fig, crossHair)
% update cross hair for figure.
% get current point and positions; take care of units
cp = hgconvertunits(fig, [fig.CurrentPoint 0 0], fig.Units, 'pixels', fig);
figPos = hgconvertunits(fig, fig.Position, fig.Units, 'pixels', fig.Parent);
cp = cp(1:2)./figPos(3:4);
axesPos = fig.Children.Position;
% Early return if point is outside the figure
if cp(1) < axesPos(1) || cp(2) < axesPos(2) || cp(1) > (axesPos(1)+axesPos(3)) || cp(2) > axesPos(2)+axesPos(4)
    return
end

diameter = 10; % pixels
crossHair.Position = [cp-diameter./figPos(3:4)/2, diameter./figPos(3:4)];

end


function crossHair = createCrossHair(fig)
crossHair = annotation(fig, 'ellipse', [0,0,0,0]);
crossHair.Color = 'w';
end

There is a potential bug in this method, that is in the end of user input, when enter key is hit, the modified function does not return any x or y value. In fact the function outputs in the while loop are empty matrices.

To avoid crashing, simply add a check after user input, like this:

 while sum(button) <=1    
    [x,y,button] = testf(1) % use modified ginput
    if isempty(x) || isempty(y)
        break
    end
    I= insertShape(I,'FilledCircle',[x y r],'LineWidth',1, 'Color', colorCode,  'Opacity', 1);
    imshow(I); 
 end

Upvotes: 1

Related Questions