我有一只手的 X 射线图像。我需要自动提取骨骼。我可以使用不同的技术轻松分割一只手。但是我需要得到骨头并且使用这些技术没有帮助。有些骨头比其他骨头更亮,所以如果我使用阈值,它们中的一些会消失,而另一些会变得更清晰,上升阈值。我想也许我应该只限制手的一个区域?是否可以对不是正方形的 ROI 设置阈值?O也许你有任何其他的解决方案,建议?也许有一些像 OpenCV 这样的库或类似的库?任何帮助都会非常棒!
扩展:
原始图像 预期输出
我有一只手的 X 射线图像。我需要自动提取骨骼。我可以使用不同的技术轻松分割一只手。但是我需要得到骨头并且使用这些技术没有帮助。有些骨头比其他骨头更亮,所以如果我使用阈值,它们中的一些会消失,而另一些会变得更清晰,上升阈值。我想也许我应该只限制手的一个区域?是否可以对不是正方形的 ROI 设置阈值?O也许你有任何其他的解决方案,建议?也许有一些像 OpenCV 这样的库或类似的库?任何帮助都会非常棒!
扩展:
原始图像 预期输出
一种方法是从图像中分割手和手指:
然后仅使用手部轮廓创建另一个图像:
一旦你有了轮廓,你就可以侵蚀图像以使其更小。这用于从手和手指图像中减去手,得到手指:
下面的代码显示了执行这种方法:
void detect_hand_and_fingers(cv::Mat& src);
void detect_hand_silhoutte(cv::Mat& src);
int main(int argc, char* argv[])
{
cv::Mat img = cv::imread(argv[1]);
if (img.empty())
{
std::cout << "!!! imread() failed to open target image" << std::endl;
return -1;
}
// Convert RGB Mat to GRAY
cv::Mat gray;
cv::cvtColor(img, gray, CV_BGR2GRAY);
cv::Mat gray_silhouette = gray.clone();
/* Isolate Hand + Fingers */
detect_hand_and_fingers(gray);
cv::imshow("Hand+Fingers", gray);
cv::imwrite("hand_fingers.png", gray);
/* Isolate Hand Sillhoute and subtract it from the other image (Hand+Fingers) */
detect_hand_silhoutte(gray_silhouette);
cv::imshow("Hand", gray_silhouette);
cv::imwrite("hand_silhoutte.png", gray_silhouette);
/* Subtract Hand Silhoutte from Hand+Fingers so we get only Fingers */
cv::Mat fingers = gray - gray_silhouette;
cv::imshow("Fingers", fingers);
cv::imwrite("fingers_only.png", fingers);
cv::waitKey(0);
return 0;
}
void detect_hand_and_fingers(cv::Mat& src)
{
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3,3), cv::Point(1,1));
cv::morphologyEx(src, src, cv::MORPH_ELLIPSE, kernel);
int adaptiveMethod = CV_ADAPTIVE_THRESH_GAUSSIAN_C; // CV_ADAPTIVE_THRESH_MEAN_C, CV_ADAPTIVE_THRESH_GAUSSIAN_C
cv::adaptiveThreshold(src, src, 255,
adaptiveMethod, CV_THRESH_BINARY,
9, -5);
int dilate_sz = 1;
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size(2*dilate_sz, 2*dilate_sz),
cv::Point(dilate_sz, dilate_sz) );
cv::dilate(src, src, element);
}
void detect_hand_silhoutte(cv::Mat& src)
{
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7), cv::Point(3, 3));
cv::morphologyEx(src, src, cv::MORPH_ELLIPSE, kernel);
int adaptiveMethod = CV_ADAPTIVE_THRESH_MEAN_C; // CV_ADAPTIVE_THRESH_MEAN_C, CV_ADAPTIVE_THRESH_GAUSSIAN_C
cv::adaptiveThreshold(src, src, 255,
adaptiveMethod, CV_THRESH_BINARY,
251, 5); // 251, 5
int erode_sz = 5;
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size(2*erode_sz + 1, 2*erode_sz+1),
cv::Point(erode_sz, erode_sz) );
cv::erode(src, src, element);
int dilate_sz = 1;
element = cv::getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size(2*dilate_sz + 1, 2*dilate_sz+1),
cv::Point(dilate_sz, dilate_sz) );
cv::dilate(src, src, element);
cv::bitwise_not(src, src);
}