Limit impoly clicks and convert it to a rectangle - Matlab - matlab

I am using impoly as in the script below and I have two questions:
Can I limit the to points clicked (e.g., 5) and close it automatically?
Is there a way convert the impoly to imrect like in the attached image (red box)?
Script:
clc;
clear;
figure, imshow('pout.tif');
hpoly = impoly(gca);

From the documentation of impoly, I don't think it is directly possible. For such custom behaviour, you should probably write your own point picking function.
Several matlab functio ncan help you in this direction.
[x,y] = ginput(n) to pick points
impoint(hparent,x, y) to draw draggable points,
line to draw a the line between points, and the rectangle bounding box.
impoint has a 'PositionConstraintFcn' parameter, that will call a function of yours when the point is moved. You can use it to update the lines draw when the points are moved.
I suggest you to have a main function that handles the point picking (constraining the number of points, etc...), and a "display" function, that calculate the bounding box, draw the lines between points, that you can call when a point is added (in the main function), or when a point is moved (with the 'PositionConstraintFcn'parameter).

Related

Interpolate out of vector range to split image in MATLAB

I have an image, and I'm letting the user draw a line on it to pick a region. Now, I would like to take that line (red line in the attached image) and extend it to get to the ends of the frame from both sides (white line in image).
I tried using interp1 but when I'm trying to get those coordinates on the frame itself, I get NaNs since it's not between the two points that the user picked.
Any suggestions on how to pick those points? Or alternatively, a better way to split the image?

impoly only approximately correct on log-scale axes

When determining points within polygons using MATLAB's inpolygon function, I find that the results are exactly correct for polygons drawn on linear axes but only approximately correct for polygons drawn on log-scale axes. Although my suspicions lean in favor of a MATLAB bug, it's possible I've overlooked something.
The following code reproduces the issue I have been experiencing with other data. The results are shown in the following image (the bottom set of panels are zoomed views of the top panels). One can appreciate that there are unlabeled points inside the polygon and labeled points outside the polygon, neither of which should occur, in the case of a polygon drawn on log-scale axes (right). In contrast, the polygon test is exact for polygons drawn on linear axes (left).
n=2E4;
x(:,1)=rand(n,1); y(:,1)=rand(n,1);
x(:,2)=lognrnd(0.5,0.25,n,1); y(:,2)=lognrnd(0.5,0.25,n,1);
for m=1:2
subplot(1,2,m);
scatter(x(:,m),y(:,m),'.'); hold on;
if(m==2)
set(gca,'xscale','log'); set(gca,'yscale','log');
end
p=impoly(gca);
pc=getPosition(p);
in=inpolygon(x(:,m),y(:,m),pc(:,1),pc(:,2));
scatter(x(in,m),y(in,m),20);
end
I think you missed something: A line in normal scale is not a line in log scale. Your polygons are not properly drawn in the log scale, as you draw 2 points and put them together with a straight line.
Look at the real polygon in log space:
close all
clear
n=2e4;
x(:,1)=rand(n,1); y(:,1)=rand(n,1);
x(:,2)=lognrnd(0.5,0.25,n,1); y(:,2)=lognrnd(0.5,0.25,n,1);
for m=1:2
subplot(1,2,m);
scatter(x(:,m),y(:,m),'.'); hold on;
if(m==2)
set(gca,'xscale','log'); set(gca,'yscale','log');
end
p=impoly(gca);
pc=getPosition(p);
% plot polygon
hold on
for ii=1:size(pc,1)-1
plot(linspace(pc(ii,1),pc(ii+1,1),100),linspace(pc(ii,2),pc(ii+1,2),100),'g')
end
plot(linspace(pc(end,1),pc(1,1),100),linspace(pc(end,2),pc(1,2),100),'g')
in=inpolygon(x(:,m),y(:,m),pc(:,1),pc(:,2));
scatter(x(in,m),y(in,m),20);
end
Look at this zoomed in result (click to enlarge):
This happens because the polygon is defined in euclidean space, and it is defined as points linked by lines. If you want to work in log space, things may get complicated. One way to numerically approximate it is the inverse of what I did for plotting. Create dense enough sampled straight line on log space, convert it to linear space, and define a high vertex polygon with the resulting points. Then use inpolygon.

