You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于中指的手部X光图像拉直(OpenCV)技术实现及问题解决

手部X光图像中指拉直预处理完整方案及问题解决

背景与已完成预处理

需处理约10000张手部X光图像,目标是将中指拉直。已完成以下预处理步骤:

  • 对图像应用Gaussian Blur及Threshold(Binary + Otsu)处理;
  • 执行dilation操作,将手部合并为单一对象;
  • 使用cv2.findContours()提取手部边缘轮廓;
  • 应用cv2.convexHull()和cv2.convexityDefects()标记凸包最远点,筛选出距离凸包超阈值的指缝点。

已实现的代码如下:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img_path = "sample_image.png"

# 图像阈值处理
image = cv2.imread("sample_image.png")
original = image.copy() 
blank = np.zeros(image.shape[:2], dtype = np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (127,127), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# 膨胀操作合并手部区域
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations = 2)

# 提取最大手部轮廓
contours, hierarchy = cv2.findContours(dilate, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = max(contours, key = lambda x: cv2.contourArea(x))

cv2.drawContours(image, [contours], -1, (255,255,0), 2)

# 标记凸包缺陷点(指缝)并存储
finger_gaps = []
hull = cv2.convexHull(contours, returnPoints = False)
defects = cv2.convexityDefects(contours, hull)
for i in range(defects.shape[0]):
    _, _, farthest_point_index, distance = defects[i, 0]
    farthest_point = contours[farthest_point_index][0]
    # 改用轮廓面积比例作为动态阈值,适配不同大小图像
    if distance > 0.001 * cv2.contourArea(contours):
        finger_gaps.append(farthest_point)
        circle = cv2.circle(image, farthest_point, 20, [0,0,255], -1)

下一步需求

  1. 从筛选出的指缝点中识别出靠近中指的中间两点;
  2. 沿中指方向旋转图像实现拉直。

现存问题

  • 中指较短的X光图处理失效;
  • 左倾手部拉直后方向倒置(已通过ellipse_angle = ((ellipse_angle + 90) % 180) - 90修正,但需结合完整逻辑)。

完整解决方案

1. 中指区域定位与中间指缝点识别

针对中指较短的情况,结合椭圆拟合与指尖点检测补充定位逻辑:

代码实现:

# 拟合手部椭圆,获取方向信息并修正角度
ellipse = cv2.fitEllipse(contours)
(x, y), (MA, ma), angle = ellipse
# 修正角度,解决左倾倒置问题
angle = ((angle + 90) % 180) - 90

# 检测指尖点(凸包顶点)
hull_points = cv2.convexHull(contours, returnPoints=True)
# 按y坐标排序,取顶部5个点作为候选指尖(假设手臂在下,指尖在上)
hull_points_sorted = sorted(hull_points, key=lambda p: p[0][1])
candidate_fingertips = hull_points_sorted[:5]

# 定位中指两侧的指缝点
middle_gaps = []
if len(finger_gaps) >= 2:
    # 根据椭圆角度判断左右手,调整排序方向
    finger_gaps_sorted = sorted(finger_gaps, key=lambda p: p[0])
    if angle > 0:
        # 左手情况,反转排序
        finger_gaps_sorted = finger_gaps_sorted[::-1]
    # 取中间的两个指缝点
    middle_gaps = finger_gaps_sorted[1:3] if len(finger_gaps_sorted)>=3 else finger_gaps_sorted[:2]
else:
    # 指缝点不足时,结合中间指尖生成虚拟指缝点
    if len(candidate_fingertips)>=3:
        middle_tip = candidate_fingertips[1][0]
        # 基于指尖位置生成左右偏移点作为替代指缝
        middle_gaps.append((middle_tip[0]-30, middle_tip[1]))
        middle_gaps.append((middle_tip[0]+30, middle_tip[1]))

2. 图像旋转拉直

基于中指方向(指缝连线或椭圆修正角度)旋转图像:

def rotate_image(image, angle, center=None, scale=1.0):
    (h, w) = image.shape[:2]
    if center is None:
        center = (w // 2, h // 2)
    # 获取旋转矩阵
    M = cv2.getRotationMatrix2D(center, angle, scale)
    # 计算旋转后的图像尺寸,避免裁剪
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    new_w = int((h * sin) + (w * cos))
    new_h = int((h * cos) + (w * sin))
    # 调整平移参数,使图像居中
    M[0, 2] += (new_w / 2) - center[0]
    M[1, 2] += (new_h / 2) - center[1]
    # 执行旋转,使用抗锯齿与边界填充
    rotated = cv2.warpAffine(image, M, (new_w, new_h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
    return rotated

# 确定旋转角度
rotate_angle = 0
if len(middle_gaps) == 2:
    # 计算指缝连线的角度
    dx = middle_gaps[1][0] - middle_gaps[0][0]
    dy = middle_gaps[1][1] - middle_gaps[0][1]
    gap_angle = np.degrees(np.arctan2(dy, dx))
    rotate_angle = -gap_angle
else:
    # 用修正后的椭圆角度作为替代
    rotate_angle = -angle

# 旋转原始图像与预处理图像
rotated_original = rotate_image(original, rotate_angle)
rotated_processed = rotate_image(image, rotate_angle)

# 可视化结果
plt.figure(figsize=(12,6))
plt.subplot(121), plt.imshow(cv2.cvtColor(original, cv2.COLOR_BGR2RGB)), plt.title('Original')
plt.subplot(122), plt.imshow(cv2.cvtColor(rotated_original, cv2.COLOR_BGR2RGB)), plt.title('Rotated')
plt.show()

3. 针对中指较短情况的优化

  • 动态阈值:将凸包缺陷的距离阈值改为基于轮廓面积的比例值,适配不同大小的手部图像;
  • 指尖辅助:当指缝点不足时,利用椭圆长轴方向与指尖位置生成虚拟指缝点;
  • 左右手自动判断:通过椭圆拟合角度与指尖分布,自动调整指缝点排序,避免定位偏差。

内容的提问来源于stack exchange,提问作者Bathtub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:12:09