调整和提高X射线图像的对比度及其质量

Bat*_*tub 2 python opencv image image-processing computer-vision

我想调整/提高手部 X 射线图像的对比度。我有大约 10000 张这样的 X 射线图像。我不想手动编辑它们,而是想对它们进行编码或自动化。数据集中的大多数图像都具有与这三幅图像类似的图像质量。

我已经尝试过这里这里的建议。但是,当我运行一些图像样本时,我得到与输入相同的输出。

有没有更好的方法来提高对比度,特别是手部 X 射线图像的对比度?因此,从这三个图像输入中,我希望它们看起来像这样。如果能自动完成,那就太棒了。如何编写此代码?

fmw*_*w42 7

我建议在 Python/OpenCV/Skimage 中使用 skimage (rescale_intensity) 来拉伸动态范围(在用平均颜色覆盖标签后)。它会自动查找输入的最小值和最大值,并将它们拉伸为全黑和全白(即 0 和 255),或者根据需要计算最小值和最大值以及偏差。

  • 读取输入
  • 转换为灰度
  • 模糊
  • 应用形态学关闭
  • 临界点
  • 获取轮廓并排除太小和太大的轮廓,以便选择标签。
  • 在灰度图像的副本上绘制填充轮廓,其值等于灰度图像的平均值,以覆盖标签
  • 使用 Skimage 将最小值和最大值分别拉伸到 0 和 255。如果您不需要偏置最小值或最大值,则可以将 (minval,maxval) 替换为“image”。它会自动计算 minval 和 maxval,您无需使用 Numpy 来查找它们。
  • 保存输出

import cv2
import numpy as np
import skimage.exposure

# load images
img1 = cv2.imread('xray1.webp')
img2 = cv2.imread('xray2.webp')
img3 = cv2.imread('xray3.webp')

# convert to gray
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
gray3 = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)

# blur
blur1 = cv2.GaussianBlur(gray1, (0,0), sigmaX=6, sigmaY=6)
blur2 = cv2.GaussianBlur(gray2, (0,0), sigmaX=6, sigmaY=6)
blur3 = cv2.GaussianBlur(gray3, (0,0), sigmaX=6, sigmaY=6)

# morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (45,45))
morph1 = cv2.morphologyEx(blur1, cv2.MORPH_CLOSE, kernel)
morph2 = cv2.morphologyEx(blur2, cv2.MORPH_CLOSE, kernel)
morph3 = cv2.morphologyEx(blur3, cv2.MORPH_CLOSE, kernel)

# threshold
thresh1 = cv2.threshold(morph1, 0, 255, cv2.THRESH_OTSU)[1] 
thresh2 = cv2.threshold(morph2, 0, 255, cv2.THRESH_OTSU)[1] 
thresh3 = cv2.threshold(morph3, 0, 255, cv2.THRESH_OTSU)[1] 

# get contours and filter on size
masked1 = gray1.copy()
meanval = int(np.mean(masked1))
contours = cv2.findContours(thresh1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > 500 and area < 50000:
        cv2.drawContours(masked1, [cntr], 0, (meanval), -1)
    
masked2 = gray2.copy() 
meanval = int(np.mean(masked2))
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > 500 and area < 50000:
        cv2.drawContours(masked2, [cntr], 0, (meanval), -1)

masked3 = gray3.copy() 
meanval = int(np.mean(masked3))
contours = cv2.findContours(thresh3, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > 500 and area < 50000:
        cv2.drawContours(masked3, [cntr], 0, (meanval), -1)

# stretch
minval = int(np.amin(masked1))
maxval = int(np.amax(masked1))
result1 = skimage.exposure.rescale_intensity(masked1, in_range=(minval,maxval), out_range=(0,255)).astype(np.uint8)
minval = int(np.amin(masked2))
maxval = int(np.amax(masked2))
result2 = skimage.exposure.rescale_intensity(masked2, in_range=(minval,maxval), out_range=(0,255)).astype(np.uint8)
minval = int(np.amin(masked3))
maxval = int(np.amax(masked3))
result3 = skimage.exposure.rescale_intensity(masked3, in_range=(minval,maxval), out_range=(0,255)).astype(np.uint8)

# save output
cv2.imwrite('xray1_stretched.png', result1)
cv2.imwrite('xray2_stretched.png', result2)
cv2.imwrite('xray3_stretched.png', result3)

# Display various images to see the steps
cv2.imshow('thresh1', thresh1)
cv2.imshow('thresh2', thresh2)
cv2.imshow('thresh3', thresh3)
cv2.imshow('result1', result1)
cv2.imshow('result2', result2)
cv2.imshow('result3', result3)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)

结果1:

在此输入图像描述

结果2:

在此输入图像描述

结果3:

在此输入图像描述