【问题标题】:Python: Calculating the angle between two bones in an x-rayPython:计算 X 射线中两个骨骼之间的角度
【发布时间】:2018-04-10 00:49:54
【问题描述】:

我正在尝试编写一个脚本来计算给定 X 射线的两根骨头之间的角度。

X 射线样本如下所示:

我正在尝试计算每个骨骼的中线,本质上是一条沿着骨骼两侧中点的线,然后比较两条中线之间的角度。

我曾尝试使用 OpenCV 来获取骨骼的轮廓,但它似乎不够准确并且会获取大量额外数据。我被困在下一步如何移动以及如何计算中线。我对图像处理很陌生,但有使用 Python 的经验。

使用 OpenCV 结果获取边缘:

OpenCV 代码:

import cv2

# Load the image
img = cv2.imread("xray-3.jpg")

# Find the contours
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img,60,200)
im2, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

hierarchy = hierarchy[0] # get the actual inner list of hierarchy descriptions

# For each contour, find the bounding rectangle and draw it
cv2.drawContours(img, contours, -1, (0,255,0), 3)

# Finally show the image
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

【问题讨论】:

  • 没有愚蠢的超前卫超白文本标签有机会获得数据吗?
  • 使用分类器读取宽基/窄骨。你应该找到两个,一个向上/一个向下。然后从左到右对骨骼进行从黑到白到黑的水平扫描。在中心放置一个点。在不同的垂直位置执行多次扫描。连接每个分类器中的点以定义该骨骼的角度。
  • @zipzit horizo​​ntal 扫描会系统地将水平线与骨骼相交的中心相对于骨骼中心向左/向右移动,因为骨骼本身是不垂直于水平线,其边界是凹形的,不是线性的。我想说的是:要通过“水平”扫描找到中心,您必须在骨骼的正交方向上进行扫描,但为此您必须知道骨骼的角度,这就是我们想要的首先要找到...
  • @AndreyTyukin 。没有。拿一张纸、一条直尺和一支铅笔。试试吧。我不知道正确的几何描述。它就像 1700 年代的木匠使用尺子轻松细分测量值一样。真是老派。也许那发生在1600年代。您可以从任何角度进行扫描,只要扫描的两端穿过远离关节区域的骨骼即可。您只想在中间放置一个点,然后连接这些点。 Link
  • @zipzit 问题是x射线图像上没有“远离关节的区域”,至少它不足以将骨骼的图像近似为具有两个平行边的矩形.这是骨骼小角度的合理近似值,但如果它正是我们所追求的小角度,我认为这不会给出特别好的近似值。

标签: python image opencv graph hough-transform


【解决方案1】:

如果不是作弊,我建议将图像裁剪为不包含尽可能多的标签和比例,同时不删除任​​何感兴趣的区域。

话虽如此,如果您对图像进行一些预处理,我认为您获取轮廓的方法将是可用的。一种可以解决问题的算法是Difference of Gaussians (DoG) 过滤器,它会带出更多的边缘。我稍微修改了this code,它将使用几个不同的 sigmak 值来计算 DoG 过滤器。

from skimage import io, feature, color, filters, img_as_float
from matplotlib import pyplot as plt

raw_img = io.imread('xray-3.jpg')
original_image = img_as_float(raw_img)
img = color.rgb2gray(original_image)

k = 1.6

plt.subplot(2,3,1)
plt.imshow(original_image)
plt.title('Original Image')

for idx,sigma in enumerate([4.0, 8.0, 16.0, 32.0]):
    s1 = filters.gaussian(img, k*sigma)
    s2 = filters.gaussian(img, sigma)

    # multiply by sigma to get scale invariance
    dog = s1 - s2
    plt.subplot(2,3,idx+2)
    print("min: {} max: {}".format(dog.min(), dog.max())
    plt.imshow(dog, cmap='RdBu')
    plt.title('DoG with sigma=' + str(sigma) + ', k=' + str(k))

ax = plt.subplot(2, 3, 6)
blobs_dog = [(x[0], x[1], x[2]) for x in feature.blob_dog(img, min_sigma=4, max_sigma=32, threshold=0.5, overlap=1.0)]
# skimage has a bug in my version where only maxima were returned by the above
blobs_dog += [(x[0], x[1], x[2]) for x in feature.blob_dog(-img,  min_sigma=4, max_sigma=32, threshold=0.5, overlap=1.0)]

#remove duplicates
blobs_dog = set(blobs_dog)

img_blobs = color.gray2rgb(img)
for blob in blobs_dog:
    y, x, r = blob
    c = plt.Circle((x, y), r, color='red', linewidth=2, fill=False)
    ax.add_patch(c)
plt.imshow(img_blobs)
plt.title('Detected DoG Maxima')

plt.show()

乍一看,sigma=8.0, k=1.6 可能是您最好的选择,因为这似乎最好地夸大了小腿的边缘,同时消除了小腿上的噪音。特别是在受试者的左(右图)腿上。再试一次边缘检测,使用 ksigma 并告诉我你得到了什么 :)

如果结果看起来不错,您应该能够在图像的每一行中为任一腿检测到的边缘之间获得一个中心点。然后只需找到最适合任何一条腿的中点的线,你就可以开始了。您还需要将一条腿与另一条腿隔离开来,因此,如果不是作弊,可能会将图像从中间裁剪成两张图像。

【讨论】:

  • 这太棒了!裁剪图像以摆脱标签和额外信息,甚至获得单独的腿,绝对是可能的。我现在试试这个。谢谢你,这正是我想要的!
猜你喜欢
  • 2019-07-09
  • 1970-01-01
  • 2011-02-10
  • 2011-07-17
  • 1970-01-01
  • 2016-07-31
  • 2013-11-03
  • 2021-06-18
  • 2011-01-09
相关资源
最近更新 更多