当前位置: 首页 > news >正文

检测手绘图中不规则曲线交点的方法和一般规则线条交点的方法

检测手绘图中不规则曲线交点的方法

针对手绘图中的不规则曲线,传统几何方法不再适用。以下推荐几种有效处理不规则曲线交点的技术,结合图像处理方法和优化策略:

最佳方法:骨架化 + 交点检测算法

import cv2
import numpy as np
from skimage.morphology import skeletonize, thin
from scipy.ndimage import convolve

def find_handdrawn_intersections(image):
“”"
检测手绘曲线交点的完整流程
:param image: 输入手绘图(RGB或灰度)
:return: 交点坐标列表 [(x1, y1), (x2, y2), …]
“”"
# 1. 预处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else image
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 2. 骨架化处理(使曲线变为单像素宽)
skeleton = skeletonize(binary // 255).astype(np.uint8) * 255# 3. 自定义交点检测卷积核(检测至少3个方向的交叉)
kernel = np.array([[1, 2, 1],[2, 0, 2],[1, 2, 1]], dtype=np.uint8)# 4. 卷积运算识别交点候选
conv_result = convolve(skeleton, kernel)# 5. 提取交点(值在3-6表示有3-4个方向交叉)
intersections = []
min_val = 3 * 255  # 至少3条线交叉
max_val = 7 * 255  # 防止噪声点# 查找符合条件的点
for y in range(1, conv_result.shape[0]-1):for x in range(1, conv_result.shape[1]-1):if min_val <= conv_result[y, x] <= max_val:# 确保是真实交叉(排除相邻伪交点)if conv_result[y, x] > max(conv_result[y-1, x], conv_result[y+1, x], conv_result[y, x-1], conv_result[y, x+1]):intersections.append((x, y))# 6. 聚类去重(处理较粗线条生成多个相邻点)
clustered = []
if intersections:# 使用欧式距离聚类(20像素内归为同一交点)remaining = np.array(intersections)while len(remaining) > 0:centroid = remaining[0]distances = np.linalg.norm(remaining - centroid, axis=1)group = remaining[distances < 20]cluster_center = np.mean(group, axis=0).astype(int)clustered.append(tuple(cluster_center))remaining = remaining[distances >= 20]return clustered

替代方法:边缘跟踪 + 邻域分析

def edge_tracking_method(image):
“”“更保守的边缘跟踪交点检测”“”
# 1. 预处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape)==3 else image
edges = cv2.Canny(gray, 50, 150)

# 2. 细化边缘
skeleton = cv2.ximgproc.thinning(edges)# 3. 边缘跟踪
intersections = []
directions = [(1,0), (0,1), (-1,0), (0,-1), (1,1), (-1,1), (-1,-1), (1,-1)]# 扫描图像寻找十字点
for y in range(1, skeleton.shape[0]-1):for x in range(1, skeleton.shape[1]-1):if skeleton[y, x] == 255:  # 当前是边缘点neighbor_count = 0# 检查8邻域for dx, dy in directions:if skeleton[y+dy, x+dx] == 255:neighbor_count += 1# 4-6个邻接点表示可能是交点if 4 <= neighbor_count <= 6:# 验证确实是交叉点(排除曲线末端)orthogonal_neighbors = (skeleton[y, x-1] + skeleton[y, x+1] + skeleton[y-1, x] + skeleton[y+1, x])if orthogonal_neighbors >= 3*255:intersections.append((x, y))return intersections

可视化与测试

测试和可视化

def visualize_intersections(image, points):
display_img = image.copy() if len(image.shape)==3 else cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
for (x, y) in points:
cv2.circle(display_img, (x, y), 8, (0, 0, 255), -1) # 红色实心点标记交点
return display_img

使用示例

image_path = “handdrawn_diagram.png”
img = cv2.imread(image_path)

方法1:骨架化+卷积(更适合复杂图)

intersections = find_handdrawn_intersections(img)
result_img = visualize_intersections(img, intersections)

方法2:边缘跟踪(更保守,适合简单图)

intersections = edge_tracking_method(img)

cv2.imshow(“Detected Intersections”, result_img)
cv2.waitKey(0)

技术要点说明

  1. 为什么骨架化是必要的:
    • 手绘图线条厚度不均匀

    • 骨架化将曲线压缩为单像素宽的中心线

    • 使用Zhang-Suen或Guo-Hall算法(skimage.skeletonize或cv2.ximgproc.thinning)

  2. 关键卷积核设计原理:

    [[1, 2, 1],
    [2, 0, 2],
    [1, 2, 1]]

    • 中心点权重为0

    • 正交方向权重较高(2),对角方向较低(1)

    • 响应值范围3-6表示3-4个方向交叉

  3. 后处理优化:
    • 邻域最大值检测:保证识别交点中心而非边缘

    • 聚类去重:合并邻近点得到精确交点位置

    • 方向验证:排除曲线末端伪交点

  4. 手绘图的特殊处理:
    • 增强对比度:使用Otsu自适应性二值化

    • 抗锯齿处理:中值滤波保持边缘清晰

    • 断点连接:对小间隙进行形态学闭操作
    kernel = np.ones((3, 3), np.uint8)
    closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)

