I have an image opened in an axes object inside a GUIDE MATLAB GUI. I want to be able to update some variables depending in the position of the cursor over the image. My effort in order to achieve it has been to use the following code to set the behavior of the axes:
pointerBehavior.enterFcn = [];
pointerBehavior.exitFcn = [];
pointerBehavior.traverseFcn = #(figHandle, currentPoint)CoordChanger(figHandle,currentPoint, hObject, handles);
iptSetPointerBehavior(handles.axes1, pointerBehavior);
iptPointerManager(gcf);
With the following function:
function CoordChanger(figh, cp, hObject, handles)
handles.output = hObject;
CursorPosition = get(handles.axes1,'CurrentPoint')
guidata(hObject, handles);
However when I look at the CursorPosition value while I’m moving the cursor along the image it always shows the same value. What am I doing wrong? Is there any other way to achieve the same result?
Look at the cp variable inside CoordChanger, you should see the cursor position changing there.
Related
I am attempting to convert a 1x8 array into an image, I know that the resulting image would be tiny. I do that using the following code:
filename = fullfile('/Users/jlmontalvo/Documents/MATLAB/train_data.csv');
T = readtable(filename);
C1 = [];
t = T(1,:);
a = t.Variables;
a(end) = []; %getting rid of the last value
test = getimage(imshow(a, [])); %display image
imwrite(test,'/Users/jlmontalvo/Desktop/hello.png'); %store image
the issue is that the image that MATLAB displays looks like this:
but the one that is actually saved is completely different and looks like this:
Why is this?
getimage gets the data displayed. That is, after
test = getimage(imshow(a, []));
test is identical to a.
You are showing the image with contrast stretch, making the smallest value black and the largest value white. But retrieving the data from those axes does not take any of that into account, it simply returns the displayed data.
Instead, you could stretch the data yourself:
test = double(a);
test = test - min(test(:));
test = test / max(test(:));
I am trying to write a GUI that will allow user to
1) create as many as draggable circles after pushing Add Circle button
I designed the function as below. It inserts fixed sized circles on the image each time I hit 'add' button. I count the push button hit number, too (in case I use it as a loop index)
function Add_Callback(hObject, eventdata, handles)
% hObject handle to Add (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
diameter = 30;
handles.trap = imellipse(gca,[100, 100, diameter, diameter]);
addNewPositionCallback(handles.trap ,#(p) title(mat2str(p,3)));
fcn = makeConstrainToRectFcn('imellipse',get(gca,'XLim'),get(gca,'YLim'));
setFixedAspectRatioMode(handles.trap,'True');
setPositionConstraintFcn(handles.trap,fcn);
wait(handles.trap);
handles.count = handles.count+1
guidata(hObject, handles);
2) drag them to desired positions - It is automatically done by Matlab :)
3) select the active circle (e.g. set_as_Active function) - Here is the problem.
4) delete the one that the user think is unnecessary with a button (e.g. Delete_Circle) or with double click if possible
Since I can not select the active circle, when I hit delete, it deletes the updated handle object and next time it gives error.
delete(handles.trap);
guidata(hObject, handles);
I have used imellipse function to add draggable circles. However, I could not update the positions of the circles and select the desired circle as active. How can I do that?
Thanks for the helps.
I have a 3 dimension matrix of data (a stack of images across a dimension, time for example.
I want to display an image, and have a slider below to navigate across the images.
I wrote a piece of code which works, but it's bulky and kinda ugly I think...I want to write a clean function and so I would like to know if anyone know of a cleaner, nicer way to do it.
Here is my code:
interv = [min max]; % interval for image visualization
imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv);
title('My Title');
xlabel('X (cm)');
ylabel('Y (cm)');
pos = get(gca,'position');
% slider position
Newpos = [pos(1) pos(2)-0.1 pos(3) 0.05];
pp = 1;
% callback slider
S = ['pp=floor(get(gcbo,''value''));imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv));' ...
'set_axes_elasto;title(''My Title'');disp(pp);'];
Mz = size(MyMatrix,3);
% Creating Uicontrol
h = uicontrol('style','slider',...
'units','normalized',...
'position',Newpos,...
'callback',S,...
'min',1,'max',Mz,...
'value',pp,...
'sliderstep',[1/(Mz-1) 10/(Mz-1)]);
Here is a way to do it using a listener object for smooth visualization of your stack. I made up a dummy stack using grayscale variations of the same image (i.e. only 4 frames) but the principle will be the same for your application. Notice that I use imshow to display the images, but using imagesc as you do won't cause any problem.
The code is commented so hopefully this is clear enough. If not please don't hesitate to ask for help!
Code:
function SliderDemo
clc
clear all
NumFrames = 4; %// Check below for dummy 4D matrix/image sequence
hFig = figure('Position',[100 100 500 500],'Units','normalized');
handles.axes1 = axes('Units','normalized','Position',[.2 .2 .6 .6]);
%// Create slider and listener object for smooth visualization
handles.SliderFrame = uicontrol('Style','slider','Position',[60 20 400 50],'Min',1,'Max',NumFrames,'Value',1,'SliderStep',[1/NumFrames 2/NumFrames],'Callback',#XSliderCallback);
handles.SliderxListener = addlistener(handles.SliderFrame,'Value','PostSet',#(s,e) XListenerCallBack);
handles.Text1 = uicontrol('Style','Text','Position',[180 420 60 30],'String','Current frame');
handles.Edit1 = uicontrol('Style','Edit','Position',[250 420 100 30],'String','1');
%// Create dummy image sequence, here 4D sequence of grayscale images.
MyImage = imread('peppers.png');
MyMatrix = cat(4,rgb2gray(MyImage),MyImage(:,:,1),MyImage(:,:,2),MyImage(:,:,3));
%// Use setappdata to store the image stack and in callbacks, use getappdata to retrieve it and use it. Check the docs for the calling syntax.
setappdata(hFig,'MyMatrix',MyMatrix); %// You could use %//setappdata(0,'MyMatrix',MyMatrix) to store in the base workspace.
%// Display 1st frame
imshow(MyMatrix(:,:,:,1))
%// IMPORTANT. Update handles structure.
guidata(hFig,handles);
%// Listener callback, executed when you drag the slider.
function XListenerCallBack
%// Retrieve handles structure. Used to let MATLAB recognize the
%// edit box, slider and all UI components.
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
%// Get current frame
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
%// Display appropriate frame.
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
%// Slider callback; executed when the slider is release or you press
%// the arrows.
function XSliderCallback(~,~)
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
end
The figure looks like this:
Hope that helps!
I've created one image editor window in MATLAB, which includes various operations including brightness, contrast, crop, rotate etc.., In this GUI, each operations has its own function call backs.
My problem is with linking one function with another. if i crop image, then if i change brightness my current code changes brightness of original image rather than cropped image.
similarly at first i if change brightness and then if i crop, my code will crop original image rather than brightened image.
Below code is to change brightness.
function slider2_Callback(hObject, eventdata, handles)
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
b = get(handles.slider2,'value');
j = imadjust(x,[],[],b);
axes(handles.axes1);
imshow(j);
Below code is to crop
function crop_Callback(hObject, eventdata, handles)
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
new = imcrop(x);
axes(handles.axes1);
imshow(new);
Suppose say at first if i crop image, then next step if i change brightness of cropped image later some other operation on above edited image, How can i link one operation with another?
I think it's because you are not updating your handles after changing them, hence the code is still referring to the old handle.
Try guidata(hObject, handles); right after cropping.
Instead of having global variable for the file name, you need to have a global variable for the image. So in each of your callbacks you can manipulate with your image without reading the image every time. Also, you should keep your changes at the end of each call back by setappdata. Thus, your callbacks would be something like this:
function changeimage_Callback(hObject, eventdata, handles)
image = getappdata(0, 'image');
% manipulation on image
% show image
setappdata(0, 'image', image);
If you have one GUI, I think it would be more convenient if you do such a thing with handles. That is, load your image in your GUI and keep it like this:
handles.image = imread(filename);
guidata(hObject, handles);
Then your callbacks would be like this:
function changeimage_Callback(hObject, eventdata, handles)
% manipulation on handles.image
% show handles.image
guidata(hObject, handles);
Instead of loading the original image file to perform your manipulation on, load the image from the figure.
In other words, replace
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
with
x = getimage(handles.axes1);
I didn't test the code but it should fix your problem with a minimal amount of work.
I have a code that loads an image to a plot, draws a rectangle on it an after this saves the image into a png file:
figure('Visible', 'off');
imshow(im)
hold on
for n=1:size(windowCandidates,1)
rectangle('Position',[x,y,w,h],'EdgeColor','g','LineWidth',2)
end
f=getframe;
[img_bound,map]=frame2im(f);
imwrite(img_bound, strcat(directory, 'name.', 'png'));
hold off
How can I do the same without displaying it in a figure? Just modifying it and saving, I dont want the user to see all this process)
Thanks!
You can make a figure invisible with:
figure('Visible', 'off');
And then just write it out as Matlab fig via:
saveas(gcf, 'path/to/filename');
or using the print command to png is this case
print('-dpng', 'path/to/filename');
Similar question with good answers and explanations else where on stackoverflow
Update
Thanks to Steve for pointing to this undocumented matlab function
function so;
close all;
im = imread('cameraman.tif');
hfig = figure('Visible', 'off'), imshow(im, 'Border', 'tight');
for n=1:2
rectangle('Position', [20*n, 20*n, 50, 50], 'EdgeColor', 'g', 'LineWidth', 2)
hold on;
end
F = im2frame(zbuffer_cdata(gcf));
imwrite(F.cdata, 'test.png');
% Function copied from
% http://www.mathworks.com/support/solutions/en/data/1-3NMHJ5/?solution=1
% -3NMHJ5
%
function cdata = zbuffer_cdata(hfig)
% Get CDATA from hardcopy using zbuffer
% Need to have PaperPositionMode be auto
orig_mode = get(hfig, 'PaperPositionMode');
set(hfig, 'PaperPositionMode', 'auto');
cdata = hardcopy(hfig, '-Dzbuffer', '-r0');
% Restore figure to original state
set(hfig, 'PaperPositionMode', orig_mode);