MATLAB - How to zoom in to mouse position - matlab

have an image that I would like to zoom in/out when I left/Right-click a point on the image but I do not want to do it using the magnifying glass. Basically, I need a script for what I said above. I have come up with the following script but it only zooms in/out to the center not to the position that I click on.
And if you are asking why I am getting the clicked position using ginput the answer is, I am planning to use this script to edit a binary image! I have removed the lines corresponding to the binary image editing part to avoid any confusion.
hFi= figure; imshow(e);
button=0;
while button~=2
% Get the mouse position on the axes (needed for binary image editing) and button number
[y,x,button]=ginput(1);
% Get the mouse position on the figure
position=get(hFi,'CurrentPoint')
% Set 'CurrentPoint' to the mouse position that was just captured
set(hFi,'CurrentPoint',position)
% Determine if it is a zoom-in or zoom-out
if button==1
zoom(2);
elseif button==3
zoom(0.5);
end
end
I think the command set() does not do anything here but I saw someone suggested that in a forum. Sorry if that looks dumb!

I am assuming you have a matrix as you are asking for the y and x values.
In this way a simple answer would be to display a smaller, or a larger range of values.
Let A be your matrix.
A=rand(1000,1000);
figure,
h=imagesc(A)
axis off
axis image
colormap('gray')
A_range=size(A);
A_zoom=1;
while true
[y,x,button]=ginput(1)
A_center=[x,y];
if button==1
A_zoom=A_zoom/2;
elseif button==3
A_zoom=A_zoom*2;
end
axis([max(x-A_range(1)*A_zoom,1), min(x+A_range(1)*A_zoom,A_range(1)), ...
max(y-A_range(2)*A_zoom,1), min(y+A_range(2)*A_zoom,A_range(2))])
end

Alright, after playing around with imshow and reading through the documentation on internet, I finally came up with what I had been looking for. Thanks to everyone who suggested some ideas, especially ASantosRibeiro who gave me the idea of changing the axis limits.
Basically, I used a combination of commands zoom and xlim/ylim. Therefore, the final code would look like:
hFi= figure; h=imshow(e);
button=0;
zlvl=1;
xl = get(gca,'xlim');
xlen = size(e,2);
yl = get(gca,'ylim');
ylen = size(e,1);
while button~=2
% Get the mouse position on the axes (needed for binary image editing) and button number
[y,x,button]=ginput(1);
% Determine if it is a zoom-in or zoom-out
if button==1
zlvl = zlvl*2;
zoom(2);
elseif button==3
zlvl = zlvl/2;
if zlvl<1, zlvl=1; end % No zoom level smaller than 1
zoom(0.5);
end
% Change the axis limits to where the mouse click has occurred
% and make sure that the display window is within the image dimensions
xlimit = [x-xlen/zlvl/2+0.5 x+xlen/zlvl/2+0.5];
if xlimit(1)<0.5, xlimit=[0.5 xlen/zlvl+0.5]; end
if xlimit(2)>0.5+xlen, xlimit=[xlen-xlen/zlvl+0.5 xlen+0.5]; end
xlim(xlimit);
ylimit = [y-ylen/zlvl/2+0.5 y+ylen/zlvl/2+0.5];
if ylimit(1)<=0.5, ylimit=[0.5 ylen/zlvl+0.5]; end
if ylimit(2)>=0.5+ylen, ylimit=[ylen-ylen/zlvl+0.5 ylen+0.5]; end
ylim(ylimit);
end
This code lets you zoom in/out when you use ginput and you need to use imshow to keep the aspect ratio of image fixed. This becomes very helpful when you need to read coordinates of image pixels and zoom in/out as well. It zooms in when the user left-clicks and zooms out when the user left-clicks. If the middle button is clicked the while loop ends. Other buttons can be added to perform desired operations. For example, I added a few lines of code to edit binary images.
I would like to know your thoughts and if there is any way to make this code more efficient.

Related

How to zoom in on figures when I use inputdlg in my code?