3D mouse input in matlab/simulink

I want to take input coordinates through mouse in Matlab oR Simulink, there is no built-in facility in Matlab of input of 3D coordinate through mouse device, however the buit-in function ginput can only store 2D coordinates of mouse, is there is any possibility in MATLAB/SIMULINK to input 3D coordinates through mouse device?
If I understand you correctly, you want to get the coordinates (in data space) of the mouse click, when the plot is 3D. That is, you click somewhere in the plot and it returns your current position. I have actually tackled this exact problem before.
The main difficulty with this task--and the other posters have alluded to it--is that you are clicking on a 2D screen. Thus, you cannot specify 3 independent positions on a 2D screen uniquely. Rather, clicking on the screen defines a line segment, normal to the plane of the screen, and any of the 3D points along this line are equally valid. Do you understand why this is the case?
To demonstrate, try this short example in Matlab:
surf(peaks); %draw a sample plot
keydown = 2;
while keydown ~= 0,
disp('Click some where on the figure');
keydown = waitforbuttonpress;
end
currPt = get(gca,'CurrentPoint');
disp(currPt);
You'll observe that currPt is a 2x3 matrix. This defines the start and end points of this line. Let's plot this line now:
hold on;
plot3( currPt(:,1), currPt(:,2), currPt(:,3), 'k-', 'LineWidth', 2);
view(-19,46); %rotate to view this line
So the question is: how to define which point along this line you want to select? Well the answer depends on what type of data you have in the first place. If you have point data, choosing one of your vertices exactly can be tricky, and you might need to do some post-processing of your data (for example, to calculate the closest point in your dataset to the currPt line). If you have patch or surface data (such as this example), this is just the intersection of a line and a plane.
There are some tools on the File Exchange to get 3D points for various datasets. One that I just found is: http://www.mathworks.com/matlabcentral/fileexchange/7594-click3dpoint

MATLAB: Interactive tool to "draw" a Plot?

Do you know a simple way to draw arbitrary splines or lines in a plot-figure? I've got the following figure which I created in powerpoint with more or less arbitrary spline-curve (blue) but I'd like to do the same in MATLAB now because of a better look in the final plot-output.
I'm now wondering if I've got to manually "find" data-values to draw some sort of spline (which looks roughly like the blue one below) myself or if there's maybe a tool where I can simply insert some points into a plot interactively and there's a curve fitted though it to create something similar!?
The green and red lines I can figure out myself (probably also have to plot them manually, do I)?!?
Thanks in advance!
EDIT
Okay I found a way myself doing it in MATLAB to gnerate a nice spline: Use splinetool, then either use an example or import some data and then you can interactively add and delete points until your spline looks roughly like it should. Then file->print to figure and then tools->edit plot! You can then delete everything you don't need, add title, xlabel and ylabel etc. and then export it to latex with e.g. matlab2tikz :-) Very nice stuff!!
According the purpose, print nice plots for the thesis, I have some out-of-Matlab recommendations.
1) plot everything as usual, you get a figure handle and an axes handle
h = figure( ... )
a = gca
2) use the data cursor function of the figure window and interactively insert the base points for your later splines. You can additional points by right-click.
t = linspace(0,2*pi,1000);
[x y] = deal(sin(t),cos(t))
Later you delete the "visual" part of the data tip inside Illustrator/Inkscape, if you just want to keep the anchor point of the vector graphic to snap your splines.
There is also the possibility of custom data tips: Tutorial at Matlab Central
3) I once wrote a function to nicely plot Matlab figures as vector graphic based PDFs. You can specify height, width and how much white margin around you want. You just need to pass figure and axes handle and the name:
function saveFigure( fig_handle, axes_handle, name , height , width , margin)
set(axes_handle,'LooseInset',get(gca,'TightInset'));
set(fig_handle, 'Units','centimeters','PaperUnits','centimeters')
% the last two parameters of 'Position' define the figure size
set(fig_handle,'Position',[-margin -margin width height],...
'PaperPosition',[0 0 width+margin height+margin],...
'PaperSize',[width+margin height+margin],...
'PaperPositionMode','auto',...
'InvertHardcopy', 'on',...
'Renderer','painters'... %recommended if there are no alphamaps
);
saveas(fig_handle,name,'pdf')
end
4) You get a PDF you could directly use for Latex - for use in MS Office use 'emf' (
Enhanced metafile) rather than 'pdf'. Open this file with Adobe Illustrator (preferable as it offers layers) or Inkskape (Open Source).
5) The datatips are recognized as graphical objects, you can catch them and draw a spline on them. For Illustrator I'd recommend to put the spline in another layer than the actual figure. Later you can just swap the figure and give the spline new anchor points. In Inkscape you could use the grouping function to keep everything together.
6) I'd say you save a lot of time over a only-Matlab-solution. Good look!

