在最近的图像处理项目中,其中一个环节:图片中大量短线(不是噪声),需要在下一步处理前进行清除。在确定具体实现时,碰到了Canny边缘检测、霍夫变换与主动二值化处理的辩证使用,相关逻辑从图片灰度化以后开始,到短线的删除。

一、处理的主要流程如下:

      第一步:转换为灰度图;

      第二步:Canny的边缘检测;     

      第三步:霍夫变换直线检测;

      第四步:删除短线;

     以下是核心代码(Python):

    # 1、转换为灰度图gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)print(f"二值化: {np.unique(gray)}")# 2、优化的边缘检测参数,适合检测细线条edges = cv2.Canny(gray, 20, 60, apertureSize=3, L2gradient=True)# 3、使用霍夫变换检测直线(优化参数适合短线检测)lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=10, minLineLength=min_line_length,maxLineGap=2  # 减小间隙阈值,适合短线)# 4、要移除的短线if lines is not None:# 创建一个掩码用于绘制要移除的短线mask = np.zeros_like(edges)cv2.imwrite('mask1.jpg', mask)print(f"检测到 {len(lines)} 条直线")# 遍历所有检测到的线for line in lines:x1, y1, x2, y2 = line[0]# 计算线的长度line_length = np.sqrt((x2 - x1)**2 + (y2 - y1)** 2)print(f"要移除的短线长度:{line_length}")       print(f"要移除的短线端点:{x2},{y2},{x1},{y1}")       # 如果线的长度小于阈值(此处为100),则认为是短线,需要移除if line_length < 100:# 在掩码上绘制短线(白色)cv2.line(mask, (x1, y1), (x2, y2), 255, 3)# 找到掩码中非零的区域(即短线区域)cv2.imwrite('mask.jpg', mask)non_zero = cv2.findNonZero(mask)if non_zero is not None:# 二值化图像处理:直接将短线区域像素设为255(白色背景)# 注意:如果你的背景是黑色(0),则改为 result[mask != 0] = 0result[mask != 0] = 255

二、为什么霍夫变换前要进行Canny边缘检测

       先说结论:Canny 的核心作用是 “过滤无效信息,只给霍夫变换提供真正的边缘”。图片直接进行霍夫变换,会 “过度检测”,把灰度图中所有非纯白的区域都误判为直线,最终导致 mask 产生大量线条。

       理解其中缘由,需从霍夫变换的输入图像特性 和 Canny 边缘检测的作用 两方面分析:

1、霍夫变换(HoughLinesP)的核心逻辑

       HoughLinesP 是用来检测图像中的直线,它的输入是 “边缘图像”(即只有边缘像素为非零值的图像)。

  • 如果输入是原始灰度图(没经过 Canny):灰度图中所有非纯白(255)的像素都会被视为 “潜在边缘”;
  • 如果输入是 **Canny 后的边缘图 **:只有真正的边缘像素会被保留,背景是纯黑(0)。
2、Canny 边缘检测的作用

       Canny 是 “精准边缘提取器”,它会:

  1. 过滤噪声,只保留强边缘
  2. 把边缘细化为单像素宽度;
  3. 最终输出 “只有边缘是白色(255),背景是黑色(0)” 的图像。
3、没有Canny边缘检测,霍夫变换 “乱检测” 的原因

       当你直接把原始灰度图传给 HoughLinesP 时:

  • 灰度图中所有不是纯白(255)的区域,都会被 HoughLinesP 视为 “可能的直线片段”;
  • 原始图像中即使是平滑的灰度渐变、轻微的噪声,都会被误判为 “直线”,导致检测出大量虚假直线。
4、直观对比:有 Canny vs 无 Canny
步骤有 Canny 的情况无 Canny 的情况
输入图像只有 “强边缘” 的二值图(背景全黑)原始灰度图(包含大量非纯白的灰度像素)
HoughLinesP 检测只检测 “强边缘” 组成的直线,数量少且精准把所有 “非纯白区域” 都当边缘,检测出大量虚假直线
mask 标记结果只标记真正需要删除的短线,数量少标记大量虚假直线,mask 充满线条

       因此,通常Canny边缘检测,是霍夫变换精准检测直线的前提。

