Drawing a resizeable box on an image - matlab

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..

Related

Loop to change block position

I have a Matlab script that creates a Model Block for each element i found in a text file.
The problem is that all Models are created on each other in the window. So i'm trying to make a loop like:
for each element in text file
I add a Model block
I place right to the previous one
end
So it can look like this:
As you can see on the left, all models are on each other and I would like to place them like the one on the right.
I tried this:
m = mdlrefCountBlocks(diagrammeName)+500;
add_block('simulink/Ports & Subsystems/Model',[diagrammeName '/' component_NameValue]);
set_param(sprintf('%s/%s',diagrammeName,component_NameValue), 'ModelFile',component_NameValue);
size_blk = get_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position');
X = size_blk(1,1);
Y = size_blk(1,2);
Width = size_blk(1,3);
Height = size_blk(1,4);
set_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position',[X+m Y X+Width Y+Height]);
Inside the loop but it returns an error Invalid definition of rectangle. Width and height should be positive.
Thanks for helping!
The position property of a block does actually not contain its width and height, but the positions of the corners on the canvas (see Common Block Properties):
vector of coordinates, in pixels: [left top right bottom]
The origin is the upper-left corner of the Simulink Editor canvas before any canvas resizing. Supported coordinates are between -1073740824 and 1073740823, inclusive. Positive values are to the right of and down from the origin. Negative values are to the left of and up from the origin.
So change your code to e.g.:
size_blk = get_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position');
set_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position', size_blk + [m 0 0 0]);

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.

How to draw multiple shapes using Matlab vision toolbox and step function?

I'm trying to insert 2 shapes (circle and rectangle) to an image using these functions. But I'm unable to do that.
Here's my code
J = step(shapeInserter, I, bbox); %bbox is rectangle which is already defined
J = step(shapeInserter, I, circle); %circle is circle which is already defined
imwrite(J,'image.jpg','jpg'); % it draws only the circle
I have a long way which is to save the rectange image then load again to draw the circle and resave. Which i wish to avoid as it's really time consuming.
I'm trying to do something like this (similar to the plotting graph function)
hold on
%draw circle
%draw rectangle
hold off
imwrite(J,'image.jpg','jpg');
Please advise, thanks
The vision.ShapeInserter object has a property Shape, which can either be set to
'Rectangles'
'Circles'
'Lines'
'Polygons'
By default, it is set to 'Rectangles'. To use the same ShapeInserter object to place a circle, you will have to release it first by calling release(shapeInserter); and modifying the Shape property by set(shapeInserter,'Shape','Circles'). Then you can call the step method again to insert the circle.
Here is a small example:
I = imread('cameraman.tif');
rectangle = int32([10,10,50,60]);
circle = int32([200,200,40]);
shapeInserter = vision.ShapeInserter('Fill',true);
J = step(shapeInserter,I,rectangle);
release(shapeInserter);
set(shapeInserter,'Shape','Circles');
K = step(shapeInserter,J,circle);
imshow(K);
I'm a total noob to Matlab Image stuff but here is some very strait forward way of doing it :
frame=imread( '/home/omido/DeepLearning/matlab_segmentation/track/track/Image2.jpg' );
result = insertShape(frame, 'FilledRectangle', [100,100,100,100], 'Color', 'green');
result = insertShape(result, 'FilledRectangle', [200,200,200,200] , 'Color', 'yellow');
imshow(result);
and this is the result:
and as in the previous answer there are multiple shapes, you can find them here.

Draw 2 imline to be perpendicular to each other matlab

Is there any way to constraint the the imline to be always perpendicular to the other imline drawn on the same object. for ex. I draw a first line using "imline" now I want to draw second line across the first line to be perpendicular to it. if there is a way to force the second imline to be perpendicular to the first line keeping the flexibility of extending the length it will solve my problem some extent.
I want something like a flexible cross hair(which can rotate along the axis and have flexible sides) on my image to measure the height and width of the certain object.
Code:
function perpline()
imshow(rand(200),[]);
line1 = imline(gca,[50 50; 150 150]);
setColor(line1,'r');
line2 = imline(gca,[50 150; 150 50]);
setColor(line2,'g');
addNewPositionCallback(line2,#(pos)callback_line(pos));
function callback_line(pos)
% Must update line1 based on line2's position
pos_line1 = getPosition(line1);
pos_line2 = getPosition(line2);
% Get middle
pos_center = [(pos_line2(1,1)+pos_line2(2,1))/2 (pos_line2(1,2)+pos_line2(2,2))/2];
% Find displacement
vec_disp = [pos_line2(2,1)-pos_line2(1,1) pos_line2(2,2)-pos_line2(1,2)];
% Get normal unit vector
vec_perp = [-vec_disp(2) vec_disp(1)]/norm(vec_disp);
% Preserve length of line2
length_line1 = norm([pos_line1(2,1)-pos_line1(1,1) pos_line1(2,2)-pos_line1(1,2)]);
pos_line1_update = [-vec_perp*length_line1/2+pos_center;
vec_perp*length_line1/2+pos_center];
% Set position
setPosition(line1,pos_line1_update);
end
end
Save it as a function then call it. You can drag the green line around and the red line remains perpendicular. Note that you have to define how you want it to preserve the perpendicularity. I chose to preserve the length of the red line and keep it in the center of the green line.

Copying a portion of an IplImage into another Iplimage (that is of same size is the source)

I have a set of mask images that I need to use everytime I recognise a previously-known scene on my camera. All the mask images are in IplImage format. There will be instances where, for example, the camera has panned to a slightly different but nearby location. this means that if I do a template matching somewhere in the middle of the current scene, I will be able to recognise the scene with some amount of shift of the template in this scene. All I need to do is use those shifts to adjust the mask image ROIs so that they can be overlayed appropriately based on the template-matching. I know that there are functions such as:
cvSetImageROI(Iplimage* img, CvRect roi)
cvResetImageROI(IplImage* img);
Which I can use to set crop/uncrop my image. However, it didn't work for me quit the way I expected. I would really appreciate if someone could suggest an alternative or what I am doing wrong, or even what I haven't thought of!
**I must also point out that I need to keep the image size same at all times. The only thing that will be different is the actual area of interest in the image. I can probably use the zero/one padding to cover the unused areas.
I believe a solution without making too many copies of the original image would be:
// Make a new IplImage
IplImage* img_src_cpy = cvCreateImage(cvGetSize(img_src), img_src->depth, img_src->nChannels);
// Crop Original Image without changing the ROI
for(int rows = roi.y; rows < roi.height; rows++) {
for(int cols = roi.x; rows < roi.width; cols++) {
img_src_cpy->imageData[(rows-roi.y)*img_src_cpy->widthStep + (cols-roi.x)] = img_src[rows*img_src + cols];
}
{
//Now copy everything to the original image OR simply return the new image if calling from a function
cvCopy(img_src_cpy, img_src); // OR return img_src_cpy;
I tried the code out on itself and it is also fast enough for me (executes in about 1 ms for 332 x 332 Greyscale image)