如何在分割后从图像中删除小 Objects

How to Remove Small Objects from Image after Segmentation

描述

我有一张肺癌 CT 扫描图像,我想从中分割和提取癌变区域。我使用了 Open CV 和 Java.

我有以下图像作为输入:

用阈值法和分水岭法分割后,我得到了这个结果:

之后,我想从分割图像中提取癌变区域,所以我必须去除感兴趣区域(癌变结节)之外的所有噪声和其他objects。所以如下图所示,我想像这样提取癌性结节:

如何使用 OpenCV 在 android 中实现此目的?

为什么不使用用于语义分割的称为 MobileUNet 的深度神经网络 problem.I 只是提到它的设计非常简单。它适用于 IOS 和 Android。

您可以在 Github 存储库中查看更多详细信息。 https://github.com/akirasosa/mobile-semantic-segmentation

我尝试实施我建议的解决方案。我的答案是用C++,但是思路很简单,你应该可以用Java来实现。正如我评论的那样,这个想法是使用形态学来获得感兴趣的斑点。主要是erode操作。让我们看看:

   //Read input image:
   std::string imagePath = "C://opencvImages//lungsImage.png";
   cv::Mat imageInput= cv::imread( imagePath );

   //Convert it to grayscale:
   cv::Mat grayImg;
   cv::cvtColor( imageInput, grayImg, cv::COLOR_BGR2GRAY );

第一步是获取二值图像。您似乎实施了 分水岭分割 。没关系。我尝试应用具有大 window 的简单自适应阈值(对于这种情况,大小为 601)。它给了我很好的结果:

    //Get the binary image:
    cv::adaptiveThreshold( grayImg, grayImg, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 601, 10 );

这是您得到的结果:

现在,有多个斑点。但是,我会寻找最大的斑点,因为那是我们感兴趣的目标区域所在的位置。在二值图像中寻找最大的blob是我经常进行的任务,所以我为此准备了一个函数。它被称为findBiggestBlob。我稍后会介绍该功能。查看过滤掉较小的斑点后得到的结果:

    //Get the biggest blob in the binary image
    cv::Mat targetBlobs = findBiggestBlob( grayImg );

这是结果:

现在,简单地应用形态学。首先,一个 erode 操作。使用大小为 5 x 5ellipse 结构元素和 4 次迭代来分离感兴趣的 blob:

    //Apply erosion to the biggest blob mask;
    cv::Mat morphKernel = cv::getStructuringElement( cv::MORPH_ELLIPSE, cv::Size(5, 5) );
    int morphIterations = 4; // use 4 iterations
    cv::morphologyEx( targetBlobs, targetBlobs, cv::MORPH_ERODE, morphKernel, cv::Point(-1,-1), morphIterations );

查看结果,感兴趣的 blob 现已分离:

现在,这个想法很简单。如果我们再次提取图像中最大的斑点,我们最终应该得到没有癌变区域的肺部。然后,将此图像减去“分离”掩码,我们最终应该在一个掩码中得到感兴趣的斑点:

    //Get the lungs image:
    cv::Mat bigBlob = findBiggestBlob( targetBlobs );

你明白了:

    //Subtract the lungs from the first binary mask:
    cv::Mat blobOfInterest = targetBlobs - bigBlob;

现在,让我们应用 dilate 操作恢复 blob 的原始大小,使用相同的结构元素和相同的迭代次数。这是结果:

    //Restore the blob's original size:
    cv::morphologyEx( blobOfInterest, blobOfInterest, cv::MORPH_DILATE, morphKernel, cv::Point(-1,-1), morphIterations );

这是覆盖在原始图像上的斑点(红色):

这是 findBiggestBlob 函数的代码。这个想法只是计算二进制输入中的所有轮廓,计算它们的面积并存储束中面积最大的轮廓:

//Function to get the largest blob in a binary image:
cv::Mat findBiggestBlob( cv::Mat &inputImage ){

    cv::Mat biggestBlob = inputImage.clone();

    int largest_area = 0;
    int largest_contour_index=0;

    std::vector< std::vector<cv::Point> > contours; // Vector for storing contour
    std::vector<cv::Vec4i> hierarchy;

    // Find the contours in the image
    cv::findContours( biggestBlob, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); 

    for( int i = 0; i< (int)contours.size(); i++ ) {            

        //Find the area of the contour            
        double a = cv::contourArea( contours[i],false);
        //Store the index of largest contour:
        if( a > largest_area ){
            largest_area = a;                
            largest_contour_index = i;
        }

    }

    //Once you get the biggest blob, paint it black:
    cv::Mat tempMat = biggestBlob.clone();
    cv::drawContours( tempMat, contours, largest_contour_index, cv::Scalar(0),
                  CV_FILLED, 8, hierarchy );

    //Erase the smaller blobs:
    biggestBlob = biggestBlob - tempMat;
    tempMat.release();
    return biggestBlob;
}