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

如何从带曲线及不光滑边缘的线条骨架中获取线条宽度?

弯曲不光滑线条宽度估算的Julia实现方案

核心步骤与代码实现

1. 图像预处理(降噪+二值化)

先对原始图像做灰度转换、二值化和降噪,减少后续处理的干扰:

using Images, ImageMorphology, ImageFiltering

# 读取并预处理图像
img = load("你的图像路径.png")
gray_img = Gray.(img)
# Otsu法自动二值化
binary_img = binarize(gray_img, Otsu())
# 3x3中值滤波降噪
denoised_img = imfilter(binary_img, Kernel.median((3,3)))

2. 提取线条骨架

用形态学骨架提取函数得到线条的中心骨架:

skeleton = skeletonize(denoised_img)

3. 计算骨架点的正交方向

通过Sobel算子计算骨架的梯度,推导正交方向(垂直于线条切线的方向):

# 计算Sobel梯度
sobel_x = Kernel.sobel()[1]
sobel_y = Kernel.sobel()[2]
grad_x = imfilter(convert(Array{Float64}, skeleton), sobel_x)
grad_y = imfilter(convert(Array{Float64}, skeleton), sobel_y)

# 正交方向角度(梯度方向偏移π/2)
ortho_angles = atan.(grad_y, grad_x) .+ π/2

4. 沿正交方向测量宽度

遍历每个骨架点,沿正交正负方向搜索边缘,记录两侧距离并求和:

# 获取所有骨架点坐标
skeleton_points = findall(skeleton .== 1)
widths = Float64[]

for point in skeleton_points
    x, y = Tuple(point)
    angle = ortho_angles[x, y]
    
    # 正方向搜索边缘
    dist_pos = 0
    curr_x, curr_y = x, y
    while true
        curr_x += round(Int, cos(angle))
        curr_y += round(Int, sin(angle))
        # 边界检查
        if curr_x < 1 || curr_x > size(img,1) || curr_y <1 || curr_y > size(img,2)
            break
        end
        if denoised_img[curr_x, curr_y] == 0
            break
        end
        dist_pos += 1
    end
    
    # 负方向搜索边缘
    dist_neg = 0
    curr_x, curr_y = x, y
    while true
        curr_x -= round(Int, cos(angle))
        curr_y -= round(Int, sin(angle))
        if curr_x <1 || curr_x > size(img,1) || curr_y <1 || curr_y > size(img,2)
            break
        end
        if denoised_img[curr_x, curr_y] == 0
            break
        end
        dist_neg +=1
    end
    
    # 总宽度=两侧距离+自身点
    push!(widths, dist_pos + dist_neg + 1)
end

# 计算平均宽度
avg_width = mean(widths)
println("估算平均线条宽度:", avg_width)

5. 简化替代方案(距离变换法)

如果不需要逐点正交搜索,可用距离变换快速估算:

# 对背景做距离变换,前景点到最近背景的距离
dist_transform = distance_transform(1 .- denoised_img)
# 骨架点的距离值乘以2即为近似宽度
skeleton_dist = dist_transform[skeleton_points]
avg_width_dist = mean(skeleton_dist) * 2
println("距离变换法估算平均宽度:", avg_width_dist)

优化建议

  • 若骨架局部噪声大,可先对二值图像做dilate再erode的开闭运算,平滑边缘后再提取骨架。
  • 对于曲率极大的区域,可改用邻域点拟合直线的方式计算切线方向,避免梯度法的误差。
  • 过滤掉宽度异常值(比如远大于平均值的点)后再计算平均,结果更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 11:28:06