描述
我有一张肺癌 CT 扫描图像,我想从中分割并提取癌变区域。我使用过 Open CV 和 Java。
我有以下图像作为输入:
使用阈值和分水岭方法进行分割后,得到以下结果:
之后,我想从分割图像中提取癌变区域,因此我必须去除感兴趣区域(癌结节)之外的所有噪声和其他对象。如下图所示,我想像这样提取癌结节:
如何使用 OpenCV 在 Android 中实现此目的?
最佳答案
我尝试实现我建议的解决方案。我的答案是用C++,但想法很简单,你应该能够用Java实现它。正如我所评论的,这个想法是使用形态学来获得感兴趣的 Blob 。主要是侵 eclipse 操作。让我们看看:
//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 );
这是您得到的结果:
现在,有多个 Blob 。但是,我将寻找最大的 Blob ,因为那是我们感兴趣的目标区域所在的位置。搜索二值图像中最大的 Blob 是我经常执行的任务,因此我为此准备了一个函数。它称为findBiggestBlob
。稍后我会介绍这个功能。查看过滤掉较小 Blob 后得到的结果:
//Get the biggest blob in the binary image
cv::Mat targetBlobs = findBiggestBlob( grayImg );
这是结果:
现在,只需应用形态学即可。首先,侵 eclipse 操作。使用大小为 5 x 5
的椭圆
结构元素和 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 现已分离:
现在,这个想法很简单。如果我们再次提取图像中最大的 Blob ,我们最终应该得到没有癌变区域的肺部。然后,将此图像减去“分离”蒙版,我们最终应该在一个蒙版中得到感兴趣的 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 );
这是覆盖在原始图像上的 Blob (红色):
这是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;
}
关于java - 分割后如何从图像中去除小物体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60863162/