三、为什么Canny边缘检测前不要进行主动二值化处理

       Canny 边缘检测的输出是二值化图像,在 Canny 前主动做二值化,对 Canny 提取边缘的核心效果来说,确实没有多少价值,甚至可能产生反作用。可以从 Canny 的工作逻辑和二值化的局限性两方面来理解这个问题:

1、先明确:Canny 自身会 “隐性处理” 二值化逻辑

       Canny 边缘检测的核心是 “找灰度值突变的区域”(即边缘),它的流程里有两个关键步骤,本质上已经包含了 “类似二值化” 的筛选逻辑:

  1. 非极大值抑制:把梯度方向上的 “非边缘像素”(灰度变化不显著的)直接压成 0(黑色);
  2. 双阈值检测:用高、低两个阈值过滤 —— 只有梯度值超过 “高阈值” 的像素才被判定为 “强边缘”(设为 255),低于 “低阈值” 的直接舍弃(设为 0),介于两者之间的需依赖 “强边缘连接” 才保留(最终也是 255 或 0)。

       换句话说:Canny 会自己根据 “灰度变化强度”,把图像最终输出为 “边缘 = 255、背景 = 0” 的二值化边缘图,完全不需要依赖输入图像是否提前二值化。

2、更关键:提前二值化可能 “破坏 Canny 的边缘提取基础”

       Canny 提取边缘的核心依赖是 “图像的灰度梯度”(即相邻像素的灰度差异),而提前二值化会直接破坏这个梯度:

  • 二值化会把图像强行切成 “纯黑(0)” 和 “纯白(255)”,原本连续的灰度渐变(比如从 100→200 的平滑过渡)会变成 “0 和 255 的跳变”;
  • 这种 “跳变” 会让 Canny 误判出大量 “虚假边缘”(比如二值化后色块的边界,未必是你要的目标边缘),还可能让原本连续的目标边缘 “断裂”(比如细线条二值化后部分像素被压成 0,导致 Canny 无法连接完整边缘)。

       举个直观例子:如果你的原始图像是 “灰色背景上的黑色细线条”,提前二值化后,线条会变成纯黑(0)、背景变成纯白(255)—— 此时 Canny 确实能找到线条边缘,但如果线条本身有轻微灰度不均(比如部分像素是 10 而非 0),二值化会直接把这些像素 “一刀切” 成 0 或 255,反而可能让 Canny 提取的边缘变 “粗糙” 或 “不连续”;而如果直接给 Canny 输入灰度图,它能根据灰度梯度更精准地定位线条边缘,甚至修复轻微的灰度不均。

3、结论:Canny 前的二值化 “可省且建议省”

       对 Canny 来说,输入 “原始灰度图” 比 “提前二值化的图” 更友好

  • 原始灰度图保留了完整的 “灰度梯度信息”,Canny 能更精准地判断 “哪些是真边缘、哪些是噪声”;
  • 提前二值化不仅帮不上 Canny 的忙,还可能破坏梯度、引入虚假边缘,反而增加后续霍夫变换 “误检直线” 的概率。

        这样调整后,Canny 提取的边缘会更精准,霍夫变换误检的虚假直线会减少,通过mask标记查看,会发现其中检测出的短线主要是项目关注的短线。

四、结论

       “主动二值化” 只是简单的 “阈值分割”,无法替代 Canny 对边缘的 “精细化、连续化、去噪化” 处理。霍夫变换需要 “精准、连续的单像素边缘” 才能高效检测直线,通常Canny是必要的(它能进一步优化边缘质量)。

       实践验证,可分别对 “二值化图像” 和 “Canny 边缘图” 做霍夫变换,对比检测出的直线数量和精准度 —— 会发现 Canny 输出的边缘图,能让霍夫变换检测出更精准、更少的虚假直线。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/922061.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/922061.shtml
英文地址,请注明出处:http://en.pswp.cn/news/922061.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3与ue5通信-工具类

