Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
Handling multiple rectangles (imrect) problem

Subject: Handling multiple rectangles (imrect) problem

From: Andriy Nych

Date: 17 May, 2010 06:47:03

Message: 1 of 3

Hi all
I need to select a rectangular area that should include some features on four images simultaneously. I want to be able to select rectangle on one of the images and adjust it on any of the others. In other words I need positions of four rectangles to be linked.
IMRECT and IMROI does not allow to do that. Moreover, if I use the same callback for each rectangle, I can not distinguish which one triggered the callback: IMRECT and IMROI does not have handle property, like rectangle does.
So far I've come to the code below (R2008a), which works the way I want but looks ugly to me.
Does anyone have any suggestions how to make it more "beautiful"?
Is it possible somehow to avoid using four different callbacks for each rectangle?

Thanks

function MultipleRectangleTest
f0 = figure('color','w');
subplot(2,2,1); imshow('cameraman.tif'); [UD.rectangles.h1,UD.id.i1] = AddRectangle([0 0 100 100],@Rect1CallBack);
subplot(2,2,2); imshow('cameraman.tif'); [UD.rectangles.h2,UD.id.i2] = AddRectangle([0 0 100 100],@Rect2CallBack);
subplot(2,2,3); imshow('cameraman.tif'); [UD.rectangles.h3,UD.id.i3] = AddRectangle([0 0 100 100],@Rect3CallBack);
subplot(2,2,4); imshow('cameraman.tif'); [UD.rectangles.h4,UD.id.i4] = AddRectangle([0 0 100 100],@Rect4CallBack);
set(f0, 'UserData',UD);
end

function [r,id] = AddRectangle(pos,funHand)
r = imrect(gca, pos);
id = addNewPositionCallback(r,funHand);
fcn = makeConstrainToRectFcn('imrect',get(gca,'XLim'),get(gca,'YLim'));
setPositionConstraintFcn(r,fcn);
end

function Rect1CallBack(p)
disp('Rect1CallBack fired');
UD=get(gcf,'UserData');
RFN=fieldnames(UD.rectangles);
IFN=fieldnames(UD.id);
for k=[2 3 4]
    % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
    removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
    setPosition(UD.rectangles.(RFN{k}),p);
    % restore PositionCallbacks to keep the functionality
    UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
end;
% title(['Rect1 - ' mat2str(p,3)]);
set(gcf, 'UserData',UD);
end

function Rect2CallBack(p)
disp('Rect2CallBack fired');
UD=get(gcf,'UserData');
RFN=fieldnames(UD.rectangles);
IFN=fieldnames(UD.id);
for k=[1 3 4]
    % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
    removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
    % restore PositionCallbacks to keep the functionality
    setPosition(UD.rectangles.(RFN{k}),p);
    UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
end;
% title(['Rect2 - ' mat2str(p,3)]);
set(gcf, 'UserData',UD);
end

function Rect3CallBack(p)
disp('Rect3CallBack fired');
UD=get(gcf,'UserData');
RFN=fieldnames(UD.rectangles);
IFN=fieldnames(UD.id);
for k=[1 2 4]
    % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
    removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
    setPosition(UD.rectangles.(RFN{k}),p);
    % restore PositionCallbacks to keep the functionality
    UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
end;
% title(['Rect3 - ' mat2str(p,3)]);
set(gcf, 'UserData',UD);
end

function Rect4CallBack(p)
disp('Rect4CallBack fired');
UD=get(gcf,'UserData');
RFN=fieldnames(UD.rectangles);
IFN=fieldnames(UD.id);
for k=[1 2 3]
    % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
    removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
    setPosition(UD.rectangles.(RFN{k}),p);
    % restore PositionCallbacks to keep the functionality
    UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
end;
% title(['Rect4 - ' mat2str(p,3)]);
set(gcf, 'UserData',UD);
end

Subject: Handling multiple rectangles (imrect) problem

From: Corey Kelly

Date: 30 May, 2010 02:44:05

Message: 2 of 3

