Каковы методы ограничения движения ROI? - PullRequest
0 голосов
/ 26 апреля 2018

Я хочу разрешить пользователю изменять диаметр овальной области интереса или аннотации с фиксированным соотношением осей (для кругов это соотношение составляет 1: 1). Кроме того, овал должен открываться только вокруг центра, но не должен смещаться вбок.

В настоящее время у меня есть скрипт, который читает ROI и исправляет, когда пользователь отклоняется от фигуры или расположения его центра. Тем не менее, это выглядит довольно раздражающим и запутанным, например, когда круг меняется на овал, а затем возвращается к кругу. Я надеялся на команды, которые позволяют, например, изменить размер (с возможностью фиксированного отношения осей), но ограничить (боковое) движение.

Любое предложение очень приветствуется.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

В ответе выше указан тип запрашиваемых ограничений, но для полноты картины следует также отметить, что существуют некоторые ROI свойства , которые могут быть полезны в этом контексте.

Из справочной документации F1:

F1 help

Однако свойство moveable заменяет свойство resizable , т. Е. Если вы не можете двигаться, вы не можете изменить размер.

0 голосов
/ 26 апреля 2018

Этот вопрос является конкретным применением более общего вопроса здесь .


Хитрость заключается в том, чтобы действовать всякий раз, когда изменяется размер 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 )
}
...