工具 ue5-simple.js /*** UE5 通信工具* 两个核心方法&#xff1a;发送消息和接收消息*/// 确保全局对象存在 if (typeof window ! undefined) {window.ue window.ue || {};window.ue.interface window.ue.interface || {}; }/*** 生成 UUID*/ function generateUUID() {retu…

在kotlin中如何使用像java中的static

在 Kotlin 中&#xff0c;没有直接的 static 关键字&#xff0c;但有几种等效的方式来实现 Java 中静态成员的功能&#xff1a; 1. 伴生对象 (Companion Object) - 最常用 class MyClass {companion object {// 静态常量const val STATIC_CONSTANT "constant value"…

如何在 Spring Boot 中指定不同的配置文件?

介绍 Spring Boot 提供了多种方式来管理和加载配置文件&#xff0c;特别是在多环境配置下&#xff0c;比如开发、测试和生产环境。通过指定不同的配置文件&#xff0c;可以灵活地调整应用程序的行为&#xff0c;以适应不同的需求。本文将介绍在 Spring Boot 中如何指定使用不同…

在centOS源码编译方式安装MySQL5.7

一、前言 在生产环境中部署数据库时&#xff0c;很多人会选择直接使用 yum/apt 包管理器 安装 MySQL&#xff0c;这样简单快速&#xff0c;但缺点是版本受限&#xff0c;灵活性不足。对于需要指定版本、启用特定编译参数或优化的场景&#xff0c;源码编译安装 MySQL 就显得非常…

探讨Hyperband 等主要机器学习调优方法的机制和权衡

本篇文章Master Hyperband — An Efficient Hyperparameter Tuning Method in Machine Learning深入探讨了Hyperband这一高效的超参数调优方法。文章的技术亮点在于其结合了多臂老虎机策略和逐次减半算法&#xff0c;能够在大搜索空间中快速剔除表现不佳的配置&#xff0c;从而…

Mysql:InnoDB 关键特性

目录 一、插入缓冲&#xff08;Change Buffer&#xff09;→ 快递驿站的 “临时存放区” 二、两次写&#xff08;Double Write&#xff09;→ 重要文件的 “备份存档” 三、自适应哈希索引&#xff08;AHI&#xff09;→ 图书馆的 “热门书快捷查找区” 四、异步 IO&#x…

STM32-----SPI

SPI简介SCK:和I2C中SCL的时钟线一个作用&#xff0c;都是在高电平拿出数据&#xff0c;在低电平写数据MOSI:主机输出从机输入MISO:主机输入从机输出&#xff0c;只有当对应从机的SS为低电平&#xff0c;从机的MISO引脚才能设置推挽输出&#xff0c;当从机SS为高电平时&#xff…

华为考试:HCIE数通考试难度分析

随着信息技术的飞速发展&#xff0c;网络技术已成为支撑各行各业运转的重要基础&#xff0c;市场对高水平网络技术人才的需求持续增长。HCIE作为华为认证体系中的最高级别认证&#xff0c;代表了网络技术领域的专业顶尖水平。本文将对HCIE数通认证的考试内容、难度及备考策略进…

一些常用的激活函数及绘图

深度网络的一些常用激活函数&#xff0c;并通过matplot绘制出来&#xff1a; import matplotlib.pyplot as plt import numpy as npdef relu(x):return np.maximum(0, x)def leaky_relu(x, alpha0.01):return np.where(x > 0, x, alpha * x)def gelu(x):return 0.5 * x * (1…

AE苹果手机iPhone 17展示动画片头模板 App Promo Phone 17 Pro

专为 App 发布会、电商促销、新品宣传 打造的 iPhone 17 Pro 动画展示 AE 模板。 4K 超清分辨率 26 张可替换照片位&#xff0c;无需第三方插件&#xff0c;拖拽即可输出专业级手机宣传片。 核心亮点 4K 超清&#xff1a;38402160 分辨率&#xff0c;大屏投放与社媒高清压缩无…

基于Python的云原生TodoList Demo 项目,验证云原生核心特性

