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

如何提升Python中物体中心延伸臂的图像直线检测精度?

识别物体中心向外延伸的投影线问题

目标需求

我正尝试识别物体中心向外延伸的投影线,示例目标效果如下:
img1 img2
img3 img4

当前尝试方案及效果

目前已尝试步骤:找到物体轮廓后填充物体,提取填充后图像的骨架,再应用Hough Line Transform统计直线数量,效果如下:
img5
img6
img7

但该方法未达到预期效果,当前使用代码如下:

import cv2
import numpy as np

from skimage.transform import hough_line, hough_line_peaks
from skimage import io
import matplotlib.pyplot as plt
from matplotlib import cm
from skimage import color
from imutils import paths 
from skimage.morphology import skeletonize


# Load the image
img = cv2.imread("image.PNG")


plt.imshow(img[:,:,::-1])
plt.show()

thickness = 5

# Get image dimensions
height, width = img.shape[:2]

# Define border dimensions
top = bottom = thickness
left = right = thickness

# Create border mask
border_mask = np.zeros((height, width, 3), np.uint8)  # Ensure the mask has the same number of channels as the image
border_mask[top:height-bottom, left:width-right] = 255

# Add thickness to edges of image
result = cv2.bitwise_and(img, border_mask)

# Add black border
result = cv2.copyMakeBorder(result, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(0,0,0)) 
# Convert the image to grayscale (if it's not already)
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)

# Apply thresholding
_, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# Find contours in the thresholded image
contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Draw the contours on a copy of the original image
contour_image = img.copy()
cv2.drawContours(contour_image, contours, -1, (255, 255, 255), 40)
# Taking a matrix of size 5 as the kernel
kernel = np.ones((5, 5), np.uint8)

img_dilation = cv2.dilate(contour_image, kernel, iterations=10)

# Bitwise AND operation to fill the image
result = cv2.bitwise_and(img, img_dilation)

plt.imshow(result)
plt.show()


skeleton = skeletonize(result)

image = cv2.cvtColor(skeleton, cv2.COLOR_BGR2GRAY)
# Classic straight-line Hough transform
# Set a precision of 0.05 degree.
tested_angles = np.linspace(-np.pi / 2, np.pi / 2, 180)

h, theta, d = hough_line(image, theta=tested_angles)
hpeaks = hough_line_peaks(h, theta, d, threshold=0.2 * h.max())
print(len(hpeaks[0]))

plt.imshow(mask,cmap='gray')
# display the skeletonized image
fig, axes = plt.subplots()
axes.imshow(skeleton, cmap=plt.cm.gray)
axes.set_title('Skeleton of the image')
plt.show()

skeleton_copy = skeleton.copy()

for _, angle, dist in zip(*hpeaks):
    a = np.cos(angle)
    b = np.sin(angle)
    x0 = a * dist
    y0 = b * dist
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(skeleton_copy, (x1, y1), (x2, y2), (0, 0, 255), 2)

plt.imshow(skeleton_copy)
plt.show()

优化建议

1. 简化预处理流程,聚焦核心区域

当前边框处理和膨胀步骤冗余,建议直接针对目标物体做精准处理:

  • 灰度化后直接二值化,提取最大轮廓(目标物体)
  • 使用cv2.drawContours填充轮廓,得到纯净的物体掩码,替代复杂的膨胀+位运算操作,避免引入额外噪声

2. 修正骨架提取逻辑

skimage.morphology.skeletonize要求输入为单通道二值图(0/1),当前传入彩色图会导致错误,需先转灰度再归一化到0-1范围。

3. 优化Hough直线检测参数

  • 缩小角度步长,比如用np.linspace(-np.pi/2, np.pi/2, 360)提升角度检测精度
  • 调整hough_line_peaks的threshold、min_distance参数,过滤重复或噪声直线
  • 增加num_peaks限制,只保留最显著的直线

4. 基于物体中心筛选直线

先计算物体重心坐标,只保留经过中心附近的直线,过滤无关边缘噪声:

  • 通过轮廓矩计算中心:M = cv2.moments(max_contour),cx = int(M["m10"]/M["m00"]),cy = int(M["m01"]/M["m00"])
  • 计算直线到中心的距离,筛选距离小于阈值的直线

优化后示例代码

import cv2
import numpy as np
from skimage.morphology import skeletonize
from skimage.transform import hough_line, hough_line_peaks
import matplotlib.pyplot as plt

# 加载图像并预处理
img = cv2.imread("image.PNG")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 根据图像明暗自动选择二值化方向
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV if np.mean(gray) > 127 else cv2.THRESH_BINARY)

# 提取最大轮廓并填充
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
max_contour = max(contours, key=cv2.contourArea)
mask = np.zeros_like(gray)
cv2.drawContours(mask, [max_contour], -1, 255, thickness=cv2.FILLED)

# 计算物体中心
M = cv2.moments(max_contour)
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])

# 骨架化(转成0-1二值图)
skeleton = skeletonize(mask / 255)

# Hough直线检测,优化参数
tested_angles = np.linspace(-np.pi/2, np.pi/2, 360)
h, theta, d = hough_line(skeleton, theta=tested_angles)
# 调整阈值、最小距离,限制峰值数量
hpeaks = hough_line_peaks(h, theta, d, threshold=0.3*h.max(), min_distance=20, num_peaks=8)

# 绘制结果
skeleton_copy = (skeleton * 255).astype(np.uint8)
skeleton_copy = cv2.cvtColor(skeleton_copy, cv2.COLOR_GRAY2BGR)
cv2.circle(skeleton_copy, (cx, cy), 5, (0,255,0), -1)  # 标记中心

for _, angle, dist in zip(*hpeaks):
    a = np.cos(angle)
    b = np.sin(angle)
    x0 = a * dist
    y0 = b * dist
    # 延长直线至图像边界
    x1 = int(x0 + img.shape[1] * (-b))
    y1 = int(y0 + img.shape[0] * (a))
    x2 = int(x0 - img.shape[1] * (-b))
    y2 = int(y0 - img.shape[0] * (a))
    # 筛选经过中心附近的直线
    if abs((a*cx + b*cy) - dist) < 10:
        cv2.line(skeleton_copy, (x1, y1), (x2, y2), (0,0,255), 2)

plt.imshow(cv2.cvtColor(skeleton_copy, cv2.COLOR_BGR2RGB))
plt.title("优化后的中心投影线检测")
plt.show()

其他补充建议

  • 若图像噪声大,二值化前可增加cv2.GaussianBlur或cv2.medianBlur去噪
  • 多物体场景下,可通过轮廓面积过滤,只处理感兴趣的物体
  • 考虑使用概率霍夫变换(cv2.HoughLinesP),直接检测线段,更适合提取短投影线

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:45:03