opencv - 从 X 射线图像中提取手骨

标签 opencv image-processing image-segmentation

我有一只手的 X 射线图像。我需要自动提取骨骼。我可以使用不同的技术轻松地分割一只手。但我需要获取骨头,使用这些技术无济于事。有些骨头比其他骨头更亮,所以如果我使用阈值,它们中的一些会消失,而另一些则变得更清晰上升阈值。我想也许我应该只对手的一个区域设置阈值?是否可以对不是正方形的 ROI 设置阈值?哦,也许您还有其他解决方案,建议?也许有一些像 OpenCV 之类的库?任何帮助都会非常有用!

扩展:

Raw Image Expected Output

原始图像 预期输出

最佳答案

一种方法是从图像中分割手和手指:

enter image description here

然后用手剪影创建另一张图片:

enter image description here

一旦你有了剪影,你就可以侵 eclipse 图像,让它变小一点。这用于手和手指图像中减去手,得到手指:

enter image description here

下面的代码展示了如何执行这个方法:

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

关于opencv - 从 X 射线图像中提取手骨,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15718306/

相关文章:

python - 平滑手写数字中的极值点

python - 如何使用 openCV python 从文本文档中删除水印?

opencv - 带有 CUDA 的 OpenCV 在 Windows 上是否需要 SSE4.2?

android - 比较两个不同图像的像素,耗时太长

algorithm - 数蜥蜴的鳞片

colors - 为什么 HSV 上的颜色分割更容易?

c - 使用 cvSmooth() 函数进行双边过滤

c++ - visual studio 2010 错误/堆损坏

java - 突出显示图像之间的差异

python - 从图像中检测水平白线并使用 OpenCV Python 获取它们的坐标