以下是一个基于 Python 的云原生 TodoList Demo 项目&#xff0c;涵盖 容器化、Kubernetes 编排、CI/CD、可观测性、弹性扩缩容 等核心云原生特性&#xff0c;代码简洁且附详细操作指南&#xff0c;适合入门学习。项目概览 目标&#xff1a;实现一个支持增删改查&#xff08;CR…

go 日志的分装和使用 Zap + lumberjack

自带的log无法满足 按大小轮转 &#xff0c;按天数清理旧日志 &#xff0c;自动压缩 &#xff0c;限制备份数量 &#xff0c;防止磁盘写满 &#xff0c;生产环境推荐 等 使用 Zap lumberjack package mainimport ("go.uber.org/zap""go.uber.org/zap/zapcore&q…

【.Net技术栈梳理】01-核心框架与运行时(CLR)

文章目录1 .NET Runtime&#xff08;CLR-公共语言运行时&#xff09;1.1 中间语言 IL1.1.1 从源代码到通用中间语言&#xff08;IL&#xff09;1.1.2 运行时加载&#xff1a;CLR登场1.1.3 核心步骤&#xff1a;即时编译 (JIT Compilation)1.1.4 执行与内存管理&#xff08;GC&a…

Claude Code 平替:OpenAI发布 Codex CLI ,GPT-5 国内直接使用

openai推出的命令行编程工具codex已经可以使用最新 GPT-5 模型&#xff0c;拥有可媲美 Claude Code 的 AI 编码能力。本文将指导你在 Windows 系统上部署原生的 Codex CLI 程序&#xff0c;并接入超低价中转 API&#xff0c;让你在国内直接用上超高性价比的 OpenAI Codex CLI 应…

在VS2022的WPF仿真,为什么在XAML实时预览点击 ce.xaml页面控件,却不会自动跳转到具体代码,这样不方便我修改代码,

在VS2022的WPF仿真&#xff0c;为什么在XAML实时预览点击 WpfApp1\FunctionalModule\08Replace\Replace.xaml页面控件&#xff0c;却不会自动跳转到具体代码&#xff0c;这样不方便我修改代码&#xff0c;

Git Bash 别名

有些常用的指令参数非常多&#xff0c;每次都要输入好多参数&#xff0c;我们可以使用别名。Linux 系统中很多 shell&#xff0c;包括 bash&#xff0c;sh&#xff0c;zsh&#xff0c;dash 和 korn 等&#xff0c;不管哪种 shell 都会有一个 .bashrc 的隐藏文件&#xff0c;它就…

Centos7部署ceph存储

一、准备5台centos7主机 node节点双网卡&#xff08;1个内部检测&#xff0c;1个外部使用&#xff09;node节点都添加新网卡关闭防火墙和上下文都需要添加hosts文件都需要cat > /etc/hosts << EOF > 127.0.0.1 localhost localhost.localdomain localhost4 loca…

2025.9.10总结

今日感悟&#xff1a;刷到00后下班去菜市场捡菜的热点视频&#xff0c;确实挺有意思&#xff0c;不得不说&#xff0c;又省钱又好玩。虽然每天晚上能免费领个25块钱的水果回去&#xff0c;但确实没有什么新鲜感了。别人下班还能捡捡菜放松下&#xff0c;我下班&#xff0c;除了…

【数据结构与算符Trip第2站】稀疏数组

稀疏sparsearray数组 什么是稀疏数组&#xff1f; 稀疏数组是一种特殊的数据结构&#xff0c;用于高效存储和表示大部分元素为零&#xff08;或默认值&#xff09;的数组。它通过只存储非零元素的位置和值来节省内存空间。是一种压缩数组。 实现原理 在Go语言中&#xff0c;稀疏…

Sub-GHz无线收发单片机,低功耗物联网通信的硬件“基石”

随着物联网应用持续向规模化部署、广域化覆盖与高效化协同迈进&#xff0c; 作为IoT终端设备实现无线交互的核心通信单元之一——Sub-GHz无线收发单片机&#xff08;Sub-GHz射频收发芯片与单片机高度集成&#xff09;已成为系统设计中进一步简化外围元件数量、缩小硬件体积、降…