For some reason, the following code only displays the masked image with roi at 10,10 with height and width 100,100. These are the initial values. It seems the image does not update even after the getPosition function. Could anyone explain this issue?
`I = imread('/Users/imageuser/Documents/PT300.tif');
h = imshow(I);
% define circular roi by square bounding box
x = 10;
y = 10;
d1 = 100;
d2 = 100;
e = imellipse(gca, [x y d1 d2]);
% roi can be interactively moved/adjusted
% do not close figure window before createMask is called
%%% these lines are only needed if you move or resize the roi
pos = getPosition(e);
x = pos(1);
y = pos(2);
d1 = pos(3);
d2 = pos(4);
%%%
BW = createMask(e,h);
pause;
imshow(BW);`
You need to put those lines (note I inverted their order):
pause;
BW = createMask(e,h);
before calling getPosition, otherwise the new position is not updated.
Whole code:
clear
clc
close all
I = imread('coins.png');
h = imshow(I);
% define circular roi by square bounding box
x = 10;
y = 10;
d1 = 100;
d2 = 100;
e = imellipse(gca, [x y d1 d2]);
pause;
BW = createMask(e,h);
% roi can be interactively moved/adjusted
% do not close figure window before createMask is called
%%% these lines are only needed if you move or resize the roi
pos = getPosition(e)
x = pos(1);
y = pos(2);
d1 = pos(3);
d2 = pos(4);
%%%
figure
imshow(BW);
sample output after dragging the ROI:
Yay!
Note: As mentioned by juicestain, instead of using pause to halt execution of the program while the user is done creating the GUI, you can use wait to wait until the user double-clicks on the ROI object instead of having to press a key as with the pause command.
Therefore, you could replace the call to pause with a call to wait(e).
Related
I have a 3D figure in Matlab, let's assume it's sphere. What I need, is to get the X, Y, Z values of the point on surface, that I click with the mouse.
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
hold on
clicked_point = [?,?,?];
So in this example I want the clicked_point to be equal to [-3.445,-7.32,5.878].
I've tried with such solution:
clear all;
close all;
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
fig = figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
dcm_obj = datacursormode(fig);
set(dcm_obj,'DisplayStyle','datatip',...
'SnapToDataVertex','off','Enable','on')
c_info = getCursorInfo(dcm_obj);
while length(c_info) < 1
datacursormode on
c_info = getCursorInfo(dcm_obj);
end
But after that I can't even click on the sphere to display any data on figure. How can I get X, Y, Z in script? If not, how can I detect that the mouse click has already occured in Matlab?
It is not clear whether you want the clicked_point variable to reside in the base workspace or if that is going to be part of a GUI.
I'll give you a solution for the base workspace.
The trick is to just add the bit of code you need to the UpdateFcn of the datacursormode object.
Save a function getClickedPoint.m somewhere visible on your MATLAB path:
function output_txt = getClickedPoint(obj,event_obj)
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
output_txt = {['X: ',num2str(pos(1),4)],...
['Y: ',num2str(pos(2),4)]};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = ['Z: ',num2str(pos(3),4)];
end
assignin('base','clicked_point',pos)
All this code is actually a copy of the default function used by data cursors. The only modifications are:
I changed the name (obviously you want it to be unique)
I added the last line of code
This last line of code use assignin to transfer the position of the cursor into a variable (named clicked_point) in the base workspace.
Armed with that, keep your code which generate the sphere (although I recommend you change the name of the surface object to something else than sphere as this is a built in MATLAB function), and we just have to modify the datacursormode object to instruct it to use our getClickedPoint function:
[X,Y,Z] = sphere(50);
r = 10 ; X2 = X * r; Y2 = Y * r; Z2 = Z * r;
fig = figure ;
hs = surf(X2,Y2,Z2,'FaceColor','texture','EdgeColor','none','FaceLighting','phong');
axis equal
%% Assign custom update function to dcm
dcm_obj = datacursormode(fig);
set(dcm_obj,'SnapToDataVertex','off','Enable','on','UpdateFcn',#getClickedPoint)
Now the first time you click on the sphere, the variable clicked_point will be created in the workspace with the coordinates of the point. And every time you click again on the sphere the variable will be updated:
If this is to be applied with a GUI, use the same technique but instead of assignin, I would recommend to use the setappdata function. (you can read Share Data Among Callbacks to have details about how this works.)
I'm trying to plot a 3D figure(surf plot) inside a figure that I have already created but for some reason my new plot is created in a separate figure.
The code consist of 2 scripts which I will be posting.
The first script initializes the act frame I want to draw in and its callback (from the slider) draws my cylinder which for some reason appears inside a new frame leading to this mess:
Main script that creates the main figure I want to draw in.
%%
clf;
clear;
close all;
clc;
load('myHeatMap.mat','myHeatMap');
filename = ('C:\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\filenames.txt');
%This line simply gives us a table of all filenames in this file.
T = readtable(filename);
tsize = size(T);
tsize2 = size(T, 1);
filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{1,1}));
map100 = getCylinderHeatMap(filename);
%Figure/parent container (uifigure) properties%
App = uifigure('Scrollable','on','Name','Heatmap Plots','NumberTitle','off');
App_Width = 1000; App_Height = 500;
App.Position = [0 0 App_Width App_Height];
%Slider label (uilabel) properties%
Slider_Label = uilabel('Parent',App);
Slider_Label.Text = "Cylinder Number";
Slider_Label.Position = [25 20 200 100];
%Slider (uislider) properties%
Slider = uislider('Parent',App);
Slider.Limits = [1 1000];
Slider.Value = 1;
Slider_Width = App_Width - 500;
Margin = (App_Width - Slider_Width)/2;
Slider.Position = [Margin 50 Slider_Width 3];
Slider.MajorTicks = (1:100:1000);
Slider.FontSize = 6;
Red = 87; Green = 207; Blue = 220;
Slider.FontColor = [Red/255 Green/255 Blue/255];
%Plot (uiaxes) properties%
Heatmap_Cylinder_Plot = uiaxes('Parent',App);
Heatmap_Cylinder_Plot_X_Position = 100;
Heatmap_Cylinder_Plot_Y_Position = 100;
Heatmap_Cylinder_Plot_Height = 350;
Heatmap_Cylinder_Plot_Width = 400;
Heatmap_Cylinder_Plot.Position = [Heatmap_Cylinder_Plot_X_Position Heatmap_Cylinder_Plot_Y_Position Heatmap_Cylinder_Plot_Width Heatmap_Cylinder_Plot_Height];
Heatmap_Cylinder_Plot.GridColor = [0.15 0.15 0.15];
Heatmap_Cylinder_Plot.XGrid = 'on';
Heatmap_Cylinder_Plot.YGrid = 'on';
Heatmap_Cylinder_Plot.ZGrid = 'on';
%Image (uiimage) properties%
Heatmap_Image = uiimage('Parent',App);
Heatmap_X_Position = (App_Width/2) + 50;
Heatmap_Y_Position = 80;
Heatmap_Height = 350;
Heatmap_Width = 400;
Heatmap_Image.Position = [Heatmap_X_Position Heatmap_Y_Position Heatmap_Height Heatmap_Width];
%Callback function as the slider is moved%
Slider.ValueChangedFcn = #(Slider,event) Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,...
myHeatMap);
%%
%Callback function definition%
function [] = Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,myHeatMap)
Slider.Value = round(Slider.Value);
filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{Slider.Value,1}));
map100 = getCylinderHeatMap(filename);
splitFileName = strsplit(string(T{Slider.Value,1}),'.');
Slider_Label.Text = "Time Stamp: " + splitFileName{1,1};
%Put plotting code here%
plot(Heatmap_Cylinder_Plot,createSurfCylinder(map100));
%Put image plotting code here%
Heatmap_Image.ImageSource = "";
colormap(myHeatMap);
end
%%
Script for drawing actual Cylinder.
function cylinder = createSurfCylinder(matrix)
%Load heat map.
load('myHeatMap.mat','myHeatMap');
%%
%Cylinder creation
Sample_Range = 255 - 0;
Temperature_Range = 450 - 50;
Multiplier = Temperature_Range/Sample_Range;
map100 = matrix.*Multiplier + 50;
%Setting up the figure%
Radius = 1.5;
Number_Of_Data_Points = 360;
theta = linspace(0,2*pi,Number_Of_Data_Points);
%The xy values according to radius and number of points%
Z_Circle = Radius*cos(theta);
Y_Circle = Radius*sin(theta);
map100 = rot90(map100);
Height = 512;
Z_Circle = repmat(Z_Circle,Height,1);
Y_Circle = repmat(Y_Circle,Height,1);
X_Length = (1:512)';
X_Length = repmat(X_Length,1,Number_Of_Data_Points);
figure('Position', [10 10 800 800])
clf;
close;
cyl = surf(X_Length,Y_Circle,Z_Circle,'Cdata',map100);
title("3D Cylinder Heatmap Plot");
zlabel("Z-Position");
ylabel("Y-Position");
xlabel("Length(Cm)");
set(gca,'Ydir','reverse')
colormap(myHeatMap);
colorbar;
shading interp
Maximum_Value = 450;
Minimum_Value = 50;
caxis([Minimum_Value Maximum_Value]);
%Show the image in the subplot and add custome color coding to it.
% subplot(1,3,3); imshow(rot90(map100));
% colormap(myHeatMap);
% caxis([Minimum_Value Maximum_Value]);
cylinder = cyl;
%%
end
Any one that knows how to make may cylinder appear in my original Uiframe?
Any help would be much appreciated.
There are a few things you may want to note. First the closing-commands.
clf close (current) figure
clear clear all variables in the current workspace (this can the the base workspace in scripts or the workspace of the function, in which the command is called)
close all closes all open figure windows
clc clear command window.
Although these are handy commands, the are meant to be used when working in the command window and one should think twice when using them in scripts and never use them in functions. Why so? You might forget that you have used them and consequently, you code behaves unexpected. In particular if you call multiple functions/scripts, which all manipulate the same windows or output.
The command figure opens a new figure window. So every time this command is issued, a new window pops up and is set to "active", i.e. it is automatically the current figure. It returns its specific figure handle if you assign an output to it: fh = figure('Name','Figure A'). If you later what to activate a specific figure, you can call its handle: figure(fh). The function gcf always returns the handle of the current figure.
Now, let's see for example, in function createSurfCylinder, you are calling
figure('Position', [10 10 800 800])
clf;
close;
This opens a figure, closes the current figure (that is the figure you have just opened) and closes the current figure (which is now the one that was open before you opened & closed the last figure...
The plot()-function draws a line into the current axis (if not existing, it opens an axis). It can take as a first input a specific axis handle. The default is gca, which is a function meaning something like get current axis.
So to have all control over your plots, keep track of the handles. I always go like this:
fh1 = struct(); % create an empty struct
fh1.fig = figure('Name','very important figure'); % open figure & keep its handle
fh1.ax = subplot(1,1,1); % this opens a single axis & I keep the handle
% plot
plot( fh.ax, [1,10],[2,5])
ylabel( fh.ax, 'Amplitude Y / unit')
xlabel( fh.ax, 'Measure of time x / unit')
With the command subplot one can arrange multiple axes in one figure (here you need to be aware of the difference between a figure and an axis, and why there are two different types of handles). For example
fh2 = struct(); % create a new empty struct
fh2.fig = figure('Name','Multiple axes in one figure'); % open figure & keep its handle
fh2.ax = cell(3,1);
fh2.ax{1} = subplot(2,2,1); % this opens a single axis & keeps the handle
fh2.ax{2} = subplot(2,2,2); % this opens a single axis & keeps the handle
fh2.ax{3} = subplot(2,2,3:4); % this opens a single axis & keeps the handle
% do plotting with your axis-handles
(yes, I usually first open all axes and than fill them with graphs/lines)
How can I resize my axes on a matlab GUI to fit exactly with the size of the image I just resized?
I have this:
I = imread('honolulu.png');
I = imresize(im2double(I), [600, 700]);
After that I am drawing a grid on the pictures, but because the axes size is different the grid does not look good. However, if I create a figure and I do it on a figure outside the GUI it looks perfect.
Full code:
%Load map
I = imread('honolulu.png');
%Resize image to be multiple of 50 in each axis.
I = imresize(im2double(I), [600, 700]);
%Draw grid of 50x50 pixels.
I(50:50:end, :, :) = 255;
I(:, 50:50:end, :) = 255;
axes(handles.axes1);
h = handles.axes1;imshow(I);
while (ishandle(h))
try
[x, y] = ginput(1);
catch me
%break loop in case image is closed.
break;
end
%Compute top left coordinate of block clicked.
x0 = floor((x-1)/50)*50;
y0 = floor((y-1)/50)*50;
%Set block RGB to random color.
I(y0+1:y0+50-1, x0+1:x0+50-1, 1) = rand();
I(y0+1:y0+50-1, x0+1:x0+50-1, 2) = rand();
I(y0+1:y0+50-1, x0+1:x0+50-1, 3) = rand();
imshow(I);
end
% Choose default command line output for city_planning
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
How it looks vs how it is supposed to look
The lines are disappearing as the plot window changes size - something of an aliasing/rendering issue I guess. Elsewhere other people have asked similar questions without a great answer.
The best I've found is setting the initial magnification to 100% and then preventing resizing. Here's a similar example:
close all;
clear all;
clc;
I = imread('peppers.png');
I = imresize(im2double(I), [600, 700]);
%Draw grid of 50x50 pixels.
I(50:50:end, :, :) = 1;
I(:, 50:50:end, :) = 1;
h = imshow(I,'initialMagnification',100);
set(gcf,'Resize','off')
%%
while (ishandle(h))
try
[x, y] = ginput(1);
catch me
%break loop in case image is closed.
break;
end
%Compute top left coordinate of block clicked.
x0 = floor((x-1)/50)*50;
y0 = floor((y-1)/50)*50;
%Set block RGB to random color.
I(y0+1:y0+50-1, x0+1:x0+50-1, 1) = rand();
I(y0+1:y0+50-1, x0+1:x0+50-1, 2) = rand();
I(y0+1:y0+50-1, x0+1:x0+50-1, 3) = rand();
h = imshow(I);
end
I'm pretty new to different plots in Matlab and I'm trying to write a code that will show the flow field around a cylinder in Matlab. I'm at the very start and first of all I want to just make the circle in a rectangular domain (cylinder should not be right in the middle of the field).
So far, I have this set up but I want to know if it's possible to make the cylinder look more circular and less like an oval, especially because the domain is a rectangle and not a square. The points on the circle are correct but I want it to look better. Any tips on this? The code I have at the moment is:
U_i = 20; % Ambient velocity
a = 4; % cylinder radius
c = -a*5; % starting coordinate (x)
b = a*10; % ending coordinate (x)
d = -60; % starting coordinate (y)
e = 60; % ending coordinate (y)
n = a*50; % number of intervals (step size in grid)
[x,y] = meshgrid([c:(b-c)/n:b],[d:(e-d)/n:e]');
for i = 1:length(x)
for k = 1:length(x);
f = sqrt(x(i,k).^2 + y(i,k).^2);
if f < a
x(i,k) = 0;
y(i,k) = 0;
end
end
end
% Definition of polar variables
r = sqrt(x.^2+y.^2);
theta = atan2(y,x);
%% Creation of Streamline function
z = U_i.*r.*(1-a^2./r.^2).*sin(theta);%- G*log(r)/(2*pi);
%% Creation of Figure
m = 100;
s = ones(1,m+1)*a;
t = [0:2*pi/m:2*pi];
%% Streamline plot
contour(x,y,z,50);
hold on
polar(t,s,'-k');
% axis square
title('Stream Lines');
grid off
Suppose we take any image from Internet and then copy or move some part from that image to any other area inside that image the image should show from where that the part is copied / moved and then pasted. By using matlab.
a = imread('obama.jpg');
a = rgb2gray(a);
[x1 y1] = size(a);
b = uint8(imcrop(a, [170 110 200 150]));
[x2 y2] = size(b);
c = uint8(zeros(x1,y1));
for i = 1:x2
for j = 1:y2
c(i+169,j+109) = b(i,j);
end
end
[x3 y3] = size(c)
subplot(1,3,1),imshow(a);
subplot(1,3,2),imshow(b);
subplot(1,3,3),imshow(c);
Code
%%// Input data and params
a = imread('Lenna.png');
a = rgb2gray(a);
src_xy = [300,300]; %% Starting X-Y of the source from where the portion would be cut from
src_dims = [100 100]; %% Dimensions of the portion to be cut
tgt_xy = [200,200]; %% Starting X-Y of the target to where the portion would be put into
%%// Get masks
msrc = false(size(a));
msrc(src_xy(1):src_xy(1)+src_dims(1)-1,src_xy(2):src_xy(2)+src_dims(2)-1)=true;
mtgt = false(size(a));
mtgt(tgt_xy(1):tgt_xy(1)+src_dims(1)-1,tgt_xy(2):tgt_xy(2)+src_dims(2)-1)=true;
%%// If you would like to have a cursor based cut, explore ROIPOLY, GINPUT - e.g. - mask1 = roipoly(a)
mask1 = msrc;
a2 = double(a);
%%// Get crop-mask boundary and dilate it a bit to show it as the "frame" on the original image
a2(imdilate(edge(mask1,'sobel'),strel('disk',2))) = 0;
a2 = uint8(a2);
%%// Display original image with cropped portion being highlighted
figure,imshow(a2);title('Cropped portion highlighted')
figure,imshow(a);title('Original Image')
figure,imshow(mask1);title('Mask that was cropped')
img1 = uint8(bsxfun(#times,double(a),mask1));
figure,imshow(img1);title('Masked portion of image')
%%// Get and display original image with cropped portion being overlayed at the target coordinates
a_final = a;
a_final(mtgt) = a(msrc);
figure,imshow(uint8(a_final));title('Original image with the cut portion being overlayed')
Output
Please note that to use RGB images, you would need to tinker a bit more with the above code.