"Andriy Nych" <nych.andriy.nospam@gmail.com> wrote in message <hsqop7$svb$1@fred.mathworks.com>...
> Hi all
> I need to select a rectangular area that should include some features on four images simultaneously. I want to be able to select rectangle on one of the images and adjust it on any of the others. In other words I need positions of four rectangles to be linked.
> IMRECT and IMROI does not allow to do that. Moreover, if I use the same callback for each rectangle, I can not distinguish which one triggered the callback: IMRECT and IMROI does not have handle property, like rectangle does.
> So far I've come to the code below (R2008a), which works the way I want but looks ugly to me.
> Does anyone have any suggestions how to make it more "beautiful"?
> Is it possible somehow to avoid using four different callbacks for each rectangle?
>
> Thanks
>
> function MultipleRectangleTest
> f0 = figure('color','w');
> subplot(2,2,1); imshow('cameraman.tif'); [UD.rectangles.h1,UD.id.i1] = AddRectangle([0 0 100 100],@Rect1CallBack);
> subplot(2,2,2); imshow('cameraman.tif'); [UD.rectangles.h2,UD.id.i2] = AddRectangle([0 0 100 100],@Rect2CallBack);
> subplot(2,2,3); imshow('cameraman.tif'); [UD.rectangles.h3,UD.id.i3] = AddRectangle([0 0 100 100],@Rect3CallBack);
> subplot(2,2,4); imshow('cameraman.tif'); [UD.rectangles.h4,UD.id.i4] = AddRectangle([0 0 100 100],@Rect4CallBack);
> set(f0, 'UserData',UD);
> end
>
> function [r,id] = AddRectangle(pos,funHand)
> r = imrect(gca, pos);
> id = addNewPositionCallback(r,funHand);
> fcn = makeConstrainToRectFcn('imrect',get(gca,'XLim'),get(gca,'YLim'));
> setPositionConstraintFcn(r,fcn);
> end
>
> function Rect1CallBack(p)
> disp('Rect1CallBack fired');
> UD=get(gcf,'UserData');
> RFN=fieldnames(UD.rectangles);
> IFN=fieldnames(UD.id);
> for k=[2 3 4]
> % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
> removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
> setPosition(UD.rectangles.(RFN{k}),p);
> % restore PositionCallbacks to keep the functionality
> UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
> end;
> % title(['Rect1 - ' mat2str(p,3)]);
> set(gcf, 'UserData',UD);
> end
>
> function Rect2CallBack(p)
> disp('Rect2CallBack fired');
> UD=get(gcf,'UserData');
> RFN=fieldnames(UD.rectangles);
> IFN=fieldnames(UD.id);
> for k=[1 3 4]
> % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
> removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
> % restore PositionCallbacks to keep the functionality
> setPosition(UD.rectangles.(RFN{k}),p);
> UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
> end;
> % title(['Rect2 - ' mat2str(p,3)]);
> set(gcf, 'UserData',UD);
> end
>
> function Rect3CallBack(p)
> disp('Rect3CallBack fired');
> UD=get(gcf,'UserData');
> RFN=fieldnames(UD.rectangles);
> IFN=fieldnames(UD.id);
> for k=[1 2 4]
> % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
> removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
> setPosition(UD.rectangles.(RFN{k}),p);
> % restore PositionCallbacks to keep the functionality
> UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
> end;
> % title(['Rect3 - ' mat2str(p,3)]);
> set(gcf, 'UserData',UD);
> end
>
> function Rect4CallBack(p)
> disp('Rect4CallBack fired');
> UD=get(gcf,'UserData');
> RFN=fieldnames(UD.rectangles);
> IFN=fieldnames(UD.id);
> for k=[1 2 3]
> % remove PositionCallbacks from imrect in order to avoid "callback avalanche"
> removeNewPositionCallback(UD.rectangles.(RFN{k}),UD.id.(IFN{k}));
> setPosition(UD.rectangles.(RFN{k}),p);
> % restore PositionCallbacks to keep the functionality
> UD.id.(IFN{k}) = addNewPositionCallback(UD.rectangles.(RFN{k}),str2func(sprintf('Rect%dCallBack',k)));
> end;
> % title(['Rect4 - ' mat2str(p,3)]);
> set(gcf, 'UserData',UD);
> end

I'm having a similar problem, except in my case I'm creating an arbitrary number of imellipse() objects, so I actually NEED a better solution. I haven't managed to get it working yet, but my best advice would be to pass the object number as an argument to the callback function, and use that number within the function to differentiate what happens. So in your case, I think you'd want something like:
AddRectangle([0 0 100 100],{@RectCallBack,4});

And then change the callback function to a general one. If I make any headway with my problem, I'll let you know.

Subject: Handling multiple rectangles (imrect) problem

From: Walter Roberson

Date: 30 May, 2010 16:55:48

Message: 3 of 3

Corey Kelly wrote:
> "Andriy Nych" <nych.andriy.nospam@gmail.com> wrote in message
> <hsqop7$svb$1@fred.mathworks.com>...

>> I need to select a rectangular area that should include some features
>> on four images simultaneously. I want to be able to select rectangle
>> on one of the images and adjust it on any of the others. In other
>> words I need positions of four rectangles to be linked.
>> IMRECT and IMROI does not allow to do that. Moreover, if I use the
>> same callback for each rectangle, I can not distinguish which one
>> triggered the callback: IMRECT and IMROI does not have handle
>> property, like rectangle does.

> I'm having a similar problem, except in my case I'm creating an
> arbitrary number of imellipse() objects, so I actually NEED a better
> solution. I haven't managed to get it working yet, but my best advice
> would be to pass the object number as an argument to the callback
> function, and use that number within the function to differentiate what
> happens.

I think that is the right general approach, but you have to be careful
because it is not clear from the documentation that you are allowed to
pass additional arguments to the callback directly. I would thus suggest
using individual anonymous functions

for K = 1 : 4
  ...
  addNewPositionCallback(UD.rectangles.(RFN{k}),@(p) RectCallBack(p,K));
end

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us