Я пытался реализовать предложенное мной решение. Мой ответ на 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 );
Вот результат, который вы получаете:
Теперь есть несколько капель. Тем не менее, я буду искать самый большой блоб, поскольку именно там находится наша целевая область интересов. Поиск самого большого двоичного объекта в двоичном изображении - это задача, которую я часто выполняю, поэтому я подготовил функцию для этого. Это называется findBiggestBlob
. Я представлю функцию позже. Проверьте результат, который вы получите после фильтрации небольших капель:
//Get the biggest blob in the binary image
cv::Mat targetBlobs = findBiggestBlob( grayImg );
Вот результат:
Сейчас, просто примените морфологию. Во-первых, операция 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 );
Проверьте результат, объект интереса теперь отсоединен:
Теперь идея проста. Если мы снова извлечем самый большой фрагмент изображения, у нас должны получиться легкие, свободные от раковой области. Затем вычтите это изображение в «отдельную» маску, в результате мы получим интересующий объект в одной маске:
//Get the lungs image:
cv::Mat bigBlob = findBiggestBlob( targetBlobs );
Вы получите это:
//Subtract the lungs from the first binary mask:
cv::Mat blobOfInterest = targetBlobs - bigBlob;
Теперь давайте восстановим исходный размер большого двоичного объекта, применив операцию dilate
, используя тот же элемент структурирования и такое же количество итераций. Вот результат:
//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;
}