Julia环境下Canny边缘检测:轮廓点提取与自定义步长多边形逼近
解决Julia 1.10中Blob轮廓提取与自定义步长多边形逼近问题
一、替换弃用的Contour.jl:提取每个Blob的轮廓点
由于Contour.jl部分函数已弃用,我们可以先通过图像分割得到每个Blob的连通区域,再提取其轮廓点:
- 对预处理后的Canny边缘图转二值化,明确边缘区域
- 使用
label_components标记每个独立的Blob连通边缘 - 对每个标记区域,将像素坐标转换为常规几何坐标并按顺序排列
二、自定义步长的多边形逼近实现
要实现固定步长(如20μm)的多边形逼近,核心是将轮廓点按指定距离间隔重采样:
- 计算轮廓的累积弧长,确定总长度
- 将目标步长(μm单位)转换为像素单位,生成等距采样的弧长位置
- 通过插值方法(线性或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
相关产品推荐
相关产品推荐

