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

python的opencv操作记录12——Canny算子使用

文章目录

  • Canny算子
    • 非极大值抑制
    • 非极大值抑制中的插值
    • 滞后阈值
  • 实际应用
    • 直接使用Canny算子
    • 使用膨胀
    • 先阈值分割

Canny算子

上一篇说到,我在一个小项目里需要在一幅图像中提取一根试管里的两种液体的截面。为了达到这个目的使用传统图像里的区域分割技术,实际上就是想把这个图像分成两类,然后再找到这个两个类的边界。
上一张最后提到,我是使用一种拟合的方法来做的边界的判断,后来突然想到,opencv里面提供了现成的方法:边缘检测的Canny算子,直接就可以提取图像的边界。

Canny算子在官网上有介绍:

  • 调用方式:edges = cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradient)
  • 参数一:输入图像,为二值图像。
  • 参数二:阈值1,和阈值2一样,是用于控制边缘检测的度的,后面在详细过程说明中来描述。
  • 参数三:阈值2
  • 参数四:apertureSize,sobel算子的卷积大小。sobel算子用于计算图像的梯度,参考sobel算子的文章(https://blog.csdn.net/pcgamer/article/details/127942102?spm=1001.2014.3001.5502)
  • 参数五:L2gradient,是否使用二级梯度计算。实际上就是使用Laplacian算子进行二阶梯度计算,同样可以参考上面的那片文章。
  • 返回值就是一个只有边缘信息的二值图像。

Canny算子的一般介绍中,主要提到了一下几个步骤:

  • 噪声去除
  • 计算梯度
  • 非极大值抑制
  • 滞后阈值

非极大值抑制

噪声去除这个步骤一般是采用高斯模糊在做的,这个在滤波的那一篇中已经提到过,这里就不多说了,可以参考:
https://blog.csdn.net/pcgamer/article/details/124989015?spm=1001.2014.3001.5502

计算梯度之前也提过了,这里也不多说。
所以从非极大值抑制这里继续。

非极大值抑制,用人话说就是只留下最大值。那么,这里有几个问题:

  • 为什么留下最大值?
  • 留下什么最大值?就是这个最大值怎么定义?
  • 怎么留下最大值?

首先回答为什么的问题,在图像处理中,一般来说,边缘就是像素值变化最大的地方,这个很容易理解。
所以第二个问题也很简单,这里的最大值就是上文提到的梯度最大。而且是在梯度方向上梯度最大。
在写清晰度的那片文章中提到了梯度方向的计算方式,其实可以理解成当前边缘方向的法线放下那个,有点绕吧,用几个图来说明一下:
首先,梯度方向定义为arctan(gxgy)arctan(\frac{g_x}{g_y})arctan(gygx),也就是
在这里插入图片描述

放大到一整张图中:
在这里插入图片描述

黑线指向的方向就是梯度的方向。

那么上面说到非极大值抑制,就是要确定某一个点在这条梯度方向是是附近(局部)的最大值。一般来说,这个附近就是旁边的一个像素值。

非极大值抑制中的插值

虽然就是比较这个梯度方向上的三个像素点,但是这不是能直接比较的。

  • 首先,上面的梯度方向不是固定的,只有当这个梯度方向恰好是45度的整数倍时,才恰好对应到一个像素点:
    在这里插入图片描述

    • 可以从图中看到,如果是梯度方向是45,225的时候,中心像素点就是和对角线上的两个像素点比较(右上和左下)
    • 如果是梯度方向是135,315的时候,中心像素点就是和对角线上的两个像素点比较(左上和右下)
    • 如果是0,180,就是和左右两个像素点做比较
    • 如果是90和270度,就是和上下两个像素点做比较。
    • 上面的几种情况都是比较巧合的情况,但是如果不是这些角度呢?
  • 如果不是这些角度,就需要进行插值了,见下图:
    在这里插入图片描述

    比如上面的dTemp1这个点,很明显不是一个实际存在的像素点,这个像素点可以被称作一个亚像素(sub pixel),这个点的像素值可以根据旁边的两个实际像素点来插值计算,在canny算子中,插值方法就是普通的线性插值:
    这个亚像素的dTemp1的像素值就是:
    dTemp1=p1+LdTemp1−p1p2−p1dTemp1 = p1 + \frac{L_{dTemp1} - p1}{p2-p1}dTemp1=p1+p2p1LdTemp1p1
    上面的LdTemp1L_{dTemp1}LdTemp1可以根据梯度方向的gxgy\frac{g_x}{g_y}gygx来计算出来

    同样,下面的dTemp2也可以通过插值方法计算出来。

  • 插值计算完成后,就可以完成非极大值抑制的比较计算了。如果中心像素是最大的,那么就保留,不是极大值,则赋值为0。

  • 以上面的逻辑完成整张图像的计算,就完成了非极大值抑制这个过程的计算。

滞后阈值

完成非极大值抑制后,边缘已经精细了很多了,但是还不保证所有留下的像素点都是边缘,所以最后一步是通过阈值来控制这些留下的梯度值(从非极大值抑制出来的数据已经不是像素值,而是梯度值矩阵),单独通过一个阈值来控制过于简单粗暴,所以Canny算子用了两个。。。。

  • 如果高于T1,也就是两个阈值中较高的阈值,则保留。
  • 如果低于T2,也就是两个阈值中较低的阈值,则丢弃。
  • 中间的怎么办呢?从所有的高于T1的梯度值出发,如果能连接的上的中间值,则保留,否则就丢弃。
  • 一般来说T1 = 2T2

完成上面的滞后阈值计算后,就完成了Canny算子的边缘检测(当然最后是输出像素值的二值图像)

实际应用

直接使用Canny算子

不管三七二十一,我把之前的图转换成灰度图后,直接调用Canny算子:

    img = cv2.imread("./images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)edge = cv2.Canny(grey, 120, 54)cv2.imshow("origin", grey)cv2.imshow("result", edge)

效果非常的糟糕:
在这里插入图片描述

使用膨胀

因为Canny算子中的高斯模糊针对的是微小的高斯噪声,这个图像中的噪声都是大块的噪声,所以我就想着用膨胀函数试一下:

img = cv2.imread("./images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 做一把膨胀kernel_e = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))bin_clo = cv2.dilate(grey, kernel_e, iterations=10)edge = cv2.Canny(bin_clo, 120, 54)cv2.imshow("origin", grey)cv2.imshow("result", edge)

效果好了一点:
在这里插入图片描述

先阈值分割

但是还是去的不干净,而且最上面的分界线没有弄完成,突然想到上一次用大津法的阈值分割基本已经完成了前景和背景的分割,再加上一次阈值分割,用膨胀再清除一把,最后再做边缘检测:

img = cv2.imread("./images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 如果大于阈值,赋值为255,小于阈值,赋值为0# ret, binary = cv2.threshold(grey, 60, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)## 做一把腐蚀kernel_e = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))bin_clo = cv2.dilate(grey, kernel_e, iterations=10)edge = cv2.Canny(bin_clo, 120, 54)cv2.imshow("origin", grey)cv2.imshow("result", edge)

效果妥妥的:
在这里插入图片描述

大功告成!

相关文章:

python的opencv操作记录12——Canny算子使用

文章目录Canny算子非极大值抑制非极大值抑制中的插值滞后阈值实际应用直接使用Canny算子使用膨胀先阈值分割Canny算子 上一篇说到,我在一个小项目里需要在一幅图像中提取一根试管里的两种液体的截面。为了达到这个目的使用传统图像里的区域分割技术,实际…...

Spark on hive Hive on spark

文章目录Spark on hive & Hive on sparkHive 架构与基本原理Spark on hiveHive on sparkSpark on hive & Hive on spark Hive 架构与基本原理 Hive 的核心部件主要是 User Interface(1)和 Driver(3)。而不论是元数据库&a…...

【MySQL】子查询

这里写自定义目录标题子查询1、子查询的基本使用2、 单行子查询2.1、单行比较查询2.2、HAVING 中的子查询2.3、CASE中的子查询3、多行子查询4、相关子查询5、EXISTS 与 NOT EXISTS关键字子查询 子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQ…...

Day889.MySQL高可用 -MySQL实战

MySQL高可用 Hi,我是阿昌,今天学习记录的是关于MySQL高可用的内容。 正常情况下,只要主库执行更新生成的所有 binlog,都可以传到备库并被正确地执行,备库就能达到跟主库一致的状态,这就是最终一致性。但是…...

剑指 Offer 24. 反转链表

⭐简单说两句⭐ CSDN个人主页:后端小知识 🔎GZH:后端小知识 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 题目: 剑指 Offer 24. 反转链表 ,我们今天还是来看一道easy的题目吧&…...

“黑铁时代”,地产人如何以客户视角加速房企数字化转型

本文从行业洞察、业务设计、数据建设以及实践探索四个部分详细阐述地产行业数字化的实践、思考和理解。点击文末“阅读原文”,观看完整版直播回放并下载演讲文档。一、洞察:房企经营思路的变化企业的转型都是围绕着业务经营变化进行的,房企数…...

零入门kubernetes网络实战-14->基于veth pair、namespace以及路由技术,实现跨主机命名空间之间的通信测试案例

《零入门kubernetes网络实战》视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 本篇文章继续提供测试案例: 基于veth pair、namespace以及路由技术,实现跨主机命名空间之间的通信 1、网络拓扑如下 2、网络拓扑构建…...

【pytorch框架】对模型知识的基本了解

文章目录TensorBoard的使用1、TensorBoard启动:2、使用TensorBoard查看一张图片3、transforms的使用pytorch框架基础知识1 nn.module的使用2 nn.conv2d的使用3、池化(MaxPool2d)4 非线性激活5 线性层6 Sequential的使用7 损失函数与反向传播8 优化器9 对现有网络的使…...

SUP桨板电动气泵方案——鼎盛合方案

SUP桨板是现时最热门的水上运动之一,它的全称是Stand Up Paddle,简称SUP。这项运动近几年在我国三亚等地区风靡一时,在网上经常看到一些运动博主或者明星网红晒出冲浪视频,刺激又惊险。SUP桨板为充气式桨板,需要通过充…...

小白系列Vite-Vue3-TypeScript:011-登录界面搭建及动态路由配置

前面几篇文章我们介绍的都是ViteVue3TypeScript项目中环境相关的配置,接下来我们开始进入系统搭建部分。本篇我们来介绍登录界面搭建及动态路由配置,大家一起撸起来......搭建登录界面登陆接口api项目登陆接口是通过mockjs前端来模拟的模拟服务接口Login…...

C语言( 缓冲区和重定向)

一.缓冲输入,无缓存输入 while((chgetchar()) ! #) putchar(ch); 这里getchar(),putchar()每次只处理一个字符(这里只是知道就好了),而我们使用while循环,当读到#字符时停止 而看到输出例子,第一行我们输入…...

编程思想、方法论和架构的类型及应用

概要编程思想是指在编写代码时所采用的基本思维方式和方法论。分类编程思想编程思想为软件开发提供了思维范式和指导思路,例如面向对象思想、函数式编程思想等,它们帮助程序员更好地抽象问题、组织代码、提高代码复用性和可维护性,包括一下几…...

【OA办公】OA流程审批大揭秘,带你看遍所有基础流程

流程审批,是所有企业的OA办公系统重要组成部分,是任何OA办公系统都不可缺少的。比起传统的纸张传阅、签批的审批模式浪费了大量的时间和成本,因此越来越多的企业采用OA这种全新的、高效的、智能的审批模式。流程审批除了这些好处,…...

《零基础入门数据结构与算法》专栏介绍

目录 前言 第一部分:重点 第二部分:题库 第三部分:测试 第四部分:实验 第五部分:试卷 总结 前言 本专栏主要分为五个部分: ① 重要知识点详解 ② 近百道练习题解析 ③ 数据结构与算法章节测试 …...

测试开发之Django实战示例 第九章 扩展商店功能

第九章 扩展商店功能在上一章里,为电商站点集成了支付功能,然后可以生成PDF发票发送给用户。在本章,我们将为商店添加优惠码功能。此外,还会学习国际化和本地化的设置和建立一个推荐商品的系统。本章涵盖如下要点:建立…...

【Spring】一文带你吃透AOP面向切面编程技术(下篇)

个人主页: 几分醉意的CSDN博客_传送门 上节我们介绍了什么是AOP、Aspectj框架的前置通知Before传送门,这篇文章将继续详解Aspectj框架的其它注解。 文章目录💖Aspectj框架介绍✨JoinPoint通知方法的参数✨后置通知AfterReturning✨环绕通知Ar…...

【java】Spring Boot --40 个 Spring Boot 常用注解(建议收藏)

本文目录一、Spring Web MVC 注解Spring Web MVC 注解RequestMappingRequestBodyGetMappingPostMappingPutMappingDeleteMappingPatchMappingControllerAdviceResponseBodyExceptionHandlerResponseStatusPathVariableRequestParamControllerRestControllerModelAttributeCross…...

《游戏学习》| 微信对话模拟生成器源码分析

简介微信对话生成器,是一款在线微信聊天对话制作的工具,它可以设置苹果或安卓状态栏,包括手机电量、手机时间等,还可以设置不同用户的角色,然后发送文字、语音、红包、转账等多种好玩的功能,可谓是一款娱乐…...

剑指 Offer 10- I. 斐波那契数列[c语言]

目录题目思路代码结果该文章只是用于记录考研复试刷题题目 力扣斐波那契数列 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: F(0) 0, F(1) 1 …...

【C#基础】C# 数据类型总结

序号系列文章0【C#基础】初识编程语言C#1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析文章目录前言数据类型一. 值类型(Value types)二. 引用类型(Reference types)三. 指针类型(Pointer types)结…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​,覆盖应用全生命周期测试需求,主要提供五大核心能力: ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...