Rounded corner rectangle coordinate representation

Simple rounded corner rectangle code in Matlab can be written as follows.
rectangle('Position',[0,-1.37/2,3.75,1.37],...
'Curvature',[1],...
'LineWidth',1,'LineStyle','-')
daspect([1,1,1])
How to get the x and y coordinates arrays of this figure?
To get the axes units boundaries, do:
axisUnits = axis(axesHandle) % axesHandle could be gca
axisUnits will be an four elements array, with the following syntax: [xlowlim xhighlim ylowlim yhighlim], it will also contain the zlow and zhigh for 3-D plots.
But I think that is not what you need to know. Checking the matlab documentation for the rectangle properties, we find:
Position four-element vector [x,y,width,height]
Location and size of rectangle. Specifies the location and size of the
rectangle in the data units of the axes. The point defined by x, y
specifies one corner of the rectangle, and width and height define the
size in units along the x- and y-axes respectively.
It is also documented on the rectangle documentation:
rectangle('Position',[x,y,w,h]) draws the rectangle from the point x,y
and having a width of w and a height of h. Specify values in axes data
units.
See if this illustrate what you want. You have an x axis that goes from −100 to 100 and y axis that goes from 5 to 15. Suppose you want to put a rectangle from −30 to −20 in x and 8 to 10 in y.
rectangle('Position',[-30,8,10,2]);
As explained by the comments there appears to be no direct way to query the figure created by rectangle and extract x/y coordinates. On the other hand, I can think of two simple strategies to arrive at coordinates that will closely reproduce the curve generated with rectangle:
(1) Save the figure as an image (say .png) and process the image to extract points corresponding to the curve. Some degree of massaging is necessary but this is relatively straightforward if blunt and I expect the code to be somewhat slow at execution compared to getting data from an axes object.
(2) Write your own code to draw a rectangle with curved edges. While recreating precisely what matlab draws may not be so simple, you may be satisfied with your own version.
Whether you choose one of these approaches boils down to (a) what speed of execution you consider acceptable (b) how closely you need to replicate what rectangle draws on screen (c) whether you have image processing routines, say for reading an image file.
Edit
If you have the image processing toolbox you can arrive at a set of points representing the rectangle as follows:
h=rectangle('Position',[0,-1.37/2,3.75,1.37],...
'Curvature',[1],...
'LineWidth',1,'LineStyle','-')
daspect([1,1,1])
axis off
saveas(gca,'test.png');
im = imread('test.png');
im = rgb2gray(im);
figure, imshow(im)
Note that you will still need to apply a threshold to pick the relevant points from the image and then transform the coordinate system and rearrange the points in order to display properly as a connected set. You'll probably also want to tinker with resolution of the initial image file or apply image processing functions to get a smooth curve.