方法选择建议

方法 优点 适用场景

骨架化+卷积 准确性高,算法稳定 复杂手绘图,多曲线交叉

边缘跟踪 计算简单,速度快 简单示意图,曲线交叉点少

Hough变换 直线检测效果佳 以直线为主的设计图(不适合曲线)

深度学习法 鲁棒性强 有足够标注数据的高精度要求

针对特别混乱的手绘图(草图级)

可采用强化预处理流程:
def enhance_handdrawn(image):
“”“增强手绘图的预处理流程”“”
# 1. 自适应二值化
binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV, 11, 5)

# 2. 去除孤立噪点
cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, np.ones((2, 2), np.uint8))# 3. 连接小间隙
connected = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))# 4. 曲线增强
strengthened = cv2.dilate(connected, np.ones((3, 3), np.uint8), iterations=1)return strengthened

注意:对于铅笔草图等浅色绘图,可增加反卷积锐化或局部对比度增强(CLAHE)作为预处理步骤。

以上方法为实际工程中处理手绘图的成熟方案,可根据绘图质量调整参数以达到最佳效果。

在 OpenCV 中检测线条交点的两种方法比较

在计算机视觉中检测线条交点主要有两种方法:数学计算法(直接计算几何交点)和图像处理法(通过交集图计算交点)。以下是两种方法的详细实现和比较:

  1. 数学计算法(直接计算几何交点)

这种方法通过数学公式精确计算线条之间的交点坐标:
import cv2
import numpy as np

def line_intersection(line1, line2):
“”"
计算两条线段的交点
line1, line2: 格式为 (x1, y1, x2, y2)
返回交点坐标 (x, y) 或 None(当平行或不相交时)
“”"
# 提取线条端点
x1, y1, x2, y2 = line1
x3, y3, x4, y4 = line2

# 计算分母
denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)# 判断是否平行
if abs(denominator) < 1e-5:  # 平行或共线return None# 计算交点参数
ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator# 检查交点是否在线段上
if ua >= 0 and ua <= 1 and ub >= 0 and ub <= 1:x = x1 + ua * (x2 - x1)y = y1 + ua * (y2 - y1)return (int(x), int(y))return None  # 交点在线段延长线上

示例使用

假设有两组检测到的线段

horizontal_lines = [
(50, 100, 200, 100), # (x1, y1, x2, y2)
(50, 200, 200, 200)
]

vertical_lines = [
(100, 50, 100, 250),
(150, 50, 150, 250)
]

查找所有交点

intersections = []
for h_line in horizontal_lines:
for v_line in vertical_lines:
pt = line_intersection(h_line, v_line)
if pt:
intersections.append(pt)

在图像上绘制交点

image = np.zeros((300, 300, 3), dtype=np.uint8)

绘制横线

for x1, y1, x2, y2 in horizontal_lines:
cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)

绘制竖线

for x1, y1, x2, y2 in vertical_lines:
cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)

绘制交点

for pt in intersections:
cv2.circle(image, pt, 5, (255, 0, 0), -1)

cv2.imshow(“Line Intersections”, image)
cv2.waitKey(0)

  1. 图像处理法(使用交集图)

这种方法通过创建线条的图像并查找交集区域:
def find_intersections_with_image(lines, img_size=(300, 300)):
“”"
使用图像处理方法查找交点
lines: 所有线段的列表,格式为 (x1, y1, x2, y2)
img_size: 图像尺寸 (width, height)
“”"
# 创建空白图像
grid = np.zeros(img_size, dtype=np.uint8)

