Как удалить небольшие объекты из изображения после сегментации - PullRequest
1 голос
/ 26 марта 2020

Описание

У меня есть изображение КТ рака легких, которое я хочу сегментировать и извлечь из него раковые участки. Я использовал Open CV и Java.

У меня есть следующее изображение в качестве ввода:

original image

После сегментации с порогом и метод водораздела, я получаю этот результат:

original image

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

original image

Как мне добиться этого в android с помощью OpenCV?

Ответы [ 2 ]

0 голосов
/ 28 марта 2020

Я пытался реализовать предложенное мной решение. Мой ответ на C ++, но идея проста, вы должны быть в состоянии реализовать его в Java. Как я уже говорил, идея состоит в том, чтобы использовать морфологию, чтобы получить интересующий объект. В основном операция разрушает . Давайте посмотрим:

   //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 );

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

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

Вот результат, который вы получаете:

enter image description here

Теперь есть несколько капель. Тем не менее, я буду искать самый большой блоб, поскольку именно там находится наша целевая область интересов. Поиск самого большого двоичного объекта в двоичном изображении - это задача, которую я часто выполняю, поэтому я подготовил функцию для этого. Это называется findBiggestBlob. Я представлю функцию позже. Проверьте результат, который вы получите после фильтрации небольших капель:

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

Вот результат:

enter image description here

Сейчас, просто примените морфологию. Во-первых, операция erode. Используйте ellipse структурирующий элемент размером 5 x 5 с 4 итерациями, чтобы отделить интересующий объект:

    //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 );

Проверьте результат, объект интереса теперь отсоединен:

enter image description here

Теперь идея проста. Если мы снова извлечем самый большой фрагмент изображения, у нас должны получиться легкие, свободные от раковой области. Затем вычтите это изображение в «отдельную» маску, в результате мы получим интересующий объект в одной маске:

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

Вы получите это:

enter image description here

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

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

enter image description here

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

Вот капля (красного цвета), наложенная на исходное изображение:

enter image description here

Это код для функции 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;
}
0 голосов
/ 26 марта 2020

Почему вы не используете глубокую нейронную сеть под названием Mobile UNet, которая используется для проблемы сегментации * semanti c. Я просто упомянул, что у нее довольно простой дизайн. Он доступен как для IOS, так и для Android.

Более подробную информацию можно найти в репозитории Github. https://github.com/akirasosa/mobile-semantic-segmentation

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...