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

Julia环境下Canny边缘检测:轮廓点提取与自定义步长多边形逼近

解决Julia 1.10中Blob轮廓提取与自定义步长多边形逼近问题

一、替换弃用的Contour.jl:提取每个Blob的轮廓点

由于Contour.jl部分函数已弃用,我们可以先通过图像分割得到每个Blob的连通区域,再提取其轮廓点:

  • 对预处理后的Canny边缘图转二值化,明确边缘区域
  • 使用label_components标记每个独立的Blob连通边缘
  • 对每个标记区域,将像素坐标转换为常规几何坐标并按顺序排列

二、自定义步长的多边形逼近实现

要实现固定步长(如20μm)的多边形逼近,核心是将轮廓点按指定距离间隔重采样:

  1. 计算轮廓的累积弧长,确定总长度
  2. 将目标步长(μm单位)转换为像素单位,生成等距采样的弧长位置
  3. 通过插值方法(线性或Catmull-Rom)获取对应位置的坐标点,形成逼近多边形

三、完整代码示例

using Images, ImageMorphology, ImageEdgeDetection, ImageSegmentation, TestImages, 
LinearAlgebra, FileIO, Interpolations

# 图像像素与微米的比例(根据实际图像分辨率调整)
SCALE_PX_PER_UM = 1.0  # 示例:1像素对应1μm
TARGET_STEP_UM = 20    # 目标步长20μm
TARGET_STEP_PX = TARGET_STEP_UM * SCALE_PX_PER_UM

# 加载图像
function load_image()
    img = testimage("blobs")
    return Gray.(img)
end

# 预处理图像并提取边缘
function preprocess_image(img, scale)
    img = erode(dilate(img))  # 开运算去噪
    alg = Canny(spatial_scale=scale, high=Percentile(80), low=Percentile(20))
    edges = detect_edges(img, alg)
    edges_bin = edges .> 0.5  # 转二值边缘图
    return img, edges_bin
end

# 提取每个Blob的有序轮廓点
function extract_blob_contours(edges_bin)
    labels = label_components(edges_bin)
    contours = []
    for label in 1:maximum(labels)
        region_points = findall(labels .== label)
        # 转换为(x,y)几何坐标(Images.jl默认索引是(y,x))
        x_coords = [Tuple(p)[2] for p in region_points]
        y_coords = [Tuple(p)[1] for p in region_points]
        # 按质心角度排序,确保轮廓点有序
        centroid = (mean(x_coords), mean(y_coords))
        angles = atan.(y_coords .- centroid[2], x_coords .- centroid[1])
        sorted_idx = sortperm(angles)
        sorted_pts = hcat(x_coords[sorted_idx], y_coords[sorted_idx])
        push!(contours, sorted_pts)
    end
    return contours
end

# 对单个轮廓进行自定义步长重采样
function resample_contour(contour_pts, step_px)
    n = size(contour_pts, 1)
    # 闭合轮廓:首尾相连
    contour_closed = vcat(contour_pts, contour_pts[1:1, :])
    # 计算相邻点距离与累积弧长
    dists = [norm(contour_closed[i+1,:] - contour_closed[i,:]) for i in 1:n]
    cum_dists = cumsum(dists)
    total_length = cum_dists[end]

    # 生成等距采样的弧长位置
    sample_dists = 0:step_px:total_length
    sample_dists[end] < total_length && (sample_dists = vcat(sample_dists, total_length))

    # 线性插值获取采样点
    itp_x = interpolate(cum_dists, contour_closed[1:n,1], Gridded(Linear()))
    itp_y = interpolate(cum_dists, contour_closed[1:n,2], Gridded(Linear()))
    sampled_x = [itp_x(d) for d in sample_dists]
    sampled_y = [itp_y(d) for d in sample_dists]

    return hcat(sampled_x, sampled_y)
end

# 主流程
img = load_image()
img1, edges_bin = preprocess_image(img, 0.85)
contours = extract_blob_contours(edges_bin)
polygons = [resample_contour(contour, TARGET_STEP_PX) for contour in contours]

# 示例:输出第一个Blob的逼近多边形点
println("第一个Blob的逼近多边形点:")
display(polygons[1])

四、关键说明

  • 坐标转换:Images.jl的像素索引是(y,x),需转换为常规(x,y)坐标用于几何计算
  • 轮廓排序:通过质心角度排序确保轮廓点按顺时针/逆时针排列,避免重采样时出现混乱
  • 插值选择:代码使用线性插值,若需要更平滑的结果,可替换为CatmullRom插值(调整Interpolations的参数即可)
  • 步长转换:SCALE_PX_PER_UM必须根据实际图像的分辨率设置,确保步长单位从μm正确转换为像素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:34:51