# 绘制所有线条(使用白色)
for line in lines:x1, y1, x2, y2 = map(int, line)cv2.line(grid, (x1, y1), (x2, y2), 255, 1)  # 绘制白色线条# 使用腐蚀操作加粗线条(可选)
kernel = np.ones((3, 3), np.uint8)
dilated = cv2.dilate(grid, kernel, iterations=1)# 查找交点(多个线条重叠的位置)
intersections = []
for y in range(img_size[1]):for x in range(img_size[0]):if dilated[y, x] >= 255 * 2:  # 多个线条重叠# 检查邻域确保是真实交点neighbors = dilated[max(0, y-1):y+2, max(0, x-1):x+2]if np.sum(neighbors) >= 255 * 4:intersections.append((x, y))return intersections

示例使用(使用与前例相同的线条)

all_lines = horizontal_lines + vertical_lines
image_intersections = find_intersections_with_image(all_lines)

在图像上绘制交点

for pt in image_intersections:
cv2.circle(image, pt, 5, (0, 255, 255), -1) # 黄色圆圈标记

cv2.imshow(“Image Method Intersections”, image)
cv2.waitKey(0)

方法比较

特点 数学计算法 图像处理法

精度 亚像素级高精度 像素级精度(受分辨率限制)

复杂度 需要复杂的几何计算 简单易实现(只需图像操作)

处理速度 O(m×n) 组合计算(m, n为线条数) O(w×h) 逐像素扫描

优势场景 少量精确线条 复杂线条网络、交叉点密集

交点确认 明确判断是否相交 可能误判近距离平行线

适用条件 需准确获取线段端点 无法区分平行和相交

推荐方法

对于大多数计算机视觉应用,数学计算法更优,因为:

  1. 提供亚像素级精度(尤其对检测到的线条端点已精确时)
  2. 可明确判断交点是否在有效线段范围内
  3. 避免了图像处理法的像素级别误差
  4. 算法时间复杂度通常更低(除非线条数量非常庞大)

但当面对以下情况时,图像处理法可能更适用:
• 图像中有密集交叉线网络

• 不关心确切的几何关系

• 难以准确获取线条端点时

• 需要简单快速的实现方案时

实际应用中可以根据具体需求和环境选择最适合的方法,或结合两种方法使用以提高鲁棒性。

http://www.dtcms.com/a/338248.html

相关文章:

  • rom定制系列------小米cc9机型 原生安卓15系统 双版线刷root 定制修改功能项
  • 力扣(分发糖果)
  • 【完整源码+数据集+部署教程】海洋垃圾与生物识别系统源码和数据集:改进yolo11-RVB
  • 深度优先遍历dfs(模板)
  • VS Code Copilot 完整使用教程(含图解)
  • 【笔记ing】考试脑科学 脑科学中的高效记忆法
  • 图论:Floyd算法
  • 从数学原理推导的角度介绍大语言MOE架构的本质
  • Linux系统WireShark抓取本地网卡报文
  • uv 现代化的虚拟环境管理工具
  • 量化线性层,将原始的fp16/bf16权重加载到Linear8bitLt模块中,调用int8_module.to(“cuda”)量化 (44)
  • 视频讲解:CatBoost、梯度提升 (XGBoost、LightGBM)对心理健康数据、交通流量及股票价格预测研究
  • Dubbo 的SPI
  • 深入解析RabbitMQ与AMQP-CPP:从原理到实战应用
  • IDEA 配置终端提示符样式,通过脚本方式
  • IntelliJ IDEA 开发配置教程
  • WPF---数据模版
  • 监督学习(Supervised Learning)和 无监督学习(Unsupervised Learning)详解
  • PCIe ASPM详解
  • 14.Linux线程(2)线程同步、线程安全、线程与fork
  • 【秋招笔试】2025.08.17大疆秋招机考第一套
  • plantsimulation知识点25.8.18-从一个RGV到另一台RGV,工件长度和宽度方向互换
  • pytest测试框架之基本用法
  • GPT-5之后:当大模型更新不再是唯一焦点
  • 本地搭建dify+deepseek智能体
  • 【unitrix数间混合计算】3.1 零标记trait(zero.rs)
  • 【最后203篇系列】033 Mongo副本集修复过程
  • Maven resources资源配置详解
  • 小程序被爬虫攻击,使用waf能防护吗?
  • Vision Master的C#脚本与opencv联合编程