How to get waitbar on top of other figures? - matlab

Hi i am using waitbar in a script readAndInitDatabase() which as the name implies reads and initializes image database for further processing.
The problem is this i have used imshow() in this function that is used for displaying the image which is being read, this cause the waitbar to hide behind the figure how can i cause not to let this happen?
I have tried to use set command to set the position of the bar at every iteration but this completely changes the size which i don't want. This is the code for setting the position
parentFolder = ['E:\' ...
'Hand-Gesture\Project\Project_0\' ...
'Images\Database'];
parentFolder = strcat(parentFolder(1:end));
chars = 'abcdefghijklmnopqrstuvwxyz';
h = waitbar(0,'Reading Database Images');
for i = 1:length(chars)
letter = chars(i);
folder = strcat(parentFolder,'\',letter);
read_folder(folder);
waitbar(i/length(chars));
% this code sets the position of waitbar at every iteration
screenSize = get(0,'ScreenSize');
pointsPerPixel = 72/get(0,'ScreenPixelsPerInch');
width = 360 * pointsPerPixel;
height = 75 * pointsPerPixel;
pos = [screenSize(3)/2-width/2 screenSize(4)/2-height/2 width height];
set(h,'Position',pos);
end
close(h);
How do i do this? I want to avoid the set() command if i can, to do this task.

Try
h = waitbar(0,'Reading Database Images','WindowStyle','modal');
Setting the figure property window style to 'modal' keeps the figure in the foreground and eliminates the menu bar (which is already absent in the waitbar anyway).

Related

Dynamically setting a 'targetSize' for centerCropWindow2d()

Following the example from the documentation page of the centerCropWindow2d function, I am trying to dynamically crop an image based on a 'scale' value that is set by the user. In the end, this code would be used in a loop that would scale an image at different increments, and compare the landmarks between them using feature detection and extraction methods.
I wrote some test code to try and isolate 1 instance of this user-specified image cropping,
file = 'frameCropped000001.png';
image = imread(file);
scale = 1.5;
scaled_width = scale * 900;
scaled_height = scale * 635;
target_size = [scaled_width scaled_height];
scale_window = centerCropWindow2d(size(image), target_size);
image2 = imcrop(image, scale_window);
figure;
imshow(image);
figure;
imshow(image2);
but I am met with this error:
Error using centerCropWindow2d (line 30)
Expected input to be integer-valued.
Error in testRIA (line 20)
scale_window = centerCropWindow2d(size(image), target_size);
Is there no way to do use this function the way I explained above? If not, what's the easiest way to "scale" an image without just resizing it [that is, if I scale it by 0.5, the image stays the same size but is zoomed in by 2x].
Thank you in advance.
I didn't take into account that the height and width for some scales would NOT be whole integers. Since Matlab cannot crop images that are inbetween whole pixel numbers, the "Expected input to be integer-valued." popped up.
I solved my issue by using Math.floor() on the 'scaled_width' and 'scaled_height' variables.

Simultaneous interaction with 2 figures in MATLAB GUI

I am writing a GUI in MATLAB (guide) where user will be shown 2 images(both images are positioned side by side in single gui window) from a series of images (but each drifted little bit) and will be allowed to select area of interest.
I want user to select working are in image 1 while simultaneously highlighting the selected area in image 2, so that it is easier to judge whether the feature of interest has drifted out of selected area or not. How to do that?
I am using following answer to select and crop area of interest(just FYI):
crop image with fixed x/y ratio
Here is a way to do it using imrect and its addNewPositionCallback method. Check here for a list of available methods.
In the following figure I create 2 axes. On the left that's the original image and on the right that's the "modified" image. By pressing the pushbutton, imrect is called and the addNewPositionCallback method executes a function, called GetROIPosition that is used to get the position of the rectangle defined by imrect. At the same time, in the 2nd axes, a rectangle is drawn with the same position as that in the 1st axes. To be even more fancy you can use the setConstrainedPosition to force the rectangle to be enclosed in a given axes. I'll let you do it :)
Here is the whole code with 2 screenshots:
function SelectROIs(~)
%clc
clear
close all
%//=========================
%// Create GUI components
hfigure = figure('Position',[300 300 900 600],'Units','Pixels');
handles.axesIm1 = axes('Units','Pixels','Position',[30,100,400 400],'XTick',[],'YTIck',[]);
handles.axesIm2 = axes('Units','Pixels','Position',[460,100,400,400],'XTick',[],'YTIck',[]);
handles.TextaxesIm1 = uicontrol('Style','Text','Position',[190 480 110 20],'String','Original image','FontSize',14);
handles.TextaxesIm2 = uicontrol('Style','Text','Position',[620 480 110 20],'String','Modified image','FontSize',14);
%// Create pushbutton and its callback
handles.SelectROIColoring_pushbutton = uicontrol('Style','pushbutton','Position',[380 500 120 30],'String','Select ROI','FontSize',14,'Callback',#(s,e) SelectROIListCallback);
%// ================================
%/ Read image and create 2nd image by taking median filter
handles.Im = imread('coins.png');
[Height,Width,~] = size(handles.Im);
handles.ModifIm = medfilt2(handles.Im,[3 3]);
imshow(handles.Im,'InitialMagnification','fit','parent',handles.axesIm1);
imshow(handles.ModifIm,'InitialMagnification','fit','parent',handles.axesIm2);
guidata(hfigure,handles);
%%
%// Pushbutton's callback. Create a draggable rectangle in the 1st axes and
%a rectangle in the 2nd axes. Using the addNewPositionCallback method of
%imrect, you can get the position in real time and update that of the
%rectangle.
function SelectROIListCallback(~)
hfindROI = findobj(handles.axesIm1,'Type','imrect');
delete(hfindROI);
hROI = imrect(handles.axesIm1,[Width/4 Height/4 Width/2 Height/2]); % Arbitrary size for initial centered ROI.
axes(handles.axesIm2)
rectangle('Position',[Width/4 Height/4 Width/2 Height/2],'EdgeColor','y','LineWidth',2);
id = addNewPositionCallback(hROI,#(s,e) GetROIPosition(hROI));
end
%// Function to fetch current position of the moving rectangle.
function ROIPos = GetROIPosition(hROI)
ROIPos = round(getPosition(hROI));
axes(handles.axesIm2)
hRect = findobj('Type','rectangle');
delete(hRect)
rectangle('Position',ROIPos,'EdgeColor','y','LineWidth',2);
end
end
The figure after pressing the button:
And after moving the rectangle around:
Yay! Hope that helps! Nota that since you're using GUIDE the syntax of the callbacks will look a bit different but the idea is exactly the same.

Drawing a resizeable box on an image

I'm working on a gui and using GUIDE. It loads and image and has the user draw an ROI around a point (the particle ROI). I would then like to have two sliders for creating a second ROI (the Scan ROI) where the user can use sliders to set the width and height of the second roi and see it updated on the image. The sliders seem to work ok but my gui keeps drawing a new roi on top of the image so it gets messy looking really fast. I would like to remove the user sizeable roi from the image before redrawing it (while still keeping the original particle ROI on the image. I currently do it the following way :
Inside the callback for the setroi size button (this should be for the particel ROI)
handles=guidata(hObject);
particleroiSize=imrect;% - draw a rectagle around the particle to get a meausr eof ROI size
roiPoints=getPosition(particleroiSize); %-get tha parameters fo the rectanlge
partX1 = round(roiPoints(1));
partY1 = round(roiPoints(2));
partX2 = round(partX1 + roiPoints(3));
partY2 = round(partY1 + roiPoints(4)); % these are the ROi positions in pixels
roiHeight = round(roiPoints(3)); % - these are just the ROI width and height
roiWidth = round(roiPoints(4));
handles=guidata(hObject); %_ update all the handles...
handles.partX1=partX1;
handles.partX2=partX2;
handles.partY1=partY1;
handles.partY2=partY2;
handles.roicenterX = (partX1 + round(roiPoints(3))/2);
handles.roicenterY= (partY1 + round(roiPoints(4))/2);
handles.roiHeight = roiHeight;
handles.roiWidth = roiWidth;
current_slice = round(get(handles.Image_Slider,'Value'));
particleImage=handles.Image_Sequence_Data(partY1:partY2,partX1:partX2,current_slice);
handles.particleImage=particleImage;
set(handles.RoiSizeDisplay,'String',strcat('Particle ROI is ',' ',num2str(roiHeight),' ', ' by ',num2str(roiWidth)) );
guidata(hObject,handles);
And then inside the call back for the sliders that set the Scan ROI size I have (this is inside two different sliders one adjusts the width and one the height :
handles=guidata(hObject);
try
delete(handles.ScanArea);
% plus any cleanup code you want
catch
end
WidthValue = get(handles.ScanAreaSliderWidth,'value');
HeightValue = get(handles.ScanAreaSliderHeight,'value');
set(handles.ScanAreaWidthDisplay,'String',strcat('Scan Area Width is ',' ', num2str(WidthValue))); % sets the display..now to do the drawing...
%h = imrect(hparent, position);
%position = [Xmin Ymin Width Heigth];
position = [ round(handles.roicenterX-WidthValue/2) round(handles.roicenterY-HeightValue/2) WidthValue HeightValue];
handles.ScanArea = imrect(handles.Image_Sequence_Plot,position);
%h = imrect(hparent, position)
handles=guidata(hObject);
guidata(hObject, handles);
But it never deletes the scan area ROI and keeps redrawign over it..I thought the try...catch would work but it doens't seem to. Am I making extra copies of the ROI or something? Please help..
Thanks.
If you need to delete the ROI drawn with imrect, you can use findobj to look for rectangle objects (which are of type "hggroup") and delete them:
hfindROI = findobj(gca,'Type','hggroup');
delete(hfindROI)
and that should do it. Since you first draw particleroiSize, which is of the hggroup type as well, you might not want to delete all the outputs from the call to findobj. If there are multiple rectangles in your current axis, then hfindROI will contain multiple entries. As such you might want to delete all of them but the first one, which corresponds to particleroiSize.
I hope i got your question right. If not please ask for clarifications!
Thanks. This worked perfectly except that I had to use
hfindROI = findobj(handles.Image_Sequence_Plot,'Type','hggroup');
delete(hfindROI(1:end-1))
to get rid of everything but the first ROI, so I guessteh hggoup objects are added at the start ? (I thought I would use deleted(hfindROI(2:end)) to delete all but the first. Also, why does hfindROI return a list of numbers? Do they represent the hggroup objects or something like that?
thanks..

How to center text on a line

I would like to have a string of text that's centered on a line. I've tried this:
figure
axis([0,10,0,10])
d = 2.81;
center = 5;
line([center - d,center + d],[5,5])
th = text(center,4.9,'mmmmmmmmmmmmmmmmmmmmmm');
set(th,'HorizontalAlignment','center')
The text is aligned with the line on the right but not on the left. The above image is a screen shot. I did not consistently have this problem in saved versions of the figure.
Is there a way to center text on a line? I am not concerned about resizing the figure right now, but I would like to use the default font.
It seems that it's not possible to position text arbitrarily precise. I tried getting size of text and drawing line and re-positioning text accordingly. More about text properties here.
str1 = 'mmmmmmmmmmmmmmmmmmmmmm';
center = 5;
text_line_spacing = 0.2;
figure
axis([0,10,0,10])
% Set text initialy
th = text(0,0,str1);
% Get size of text
ext = get(th, 'Extent');
% text_width = ext(3);
% text_height = ext(4);
% Draw appropriate line
left = center - ext(3)/2;
right = center + ext(3)/2;
line([left right], [5 5])
% Reposition original text
set(th, 'Position', [left 5+text_line_spacing]);

Matlab Slider- Display left right arrows and move slider every 1 second

As the title says I am using the GUIDE toolbox in Matlab and I would firstly like to know how I can display the left/right arrows at either end of the slider?
Also how can I get the slider to automatically move every 1 second?
As far as I understand it I need to first create a timer object and set the execution mode and period as follows:
time = timer;
set(time,'executionMode','fixedRate','period',1);
Now I know I need to set the timerFcn to something like:
set(handles.slider1,'Value',x);
in order to change the position of the slider.
Also I understand I need to increment the x variable first by the slider step which in my case is 0.00520833. For example:
x = x + 0.00520833;
So I have some code as follows:
time = timer;
set(time,'executionMode','fixedRate','period',1);
time.timerFcn = set(handles.slider1,'Value', x = x + 0.00520833);
start(time);
However this doesn't work, and i'm sure it's because of something stupid that I am doing.
Thanks!
EDIT:
Now I can move the slider every second but what I would like to do is run a function of my own every second instead. For example:
time.timerFcn = #slider_increment;
function slider_increment
set(handles.slider1,'Value', get(handles.slider1,'Value') + 0.00520833)
slider = get(handles.slider1,'Value');
set(handles.text4,'String', slider);
I know this is a little messy but I will sort that later. The problem i'm facing is how to declare my own function inside the GUI script created by guide, and allow the function to access the handles to the GUI objects.
First, this
time.timerFcn = set(handles.slider1,'Value', x = x + 0.00520833);
Definitely produces an error...
I think you want something like this:
h = uicontrol;
time = timer;
set(time,'executionMode','fixedRate','period',1);
%Note: set(h,val,get(h,val) + change)
time.timerFcn = #(x,y)set(h,'position', get(h,'position') + 10);
start(time);