使用skimage.morphology的skeletonize提取骨架无法识别横竖线如何优化
P&ID图纸骨架提取优化方案
核心问题说明
你当前代码最核心的错误是二值化后前景背景颠倒:skeletonize函数默认提取值为1的白色前景的骨架,你使用img > 阈值得到的结果中,白底对应1,黑色管线对应0,相当于在提取背景的骨架,自然识别不到管线。除此之外没有做干扰过滤、阈值选择不合适也是结果差的主要原因。
具体优化建议
- 替换全局阈值为自适应局部二值化:工程图纸普遍存在光照不均、线条粗细不一致的问题,全局阈值很容易导致细管线在二值化阶段丢失,使用OpenCV的自适应阈值能更好的保留边缘细节,同时记得反转二值结果,让管线作为前景值为1。
- 提前过滤非管线干扰:P&ID图纸中包含大量文字、仪表标识、设备填充图案等无关内容,可通过定向形态学操作分别提取水平、垂直管线,合并后再做骨架提取,大幅降低干扰。
- 增加后处理过滤噪声:骨架提取后移除像素数低于阈值的小连通域,去掉零散的噪声骨架点,只保留有效管线骨架。
优化后代码
import cv2 as cv from matplotlib import pyplot as plt from skimage.morphology import skeletonize, remove_small_objects # 读取灰度图像 img = cv.imread('realpars_p_id_diag_mod.png', 0) # 自适应局部二值化,反转后黑色管线为前景(值为1) binary = cv.adaptiveThreshold( img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, blockSize=11, C=2 ) binary = binary / 255 # 归一化到0-1区间 # 定向提取水平、垂直管线,过滤其他干扰内容 # 水平管线提取结构元,长度可根据图纸管线粗细调整 h_kernel = cv.getStructuringElement(cv.MORPH_RECT, (25, 1)) horizontal_pipe = cv.morphologyEx(binary, cv.MORPH_OPEN, h_kernel, iterations=1) # 垂直管线提取结构元 v_kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 25)) vertical_pipe = cv.morphologyEx(binary, cv.MORPH_OPEN, v_kernel, iterations=1) # 合并水平垂直管线得到待提取骨架的二值图 pipe_binary = cv.bitwise_or(horizontal_pipe, vertical_pipe) # 骨架提取+小噪声过滤 skeleton = skeletonize(pipe_binary) # 移除像素数小于50的零散连通域,阈值可自行调整 skeleton = remove_small_objects(skeleton.astype(bool), min_size=50) # 结果可视化 plt.figure(figsize=(24, 20)) plt.subplot(131) plt.imshow(img, cmap='gray') plt.title('原始图像') plt.xticks([]), plt.yticks([]) plt.subplot(132) plt.imshow(pipe_binary, cmap='gray') plt.title('管线提取二值图') plt.xticks([]), plt.yticks([]) plt.subplot(133) plt.imshow(skeleton, cmap='gray') plt.title('骨架提取结果') plt.xticks([]), plt.yticks([]) plt.savefig("skeleton_opt_result.png") plt.show()
内容的提问来源于stack exchange,提问作者anna mezcla
相关产品推荐
相关产品推荐