First, when I use inputdlg, Matlab does not let me to zoom in on my figure.
Second, when I enter a number using the command and try to convert it to cell using num2cell, I get this error: 'error using cellstr input must be a string'.
This is the piece of code that I am using:
No = cell2mat(inputdlg('Type in number: '));
(this is where I can't zoom in anymore!)
prompt = num2cell(1:2*No);
title = 'Numbers';
answer = inputdlg(prompt,title);
(this is where I get the error!)
Do you have any ideas how I can resolve these issues? I am using Matlab on a Mac system.
To programmatically zoom in or zoom out in a figure, you can use the zoom function.
An example could be:
% Create a Figure
my_fig=figure
% Plot something in the figure
plot(randi(10,10,1))
grid minor
% Get the zoom factor
zoom_factor=str2double(inputdlg('Type in number: '))
% Zoom the axes of the selected factor
zoom(my_fig,zoom_factor)
This will zoom in the plot by the value defined in the inputdlg.
The zoom will be action will be centered in the center of the axes, as it happens when you select the zoom icon in the figure toolbar and click on the centre of the figure.
Also, you can simply call
% Enable zooming
zoom(my_fig,'on')
to enable the zoom, this has the same effect than clicking on the zoom icon on the figure toolbar.
If you want to zoom a particular area of the graph, you can change the values of xlim and ylim.
With respect to the plot created in the example, you can use inputdlg to get the new limits and then update the plot
In this case, you have to input the 4 values in the inputdlg separated by a space (e. g. 2.5 5.5 5.5 7.5)
% Get the axes handle
ax=gca;
% Store the original X anf Y Limit
orig_xlim=ax.XLim;
orig_ylim=ax.YLim;
zoom_factor=inputdlg('Type in new lim: ')
new_lim=str2num(char(zoom_factor))
ax.XLim=[new_lim(1) new_lim(2)];
ax.YLim=[new_lim(3) new_lim(4)];
Having stored the original values of the limits, you zoom out setting back them.

Cropping circles in an image with imfindcircles

I am doing a road sign recognition program in Matlab and I want to recognize circular roadsigns. Therefore I use the matlab function imfindcircles. I would like to crop only the circular roadsigns and to put them in an isolate figure. However, we have other roadsigns on each figure (triangles or squares) but I don't want them. I have no idea how to do this. Here my code :
[im_bw,map] = imread('roadsign.JPG'); %image black and white
S = regionprops(im_bw,'Extrema','Centroid','BoundingBox');
[centers, radii] = imfindcircles(im_bw,[12 40]);
for k = 1:length(S)
im_cercle = imcrop(im_bw, S(k).BoundingBox);
im_cercle = padarray(im_cercle, [20 20]); % put each roadsigns in a small figure
if radii(k) ~= 0 % Error
figure,imshow(im_cercle); title 'Circle spotted'; % Show every circular roadsigns in a figure
else
figure('visible','off'),imshow(im_cercle); title 'wrong raodsign';
end
end
I tried some other conditions with centres and radii but when I execute the code, i get dimension errors or sometimes it shows me a shape which is not a circle. I also tried to do a variable that only sets when he finds a circle, but without results. Can you help me please ?
Thanks in advance.
What you do you expect the output of regionprops to be? It isn't picking out the circles - it's picking out all the "areas" (anything that is a connected area in im_bw). In addition while imfindcircles can find circles that overlap with other things, regionprops will detect overlapping areas as a single object.
On the other hand, you call imfindcircles and then do nothing with the output.
Rather than doing anything with regionprops, just use the values of centers, radii to define a bounding box around each detected circle (optionally with some additional padding), crop that area out of the image and save/display it.

plotting is displayed upside down at MATLAB GUI

I am working on video surveillance on crowd density estimation. I am implementing a corner detection method for this project. However, I have a problem when my code is combined in GUI MATLAB, the display of plotting corner is upside down and it is not overlay on the original image. Here my code on plotting the image in GUI Matlab.
The problem is solved already and here is the correct code:
% Find row,col coords.
[r,c] = find(cim2);
%After getting row and column coordinate, I plot them together in the original image which is
% overlay image and plotting
imshow(inFrame, 'Parent', handles.axes8);
hold on;
p1 = plot([c],[r],'r.');
set(p1, 'Parent', handles.axes8);
Thank you for #Lokesh for his suggestion.
The explanation of your problem is very well given by floris.But here due to lack of full your code we are not able to perform it on our system. you can aslo try for
axis ij
which is some what similar to above answer. you can also try the below code.
imshow(inFrame,'Parent',handles.axes8);
hold on;
p1 = plot([c],[r],'r.');
set(p1,'Parent',handles.axes8);
hope this works for you..let me know about the result..
imshow inverts the Y axis. Conventionally, in image display the top left corner of the screen is (0,0) with i (the first coordinate) running down the screen, and j (the second coordinate) from left to right.
If you want the image axis to look like a conventional plot axis you can do
axis xy
This will "invert" your image, putting 0,0 in the bottom left.

Making a 2D Matlab figure that contains multiple images which start at a given point (x,y)

Problem
I am trying to make a 2D figure in Matlab which consists of multiple images and a graph with plot data (which I could eventually convert into an image too). For these images and graph, I need to be able to specify where they are located in my cartesion coordinate system.
For my specific case, it is sufficient to be able to "tell" Matlab where the left-bottom corner of the image is.
So for the example above. I would need some "trick" to let "bird1.jpg" start at position (a,b), "bird2.jpg" at position (c,d) and my plot at position (e,f) in one Matlab figure.
Solution to problem
Thanks to chappjc I was able to find a solution for my problem. Here is the code I used such that other people can use it in the future too.
figure_color = [.741 .717 .42];
axe_color = [1 1 1];
Screen.fig = figure('units','pixels',...
'name','Parallel projection',...
'menubar','none',...
'numbertitle','off',...
'position',[100 100 650 720],...
'color',figure_color,...
'busyaction','cancel',...
'renderer','opengl');
Screen.axes = axes('units','pix',...
'position',[420 460 200 200],... % (420,460) is the position of the first image
'ycolor',axe_color,...
'xcolor',axe_color,...
'color',axe_color,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','On');
Screen.img = imshow(phantom);
Screen.axes2 = axes('units','pix',...
'position',[0 0 200 200],... % (0,0) is the position of the second image
'ycolor',axe_color,...
'xcolor',axe_color,...
'color',axe_color,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','On');
Screen.img2 = imshow(phantom);
Basically what I do is first creating a (big) figure, and then create a first axe at a certain position in this big picture, and make it the default axe. In this axe I display my first image (made with the phantom function). After that I make a new axe at a another position and make it again the default axe. After I have done that, I place an image there too (the same picture, but you can also use another one if you want). You can also use handles which is the more clean method, as chappjc describes.
Positioning axes in a figure
One approach would be to manipulate the Position property of multiple axes in a figure. To make multiple axes in a figure:
hf = figure;
ha0 = axes('parent',hf,'Position',[x0 y0 w0 h0]);
ha1 = axes('parent',hf,'Position',[x1 y1 w1 h1]);
Then display your images and plots into the axes by specifying the handle (i.e. ha0 or ha1). For example: image(img0,'Parent',ha0) or imshow(img1,'parent',ha1).
Single Large Image
Another approach is to make a single large image and simply display it with image/imshow/etc.
First for the plots, you can use getframe followed by frame2im to get an image in a matrix format.
Next, decide what goes into your combined image and compute the largest box required to circumscribe the images (using their origins and sizes find the largest x and y coordinate), which includes the origin presumably. Use this info to make a blank image (e.g. img = zeros(h,w,3) for and RGB image).

In matlab, how can I zoom in on a plot in my script

I'd like to zoom in on a plot using a script. I'm only interested in horizontally constrained zooming. So I'd like to do something like
p = plot(myData);
z = zoom;
set(z, 'ZoomInToPoints' , [50 100]);
or
p = plot(myData);
myZoom([50, 100]);
So either of these functions would zoom into a plot like when you zoom in with the magnifying glass tool. I only specify two points because I only want to zoom horizontally.
Note, I've already tried to use xlim for this. While it works, it doesn't let me use the command text on my plots, which I need.
Calls to text will fix the text at a specific set of coordinates on the graph. Have you tried updating these after calling xlim?
EDIT: You can always adjust the text position:
x=1:.1:10;
y=sin(.1*x);
plot(x,y)
text(6,.8,'test') %#Sample figure
F=get(0,'children'); %#Figure handle
A=get(F,'Children'); %#Axes handle
T=findobj(A,'Type','text'); %# Text handle
oldxlim=xlim; %#grab the original x limits before zoom
oldpos=get(T,'Position'); %#get the old text position
set(A,'xlim',[5 15]); %#Adjust axes
newxlim=xlim;
newpos=[(oldpos(1)-oldxlim(1))*(diff(newxlim))...
/(diff(oldxlim))+newxlim(1) oldpos(2:end)];
%#interpolate to place the text at the same spot in the axes
set(T,'Position',newpos) %#Finally reset the text position
Not pretty, but it should work. If you have more than one annotation per axes or axes per figure, you can always throw the above code in a loop.
What is the problem with text and xlim? Is this not the type of behavior you want?
plot(1:100,randn(100,1))
text(80,1.5,'text')
set(gca,'XLim',[70 100]) % notice that text stays at same point in "data space" but moves in "axis space"
text(80,1,'text2'); % new text appears in axis space as well
If I'm misunderstanding and you want text to appear at a specific point in your axis space (not the data space that text uses) regardless of how zoomed in you are, you can create another set of axes for your text:
inset_h = axes('position',[0.5 0.5 0.2 0.2])
set(inset_h,'Color','none'); axis off
text(0,0,'text')