draw 2 pairs of resizable rectangles in matlab - matlab

I have a program that should draw 2 re sizable rectangle in matlab. drawing two resizable is ok, but I want to change size in the same time, I mean when I change size of the first one, the second'size change too. but I don know haw to connect them together. can any body help me?!
thanks.
here is my code:
figure,imshow('image.jpg');
h1 = imrect(gca, [10 10 300 500]);
h2 = imrect(gca, [200 200 400 300]);

To solve this you have to use the addNewPositionCallback.
Write your own function implementing the logic you need. This example sets all rectangles to the same size:
function myPositionFunction(allRects,changed,position)
%iterate over all rectangles
for idx=1:numel(allRects)
%skip the currently changed one
if idx~=changed
%get position, modify it and set it
thisP=allRects(idx).getPosition();
thisP(3:4)=position(3:4);
allRects(idx).setPosition(thisP);
end
end
end
Now the tricky part, how make practical usable callback:
figure
imshow('board.tif')
h1 = imrect(gca, [10 10 20 20]);
h2 = imrect(gca, [20 20 30 30]);
addNewPositionCallback(h1,#(p)myPositionFunction([h1,h2],1,p))
addNewPositionCallback(h2,#(p)myPositionFunction([h1,h2],2,p))
This way your callback is called with:
-first parameter a list of all rectangles (could be extended to more than two)
-second parameter the index of the changed rectangle
-third parameter the new boundaries of the changed rectangle

I see #Daniel has just posted an answer, but here is an alternative solution using addNewPositionCallback as well.
1) First create a function in which you draw a first rectangle, and add the callback:
function Draw2Rect(~)
global h1
A = imread('peppers.png');
imshow(A);
h1 = imrect(gca,[20 20 200 150]);
addNewPositionCallback(h1,#UpdateRect)
2) Then define the anonymous function called by the callback, in which you 1st use findobj in order to find rectangles drawn in the current axes. imrect objects are of the type 'hggroup'. Basically you look for all the rectangles present and as you move the first rectangle previous ones are deleted and a new rectangle is drawn. Here I used a dummy relation between the positions but you get the idea.
function UpdateRect(~)
global h1 % Simpler to use global variables but there are more robust alternatives!
Rect1Pos = getPosition(h1); % Get the position of your rectangle of interest
hRect = findobj(gca,'Type','hggroup'); % Find all rectangle objects
if numel(hRect>1) Once you start changing the first rectangle position, delete others.
delete(hRect(1:end-1))
h2 = imrect(gca,round(Rect1Pos/2));
end
I don't know how to post animated gifs in answers, but here are 2 images showing the 1st rectangle and then the 2 rectangles after moving the first one:
1:
2:
Hope that helps! As noted I used h1 as a global variable to easily pass data between functions, but there are more robust alternatives you can use.

Related

pzmap or pzplot color handle for multiple plots

I am plotting a closed loop poles of a systems using pzmap.m or pzplot.m whichever you prefer. I want to see the movement of poles and zeros as I change a variable depicted by L.
The function does not have a direct handle for color. In the example you can just choose the standard colors but cannot give your own color. Since I have to plot multiple times on the same figure, I create a handle for every iteration in a for loop and use findobj to set the color of the curve. To get the colors I want to have a colorbar. So I use jet to get the color distribution for my graph. But the market size stays the same and I have one ugly looking figure.
MWE:
cb=jet(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
h = findobj(gcf,'type','point'); set(h,'markers',12,'color',cb(i,:));
clear L G CL h
end
grid;
c=colorbar
c.Label.String = 'L'
If you run it you'll see that the size doesn't change and graph looks crazy with the y axis on either side labelled with ticks. I want a proper colorbar from blue to red and the colors distributed properly but can't get it after multiple tries. If I can get less cluttering that would be helpful too.
The are several problems in your code
h = findobj(gcf,'type','point'); The things drawn in the screen are actually of type 'line'!
Every iteration, you catch all the points, modify them an dimdediately after delete the properties with clear.
Additionally, h = findobj(gcf,'type','line'); will not return a single thing, but a set of them, so you need to index through it to set the properties. My modified code working looks like this:
clear;clc
cb=parula(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
end
% lets do this in the end!
% you will have length(L_array)*2 +1 items in h
h = findobj(gca,'type','line');
for jj=2:length(h)
set(h(jj),'MarkerSize',12,'Color',cb(floor(jj/2),:));
end
grid;
colormap(parula); % I am using parula, you can use jet, but I discourage it
c=colorbar;
PD: there are tons of reasons not to use jet!! Use perceptually uniform colormaps please!

Annotation - Enforce a square using imrect

I have a Matlab program that asks the user to draw a rectangle around a human on the scene (I later extract that region using imcrop). I need to enforce the user to draw a square. I am using the imrect function, but I am unable to force a square, nor find documentation on how to do it.
It seems imrect can take a position-constraining function as an input argument. This function is specified as follows:
Whenever the object is moved because
of a mouse drag, the constraint function is called using
the syntax:
constrained_position = fcn(new_position)
Position is a vector of the form [xleft ybottom width height].
So try this:
axis equal %// same sccale on both axes
axis manual %// freeze axes size
h = imrect('PositionConstraintFcn', #(x) [x(1) x(2) min(x(3),x(4))*[1 1]])
The simplest way would be to set the setFixedAspectRatioMode method to true during the rectangle creation, initially drawing a square. (Check here).
Example:
%// Make sure it's initially a square!!
hRect = imrect(gca, [10 10 100 100]);
setFixedAspectRatioMode(hRect,1)
Then no matter how you change the position, it will remain a square. Note, however, that as opposed to Luis' solution the user can't specify the initial placement of the square.

Removing the edge line on a contour plot

I used Matlab to create a polar coordinate and converted it into Cartesian coordinate.
[th,r] = meshgrid((0:0.5:360)*pi/180,0:.02:1);
[X,Y] = pol2cart(th,r);
I get data on this mesh and produce a contourf plot over it.
My problem is that I get a center line in my contourf plot which I would like to remove, could some help me with this
Thank you
If I extend a little bit your example to get something I can plot, I do reproduce the problem:
[th,r] = meshgrid((0:0.5:360)*pi/180,0:.02:1);
[X,Y] = pol2cart(th,r);
Z = sqrt( X.^2 + Y.^2 ) ;
isoLevel = 0:0.1:10 ;
[C ,hc] = contourf(X,Y,Z,isoLevel) ;
The black line at the interface is because the function contourf create patch objects and these objects tend to "close" themselves (they will create a line between the first and last point defined in their profile).
This is easier to observe if you do not complete the definition of your profile over 360 degrees. The picture on the right shows you the same example but with the grid only from 0:350 and with the LineStyle set to :.
As you can see, it is difficult to control how Matlab will actually render this specific profile limit. There are ways to control specific edges of patch objects but in this case it would involve retrieving the handle of each patch object (10 in my case but many more in more complex cases), locating the edge you want to control and basically redefining the patch (each of them). You'd be better off drawing the patches from scratch yourself.
Fortunately, there is a simple ways out of that: Get rid of all the patch edge lines...
but then you may miss your isolines! No problem, just plot them on top of the patches !
You get all your colored patches (with no border) and a set of (iso)lines over which you have full control.
Two easy way to get you patch without lines (i) set the shading to shading flat, or (ii) specify 'EdgeColor','none' in the parameter of the contourf function.
To get your isolines on top, use the sister contour function.
So using the same X,Y and Z data than previously:
isoLevel = 0:0.1:10 ;
[C ,hc] = contourf(X,Y,Z,isoLevel,'EdgeColor','none') ; %// set of patches without border
% shading flat %// use that if you didn't specify ('EdgeColor','none') above
hold on
[C2 ,hc2] = contour(X,Y,Z,isoLevel,'LineColor','k') ; %// now get your isolines
will render:
It's a good idea to store the handle hc2 in case you want to modify your isolines properties (color, style, thicknes etc ...).
Also, specifying the isoline levels is recommended. This way you can make sure both contour and contourf will use the same set of isovalues. It could probably work without this (because the underlying dataset is the same), but personally I always prefer to be explicit and not rely on background calculations.

how can i apply exact dct2 on 8x8 blocks and display them in subplots?

I=imread('ft.jpg');
[a b]=size(I);
figure;imshow(I);
j=rgb2ycbcr(I);
[m n]=size(j);
figure;
imshow(j);
ca=mat2cell(j,8*ones(1,size(j,1)/8),8*ones(1,size(j,2)/8),3);
p = 1;
figure;
figure;
X=ones(m,n,8,8);
for c=1:size(ca,1)
for r=1:size(ca,2)
temp=zeros(8,8,'uint8');
temp(:,:)=X(c,r,:,:);
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
imshow(ca{c,r});
p=p+1;
end
end
the error is:
Error using ==> subplot at 309
Illegal plot number.
Error in ==> project at 22
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
That's because you're not calling subplot properly. It needs p as the parameter for the third argument, not temp. p determines which slot you want to place your figure in. You putting in a doublevector as the third parameter makes no sense. Also, ca contains 8 x 8 pixel blocks, and you'd like to show the DCT of each block. Your current code does not do this. Actually, X is what you're trying to find the DCT of, and it's all ones.... doesn't make much sense.
You probably want to show the DCT of each block inside the figure as well, not ca.... and so you need to do this:
for c=1:size(ca,1)
for r=1:size(ca,2)
temp = double(ca{c,r}); %// Change - cast to double for precision
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),p); %// Change
imshow(temp,[]); %// Change here too
p=p+1;
end
end
Note that I did imshow(temp,[]); so that we can contrast stretch the block so that the minimum value gets mapped to black while the maximum value gets mapped to white. Everything else is a shade of gray in between. Be advised that this doesn't change the image itself. It only changes it for display.
Suggestion
You should read up on my post on how subplot works here: How does subplot work and what is the difference between subplot(121) and subplot(1,2,1) in MATLAB?
Once you read through this post, you'll have a better understanding of how each parameter works for subplot, and how you can display graphs / images in a figure.
Minor Note
Looks like you took that code from this post but you didn't copy and paste properly :) That %// Change comment, as well as the variable name ca looked oddly familiar.

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).