Updating multiple image axes with a timer - Images always load to new window not addressed one
조회 수: 21 (최근 30일)
이전 댓글 표시
I am currently trying to run a program that shows a progressing series of blocks that are colored to indicate pressure level (this is for a user to see and respond to). The rate of increase is controlled by a timer and colored blocks are loaded images onto axes.
The program actually runs when in debug mode and a break point is placed in the case statement for the function "raisePressure", but when this code is run instead of loading the images into the referenced axes after the first image, the program retrieves a handle to an axis that doesn't exist and simply creates a new window for the output.
Here is the main code of this program, but if necessary I can upload the the rest of the program.
function varargout = PressureMonitor(varargin)
% PRESSUREMONITOR MATLAB code for PressureMonitor.fig
% PRESSUREMONITOR, by itself, creates a new PRESSUREMONITOR or raises the existing
% singleton*.
%
% H = PRESSUREMONITOR returns the handle to a new PRESSUREMONITOR or the handle to
% the existing singleton*.
%
% PRESSUREMONITOR('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in PRESSUREMONITOR.M with the given input arguments.
%
% PRESSUREMONITOR('Property','Value',...) creates a new PRESSUREMONITOR or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before PressureMonitor_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to PressureMonitor_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help PressureMonitor
% Last Modified by GUIDE v2.5 29-Oct-2012 17:23:51
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @PressureMonitor_OpeningFcn, ...
'gui_OutputFcn', @PressureMonitor_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
end
% --- Executes just before PressureMonitor is made visible.
function PressureMonitor_OpeningFcn(hObject, ~, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to PressureMonitor (see VARARGIN)
handles.white = imread('white.png');
handles.red = imread('red.png');
handles.green = imread('green.png');
handles.pressureLevel = 0;
% Choose default command line output for PressureMonitor
handles.output = hObject;
% Setup timer object
handles.guifig = gcf;
handles.timer = timer('Period', 1.0, 'ExecutionMode', 'FixedRate','TimerFcn', {@increment,handles.guifig});%.guifig
guidata(handles.guifig,handles);
% Update handles structure
guidata(hObject, handles);
releasePressure(7,handles);
% UIWAIT makes PressureMonitor wait for user response (see UIRESUME)
% uiwait(handles.figure1);
end
% --- Outputs from this function are returned to the command line.
function varargout = PressureMonitor_OutputFcn(hObject, ~, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% Update handles structure
guidata(hObject, handles);
end
% --- Executes on button press in start.
function start_Callback(hObject, ~, handles)
% hObject handle to start (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
start(handles.timer);
guidata(hObject, handles);
end
% --- Executes on button press in releasePressure.
function releasePressure_Callback(hObject, ~, handles)
% hObject handle to releasePressure (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
prevLevel = handles.pressureLevel;
handles.pressureLevel = releasePressure(handles.pressureLevel,handles);
if(handles.pressureLevel == 0 && prevLevel > 6)
tElapsed = toc(handles.tStart);
disp(tElapsed)
end
% Update handles
guidata(hObject, handles);
end
function nLevel = releasePressure(level,handles)
if(level > 6)
set(handles.guifig,'CurrentAxes',handles.axes1);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes2);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes3);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes4);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes5);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes6);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes7);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes8);
imshow(handles.white);
nLevel = 0;
else
nLevel = level;
end
end
function nLevel = raisePressure(level,handles)
switch level
case 0
axes(handles.axes1);
imshow(handles.green);
nLevel = level + 1;
case 1
axes(handles.axes2);
imshow(handles.green);
nLevel = level + 1;
case 2
axes(handles.axes3);
imshow(handles.green);
nLevel = level + 1;
case 3
axes(handles.axes4);
imshow(handles.green);
nLevel = level + 1;
case 4
axes(handles.axes5);
imshow(handles.green);
nLevel = level + 1;
case 5
axes(handles.axes6);
imshow(handles.green);
nLevel = level + 1;
case 6
axes(handles.axes7);
imshow(handles.red);
nLevel = level + 1;
case 7
set(handles.guifig,'CurrentAxes',handles.axes1);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes2);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes3);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes4);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes5);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes6);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes7);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes8);
imshow(handles.red);
nLevel = level + 1;
otherwise
nLevel = level;
end
gca
end
function increment(~,~,handles)
% handles structure with handles and user data (see GUIDATA)
handle = guidata(handles);
handle.pressureLevel = raisePressure(handle.pressureLevel,handle);
if(handle.pressureLevel == 7)
tic;
handle.tStart = tic;
end
guidata(handles, handle);
end
% --- Executes on button press in stop.
function stop_Callback(hObject, ~, handles)
% hObject handle to stop (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
stop(handles.timer);
guidata(hObject, handles);
end
댓글 수: 0
채택된 답변
Sean de Wolski
2012년 11월 2일
Part 1
The problem is line 67:
% Setup timer object
handles.guifig = gcf; %ME!!!
handles.timer = timer('Period', 1.0, 'ExecutionMode', 'FixedRate','TimerFcn', {@increment,handles.guifig});%.guifig
guidata(handles.guifig,handles);
When you call gcf a new figure is poofed to become the current figure. The reason for this is the GUIDE GUI's Figure's 'HandleVisibility' is set to 'off'. This is the GUIDE default and can be changed in GUIDE->tools->GUI Options.
So now you have a new figure created and you set the GUIDATA to this figure. Axes will be poofed on this figure and the rest explains the behavior you are seeing.
The simplest way to fix this is to set handles.guifig to be handles.figure1'. 'figure1' is the default tag for the gui figure. Of course this is redundant since now you'll have handles.guifig and handles.figure1 both pointing to the same thing. Thus the easiest (and probably best) fix is to rename the figure's tag to guifig in the GUIDE Property inspector. Or you could just go through your code and replace guifig with figure1, both work.
Part 2
As far as what IA was mentioning above with using:
imshow(the_image,'Parent',handles.axes1)
This is definitely a requirement so that imshow does not poof a new axes.
Alternatively, and this is what IA was hinting at, you can just set the 'CData' of the image to be different. For a robust real time application, I would argue that this the right way to do it. The reason for this is that it is faster and cleaner to change the coloring of an image than to delete that image and make a new image. As long as all of the other properties remain the same, we can skip the delete&repeat steps.
To do this, store the image handles in and update the 'CData' as necessary.
Here is a small example that outlines the idea.
hImage = imshow(cat(3,ones(200,400),zeros(200,400,2)));
T = timer('Period',1,'TasksToExecute',10,...
'Timerfcn',@(~,~)set(hImage,'CData',circshift(get(hImage,'CData'),[0 0 1])),...
'StartDelay',1,'ExecutionMode','FixedRate');
start(T);
댓글 수: 0
추가 답변 (2개)
Image Analyst
2012년 10월 30일
편집: Image Analyst
2012년 10월 30일
When does it do that? Only for case 7? If so, try replacing all the
set(handles.guifig,'CurrentAxes',handles.axes1);
with an axes command:
axes(handles.axes1); % or whatever axes you want.
If that doesn't work, then pass the axes into all the imshow's as the 'Parent' property:
imshow(handles.green, 'Parent', handles.axes1);
If even that doesn't work, let us know. I'm working on showing images with a timer (though I've had to set it aside for a few weeks) and there was something bizarre, unexpected, and non intuitive about it. Sean de Wolski was helping me with it and for some reason you have to write to the CDdata property of the axes rather than use imshow() or something weird like that. Sean would know more - maybe he'll respond.
댓글 수: 2
Hannes
2014년 8월 26일
편집: Hannes
2014년 8월 26일
I had a very similar problem until a couple of minutes ago. I am working with timers to refresh multiple axes in my GUI. During the second call to the timer callback function a new figure was unintentionaly created. As usual, the devil is in the details. The specific code in the timer callback function was
ax1 = handles.axes1;
axes(ax1);
plot(ax1,rand,rand);
xTick = str2num(get(gca,'XTickLabel'));
That use of
gca
caused the problem. After I replaced gca by
ax1
the problem was no more. However, I don't understand why gca is not refering to my axes "ax1", since I explicitly called "axes(ax1)" before! Any explanation?
Returning to your problem. At the very end of your function
function nLevel = raisePressure(level,handles)
you are calling gca. Maybe this is causing your problem?
댓글 수: 1
Sean de Wolski
2014년 8월 26일
Because it's 'HandleVisiblity' is 'off' meaning it's hidden and can't be found.
참고 항목
카테고리
Help Center 및 File Exchange에서 Interactive Control and Callbacks에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!