From: Andriy Nych on
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
From: Corey Kelly on
"Andriy Nych" <nych.andriy.nospam(a)gmail.com> wrote in message <hsqop7$svb$1(a)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.
From: Walter Roberson on
Corey Kelly wrote:
> "Andriy Nych" <nych.andriy.nospam(a)gmail.com> wrote in message
> <hsqop7$svb$1(a)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
 | 
Pages: 1
Prev: sinsouidal pulse.
Next: Indeo5 compressor warning!