Этот вопрос является конкретным применением более общего вопроса здесь .
Хитрость заключается в том, чтобы действовать всякий раз, когда изменяется размер ROI, а затем заменять его имеющимися ограничениями. Это делается путем подключения метода «слушателя»
который вызывается при изменении ROI.
Есть два способа сделать это для ROI:
1) Присоединение слушателя к изображению , на котором находится ROI
// EXAMPLE using ImageDisplay listener
// This will handle ALL ROIs on the display, so one would like to
// "filter" specific ROIs. f.e. by using the ROI property "Name".
class CCircleRestrict
{
number x0,y0
object Init( object self, number cx, number cy ){ x0 = cx; y0 = cy; return self; }
void OnRestrict( object self, number e_fl, ImageDisplay idisp, number r_fl, number r_fl2, ROI theROI )
{
if ( theROI.ROIGetName() != "special" ) return; // Skip, if it isn't "our" ROI
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number radius = max( b - t, r - l ) / 2
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - radius, x0 - radius, y0 + radius, x0 + radius )
}
}
// Main script "attaches" the display listener to
void main()
{
// Create and show test image
number size = 512
number r1 = 20
number r2 = 20
number off = 100
image test := realImage( "Test", 4, size, size )
test.ShowImage()
imageDisplay disp = test.ImageGetImageDisplay(0)
// Add two oval ROIs, name one of them "special" for identification
ROI specialROI = NewROI()
specialROI.ROISetName( "special" )
specialROI.ROISetOval( size/2 - r1, size/2 - r1, size/2 + r1, size/2 + r1 )
specialROI.ROISetVolatile(0)
specialROI.ROISetColor(0.1,0.9,0.1)
disp.ImageDisplayAddROI(specialROI)
ROI otherROI = NewROI()
otherROI.ROISetOval( off + size/2 - r2, off + size/2 - r2, off + size/2 + r2, off + size/2 + r2 )
otherROI.ROISetVolatile(0)
disp.ImageDisplayAddROI(otherROI)
// Create listener object and attach listener to display
object dispListener = Alloc(CCircleRestrict).Init( size/2, size/2 )
disp.ImageDisplayAddEventListener( dispListener, "roi_property_changed:OnRestrict" )
}
EGUPerformActionWithAllShownImages( "Delete" )
main()
EGUPerformActionWithAllShownImages( "Arrange" )
2) Присоединение слушателя к самому объекту ROI
// EXAMPLE using ROI listener
// This will handle changes a specific ROI, regardless of the display(s) it is on
class CCircleRestrict
{
number x0,y0
object Init( object self, number cx, number cy ){ x0 = cx; y0 = cy; return self; }
void OnRestrict( object self, ROI theROI )
{
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number radius = max( b - t, r - l ) / 2
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - radius, x0 - radius, y0 + radius, x0 + radius )
}
}
// Main script "attaches" the listener to the ROI
void main()
{
// Create and show test image
number size = 512
number r1 = 20
number r2 = 20
number off = 100
image test := realImage( "Test", 4, size, size )
test.ShowImage()
imageDisplay disp = test.ImageGetImageDisplay(0)
// Add two oval ROIs
ROI specialROI = NewROI()
specialROI.ROISetOval( size/2 - r1, size/2 - r1, size/2 + r1, size/2 + r1 )
specialROI.ROISetVolatile(0)
specialROI.ROISetColor(0.1,0.9,0.1)
disp.ImageDisplayAddROI(specialROI)
ROI otherROI = NewROI()
otherROI.ROISetOval( off + size/2 - r2, off + size/2 - r2, off + size/2 + r2, off + size/2 + r2 )
otherROI.ROISetVolatile(0)
disp.ImageDisplayAddROI(otherROI)
// Create listener object and attach listener to specific ROI
object roiListener = Alloc(CCircleRestrict).Init( size/2, size/2 )
ConnectObject( specialROI.ROIGetID(), "changed", "EventID_Name", roiListener, "OnRestrict" )
}
EGUPerformActionWithAllShownImages( "Delete" )
main()
EGUPerformActionWithAllShownImages( "Arrange" )
В обоих приведенных выше примерах овальная область интереса ограничена кругом, но изменить его так, чтобы было достигнуто определенное соотношение сторон овала, просто.
Однако важно учитывать, что «вновь настроенный» и скорректированный
ROI сам снова вызовет слушателя. Должно быть обеспечено, чтобы
таким образом, бесконечный цикл не создается, т.е.
метод во второй раз не должен приводить к новым ограничениям.
Простой пример для овальной ROI с соотношением сторон 1: 2 будет использовать метод ограничения, как в:
void OnRestrict( object self, ROI theROI )
{
ar = 2
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number w = r - l
number h = b - t
number newW = max( W, AR*H )
number newH = newW/AR
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - newH/2, x0 - newW/2, y0 + newH/2, x0 + newW/2 )
}