如何使用 dm 脚本从循环 ROI 中获取信息?

How can I get information from circular ROI using dm script?

在图像中制作圆形 ROI 后,如何使用脚本从该图像区域获取信息(平均值、标准差、方差)?

我可以link用原图在圆形ROI中的位置吗?

不幸的是,这项任务并不像人们希望的那样直接和容易。

虽然脚本支持使用方便的快捷方式将图像操作限制为矩形 ROI(使用 img[] 符号),但对于不规则 ROI 却没有类似的方法。

在这种情况下,必须手动创建 ROI 的二进制掩码并手动执行所需的操作。此 post 底部的示例脚本显示了如何计算不规则 ROI 的平均值。

  • CreateImageWithROI() 创建一个带有两个 ROI 的测试图像
  • GetFirstIrregularROIOfImage() 只是 returns 图像的第一个发现的不规则 ROI
  • GetROIMean()就是实际例子

命令ROIAddToMask()用于创建掩码。请注意,还有一个类似的命令可以同时执行图像显示的 all 个 ROI 的操作:ImageDisplayAccumulateROIsToMask()

到目前为止,还不错。

However, it turns out that the newly introduced Circular ROIs do not yet support the mask-creation commands correctly (Tested with GMS 3.1).

相反,他们总是使用 ROI 的边界矩形:

因此有必要退后一步并读取 ROI 的坐标以手动从中创建蒙版。获取 ROI 的边界框并使用椭圆的 icolirow 表达式创建掩码。在下面的示例中:

  • GetFirstOvalROIOfImage() 只是 returns 图像的第一个找到的椭圆形 ROI
  • MyAddOvalROIToMask() 是椭圆形 ​​ROIs 的手动掩码创建


示例代码:

image CreateImageWithROI()
{
    // Create and show image
    number sx = 256, sy = 256
    image img := RealImage( "Image", 4, sx, sy )
    img = sin( 0.1 * iradius ) * cos( 7 * itheta )
    img.ShowImage()
    
    // Create an irregular, closed ROI
    ROI myIrRoi = NewROI()
    myIrRoi.ROIAddVertex( 0.3 * sx, 0.1 * sy )
    myIrRoi.ROIAddVertex( 0.7 * sx, 0.2 * sy )
    myIrRoi.ROIAddVertex( 0.5 * sx, 0.6 * sy )
    myIrRoi.ROIAddVertex( 0.1 * sx, 0.8 * sy )
    myIrRoi.ROISetIsClosed(1)
    myIRRoi.ROISetVolatile(0)
    
    // Create an oval ROI
    ROI myOvalROI = NewROI()
    myOvalROI.ROISetOval( 0.7 * sy, 0.7 * sx, 0.9 * sy, 0.8 * sx )
    myOvalROI.ROISetVolatile(0)
    
    // AddROIs
    imageDisplay disp = img.ImageGetImageDisplay( 0 )
    disp.ImageDisplayAddROI( myIRRoi )
    disp.ImageDisplayAddROI( myOvalROI )
    
    return img
}

ROI GetFirstIrregularROIOfImage( image img )
{
    if ( img.ImageIsValid() ) 
    {
        if ( 0 != img.ImageCountImageDisplays() ) 
        {
            imageDisplay disp = img.ImageGetImageDisplay( 0 )
            number nRois = disp.ImageDisplayCountROIs()
            for ( number i = 0; i < nRois; i++ )
            {
                ROI testROI = disp.ImageDisplayGetRoi( i )
                number isIrregularClosed = 1
                isIrregularClosed *= testROI.ROIIsClosed();
                isIrregularClosed *= !testROI.ROIIsOval();
                isIrregularClosed *= !testROI.ROIIsRectangle();
                isIrregularClosed *= ( 2 < testROI.ROICountVertices());
                if ( isIrregularClosed )
                    return testROI
            }
        }
    }   
    Throw( "No irregular ROI found" )
}

ROI GetFirstOvalROIOfImage( image img )
{
    if ( img.ImageIsValid() ) 
    {
        if ( 0 != img.ImageCountImageDisplays() ) 
        {
            imageDisplay disp = img.ImageGetImageDisplay( 0 )
            number nRois = disp.ImageDisplayCountROIs()
            for ( number i = 0; i < nRois; i++ )
            {
                ROI testROI = disp.ImageDisplayGetRoi( i )
                if ( testROI.ROIIsOval() )
                    return testROI
            }
        }
    }   
    Throw( "No oval ROI found" )
}

void MyAddOvalROIToMask( image img, ROI ovalROI )
{
    number top, left, bottom, right
    ovalROI.ROIGetOval( top, left, bottom, right )
    number sx = ( right - left )
    number sy = ( bottom - top )
    number cx = sx/2    // Used as both center x coordiante and x radius!
    number cy = sy/2    // Used as both center y coordiante and y radius!
    
    // Create mask of just the rect area
    image maskCut := RealImage( "", 4, sx, sy )
    maskCut = ( ((cx-icol)/cx)**2 + ((cy-irow)/cy)**2 <= 1 ) ? 1 : 0
    
    // Apply mask to image
    img[top, left, bottom, right] = maskCut
}

number GetROIMean( image img, ROI theRoi )
{
    if ( !img.ImageIsValid() ) Throw( "Invalid image in GetROIMean()" )
    if ( !theRoi.ROIIsValid() ) Throw( "Invalid roi in GetROIMean()" )
    
    // Create a binary mask of "img" size using the ROI's coordinates
    image mask = img * 0;   // image of same size as "img" with 0 values
    number sx, sy
    img.GetSize( sx, sy )
    
    // Oval ROIs are not supported by the command correctly
    // Hence check and compute mask manually..
    if ( theROI.ROIIsOval() )
        MyAddOvalROIToMask( mask, theROI )
    else
        theROI.ROIAddToMask( mask, 0, 0, sx, sy )
    
    if ( TwoButtonDialog( "Show mask?", "Yes", "No" ) )
        mask.ShowImage()
    
    // Do meanValue as sums of masked points
    number maskedPoints = sum( mask )
    number maskedSum
    if ( 0 < maskedPoints ) 
        maskedSum = sum( mask * img ) / maskedPoints 
    else
        maskedSum = sum( img )
    
    return maskedSum 
}

Result( "\n Testing irregular and oval ROIs on image.\n" )
image testImg := CreateImageWithROI()
ROI   testROIir  = GetFirstIrregularROIOfImage( testImg )
number ROIirMean = GetROIMean( testImg, testROIir )
Result( "\n Mean value (irregular ROI): "+ ROIirMean )

ROI   testROIoval  = GetFirstOvalROIOfImage( testImg )
number ROIovalMean = GetROIMean( testImg, testROIoval )
Result( "\n Mean value (oval ROI)     : "+ ROIovalMean )