11篇--图像边缘检测

图像梯度

要学习图像边缘检测,要先了解图像梯度的概念,我们正是通过梯度值来区分边缘像素点的

处于边缘附近的像素点与周围像素点的差距很大(不然不会有边缘呈现),所以给边缘附近的的梯度之变化很快,通过计算梯度值,来进行边缘检测。

通常有如下两种方式处理计算得到的新值:

  • 截断处理:将小于0的值设置为0,将大于255的值设置为255。这种方法简单直接,但可能会导致图像在极端值处出现不自然的截断。
  • 归一化处理:将计算得到的值线性映射到0到255的范围内。这种方法可以保留更多的细节信息,但可能需要额外的计算。

梯度处理方式

cv2.filter2D()函数

功能:用于对图像进行卷积操作。卷积是图像处理中的一个基本操作,它通过一个称为卷积核(或滤波器)的小矩阵在图像上滑动,并对每个位置进行加权求和,从而得到新的图像。

参数:

  • src:输入图像,可以是灰度图像或彩色图像。
  • ddepth:输出图像的所需深度。对于输入图像和输出图像具有相同深度的情况,该值通常设置为 -1。否则,你可以选择一个特定的深度,如 cv2.CV_8U、cv2.CV_16U、cv2.CV_32F 等。
  • kernel:卷积核,一个二维数组或矩阵。卷积核的大小通常是奇数,如 3x3、5x5 等。卷积核中的每个元素都是一个权重,用于在卷积过程中与图像像素相乘。
  • dst:输出图像(可选)。
  • anchor:卷积核的锚点(可选)。
  • delta:一个可选的附加值,它将被加到卷积结果上。这可以用于调整结果的亮度或对比度。
  • borderType:边界填充。

进行边缘检测的方向取决于选取的卷积核kernel

kernelk1时,检测方向为垂直方向

 当kernelk2时,检测方向为水平方向

当然kernel的取值并非只有上面两种,该函数通过应用自定义的卷积核对图像进行滤波处理,可以实现各种线性滤波效果。卷积核可以看作是一种特殊的算子,但本质是函数。

注意:上面的k1,k2,正是Sobel算子(下面会讲)需要使用的卷积核,所以cv2.filter2D()函数选用上面的k1,k2作为参数kernel的取值,那么它与Sobel算子的作用效果是一样的。

那么卷积核是如何运作的呢,还跟之前一样要提前填充边缘吗?放心,不需要,计算很简单。

如下图,以垂直方向为例:

卷积核进行操作的是单信道图像,灰度图或二值图,两个极端0(黑),255(白),该卷积核进行操作目的是为进行边缘检测,所以将两个极端进行重新赋值,以便及那个边缘区分开来,下面介绍的Sobel算子,也是相同的操作,不在赘述。

 实线框部分是第一次卷积,左右两边(中间列除外)各自与对赢得系数相乘,然后进行相加

(196-247)+2*(199-241)+(35-190)= -290   结果<=0,归零,将中间一列重新赋值为零

卷积核滑动,虚线部分为第二次卷积,

(243-0)+2*(245-0)+(197-0)=930  结果>0,归255,将中间列重新赋值为255

 示例代码
import cv2
import numpy as np# 读取一张图
img = cv2.imread("./shudu.png")# 进行垂直梯度处理
kernel = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
img_filter = cv2.filter2D(img, -1, kernel)# 进行水平梯度处理
kernel1 = np.array([[-1, -2, -1],[0, 0, 0],[1, 2, 1]])
img_filter_level = cv2.filter2D(img, -1, kernel1)cv2.imshow('image', img)
cv2.imshow('img_filter', img_filter)
cv2.imshow('img_filter_level', img_filter_level)cv2.waitKey(0)
效果对比

 Sobel算子

上面的两个卷积核都叫做Sobel算子,只是方向不同,它先在垂直方向计算梯度:

 cv2.Sobel()函数

功能:用于计算图像梯度(gradient)的函数

参数:

  • src: 输入图像,它应该是灰度图像。
  • ddepth: 输出图像的所需深度(数据类型)。通常,你可以使用 -1 来表示与输入图像相同的深度,或者使用如 cv2.CV_64F 等来指定特定的深度。由于梯度计算可能产生负值,因此建议使用能够包含负数的数据类型。
  • dx: x 方向上的导数阶数。如果你想要计算 x 方向上的梯度,设置这个参数为 1;如果你不关心 x 方向上的梯度,设置这个参数为 0。
  • dy: y 方向上的导数阶数。如果你想要计算 y 方向上的梯度,设置这个参数为 1;如果你不关心 y 方向上的梯度,设置这个参数为 0。通常,你不会同时设置 dx 和 dy 都为 0。
  • ksize: Sobel 核的大小。它必须是 1、3、5、7 或 9 之一。这个参数决定了用于计算梯度的滤波器的大小。大小为 1 时表示使用最小的滤波器,但通常你会使用更大的滤波器来平滑梯度计算。
  • scale: 可选参数,表示计算梯度时的缩放因子。默认值为 1,表示不进行缩放。你可以通过调整这个参数来放大或缩小梯度的结果。
  • delta: 可选参数,表示在将结果存储到目标图像之前要添加到结果中的可选增量值。默认值为 0,表示不添加增量。
  • borderType: 像素外推方法,例如 cv2.BORDER_DEFAULT、cv2.BORDER_REFLECT 等。这个参数决定了在图像边界处如何处理像素外推。
示例代码
import cv2# 读取一张图
img = cv2.imread("./shudu.png")# 使用sobel算子
# 水平梯度
img_sobel = cv2.Sobel(img, -1, 0, 1, ksize=3)
# 垂直梯度
img_sobel_2 = cv2.Sobel(img, -1, 1, 0, ksize=3)cv2.imshow('image', img)
cv2.imshow('img_sobel', img_sobel)
cv2.imshow('img_sobel_2', img_sobel_2)cv2.waitKey(0)
 效果对比

其他算子

Laplacian算子

下面为推导过程,了解即可可直接跳过,我们只关心最后的卷积核

 在此基础上考虑斜对角情况,该算子的图像卷积模板如下:

 cv2.Laplacian()函数

功能:用于计算图像的拉普拉斯算子(Laplacian)

参数:

  • src: 输入图像,它应该是灰度图像。
  • ddepth: 输出图像的所需深度。这个参数决定了输出图像的深度(数据类型)。通常,你可以使用 -1 来表示与输入图像相同的深度,或者使用 cv2.CV_64F 等来指定特定的深度。由于拉普拉斯算子可能产生负值,因此通常建议使用能够包含负数的数据类型,如 cv2.CV_64F。
  • ksize: 算子的大小。它必须是 1、3、5 或 7 之一。这个参数决定了用于计算拉普拉斯算子的滤波器的大小。大小为 1 时表示使用 4 邻域拉普拉斯算子,其他大小则使用更大的滤波器。
  • scale: 可选参数,表示计算拉普拉斯算子时的缩放因子。默认值为 1,表示不进行缩放。你可以通过调整这个参数来放大或缩小拉普拉斯算子的结果。
  • delta: 可选参数,表示在将结果存储到目标图像之前要添加到结果中的可选增量值。默认值为 0,表示不添加增量。
  • borderType: 像素外推方法,例如 cv2.BORDER_DEFAULT、cv2.BORDER_REFLECT 等。这个参数决定了在图像边界处如何处理像素外推。当 ksize 大于 1 时,这个参数才有意义。
示例代码
import cv2# 读取一张图
img = cv2.imread("./shudu.png")# 使用拉普拉斯算子
img_lap = cv2.Laplacian(img, -1, ksize=3)cv2.imshow('image', img)
cv2.imshow('img_lap', img_lap)cv2.waitKey(0)
效果对比

小结 

Sobel算子是二阶边缘检测的典型代表

Laplacian算子是二阶边缘检测的典型代表

不过 一 / 二 阶边缘检测各有优缺点,大家可自行了解。

图像边缘检测

边缘检测要用到Canny算法,Canny边缘检测方法 常被誉为 边缘检测 的最优方法。

首先,Canny算法 处理的是 图像的二值化结果,接收到二值化图像后,需要按照如下步骤进行:

  1. 高斯滤波。
  2. 计算图像的梯度和方向。
  3. 非极大值抑制。
  4. 双阈值筛选。

下面我来介绍一下这四步

1. 高斯滤波

在前面的文章里历经详细介绍了高斯滤波,遗忘的同学,链接如下:

10篇--图像噪点消除-CSDN博客

之前提到过,低通滤波器是模糊,高通滤波器是锐化

而边缘检测本身属于锐化操作,对噪点比较敏感,需要进行平滑处理。所以用到的高斯滤波高通滤波器。这里使用的是一个5*5的高斯核对图像进行消除噪声:

2. 计算图像的梯度与方向 

2.1 计算梯度

这里使用了Sobel算子(核值固定的卷积核)来计算图像的梯度值,如下所示:

这些是高数中二阶偏导数相关的概念,就不做赘述了。不理解也没关系,重点不在这,接着往下看

2.2 计算方向 

这个角度值其实就是当前边缘的梯度的方向,与边缘的方向刚好垂直。

通过这个公式我们就可以计算出图片中所有的像素点的梯度值与梯度方向,然后根据梯度方向获取边缘的方向,获得θ。得到θ的值之后,就可以对边缘方向进行分类,一般将其归为四个方向:

水平方向、垂直方向、45°方向、135°方向:

  • 当θ值为-22.5°~22.5°,或-157.5°~157.5°,则认为边缘为水平边缘;
  • 当法线方向为22.5°~67.5°,或-112.5°~-157.5°,则认为边缘为45°边缘;
  • 当法线方向为67.5°~112.5°,或-67.5°~-112.5°,则认为边缘为垂直边缘;
  • 当法线方向为112.5°~157.5°,或-22.5°~-67.5°,则认为边缘为135°边缘;

 3. 非极大值抑制

通过上面的操作,已经初步筛选出了边缘,把他们连起来不久OK了,齐活?

NO,NO,NO!本系列第10篇提到过,锐化都容易损坏边缘信息,使边缘模糊,导致经过第二步后得到的边缘像素点非常多,因此我们需要对其进行一些过滤操作。其中非极大值抑制就是一个很好的方法。

在边缘检测中,非极大值抑制的主要目的是细化边缘。具体来说,它通过对梯度图像中的像素值进行比较和筛选,只保留梯度方向上局部最大的像素值,而将其他非最大的像素值抑制为零。这样,边缘就变得更加细化和清晰,减少了冗余的边缘信息。假设当前像素点为(x,y),其梯度方向是0°,梯度值为G(x,y),那么我们就需要比较G(x,y)与两个相邻像素的梯度值:G(x-1,y)和G(x+1,y)。如果G(x,y)是三个值里面最大的,就保留该像素值,否则将其抑制为零。

并且如果梯度方向不是0°、45°、90°、135°这种特定角度,那么就要用到插值算法来计算当前像素点在其方向上进行插值的结果了,然后进行比较并判断是否保留该像素点。这里使用的是单线性插值,通过A1和A2两个像素点获得dTmp1与dTmp2处的插值,然后与中心点C进行比较。

4. 双阈值筛选

经过非极大值抑制之后,我们还需要设置阈值来进行筛选。

  • 当阈值设的太低,就会出现假边缘
  • 而阈值设的太高,一些较弱的边缘就会被丢掉

因此使用了双阈值来进行筛选,推荐高低阈值的比例为2 : 1到3 : 1之间,其原理如下图所示: 

  • 当某一像素位置的幅值超过最高阈值时,该像素必是边缘像素;
  • 幅值处于最高像素与最低像素之间时,如果它能连接到一个高于阈值的边缘时,则被认为是边缘像素,否则就不会被认为是边缘;
  • 当幅值低于最低像素时,该像素必不是边缘像素。

也就是说,上图中的A和C是边缘,B不是边缘。因为C虽然不超过最高阈值,但其与A相连,所以C就是边缘。

至此,Canny边缘检测就完成了。

 cv2.Canny()函数

功能:用于边缘检测的函数

参数:

  • ‌image‌: 输入图像,它应该是一个灰度图像(单通道)。
  • ‌threshold1‌: 第一个阈值,用于边缘检测的滞后过程。这个值较低,用于确定边缘的初始点。
  • ‌threshold2‌: 第二个阈值,用于边缘检测的滞后过程。这个值较高,用于确定边缘的最终点。如果某个像素点的梯度值高于这个阈值,它被认为是边缘;如果低于这个值但高于threshold1,并且与高于threshold2的像素点相连,它也被认为是边缘。
  • ‌edges‌: 输出图像,与输入图像大小相同,但通常是二值图像(即只包含边缘和非边缘的像素)。
  • ‌apertureSize‌(可选,默认为3): Sobel算子的大小,它决定了梯度计算的邻域大小。它必须是1、3、5或7之一。
  • ‌L2gradient‌(可选,默认为False): 一个布尔值,指示是否使用更精确的L2范数进行梯度计算。如果为True,则使用L2范数(即欧几里得距离);如果为False,则使用L1范数(即曼哈顿距离)。L2范数通常更精确,但计算成本也更高。

示例代码

import cv2img = cv2.imread("kabuto.jpg")# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化
_, img_binary = cv2.threshold(img_gray, 127, 255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 进行高斯滤波
img_blur = cv2.GaussianBlur(img_binary, (3,3), 3)# 边缘检测
img_canny = cv2.Canny(img_blur, 10, 70)cv2.imshow('img', img)
cv2.imshow('img_canny', img_canny)
cv2.waitKey(0)

效果对比 

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

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

相关文章

6.2 MapReduce工作原理

MapReduce工作原理涉及将大数据集分割成小块并行处理。Map任务读取数据块并输出中间键值对&#xff0c;而Reduce任务则处理这些排序后的数据以生成最终结果。MapTask工作包括读取数据、应用Map函数、收集输出、内存溢出时写入磁盘以及可选的Combiner局部聚合。ReduceTask工作则…

ARM Cortex-A7 MPCore 架构

1、Cortex-A7 MPCore 简介 Cortex-A7 MPcore 处理器支持 1~4 核&#xff0c;通常是和 Cortex-A15 组成 big.LITTLE 架构的&#xff0c; Cortex-A15 作为大核负责高性能运算&#xff0c;比如玩游戏啥的&#xff0c; Cortex-A7 负责普通应用&#xff0c;因为 CortexA7 省电。 Co…

天天 AI-241215:今日热点-OpenAI发布ChatGPT Projects,万能工具箱上线!

2AGI.NET | 探索 AI 无限潜力&#xff0c;2AGI 为您带来最前沿资讯。 2024年&#xff0c;人工智能&#xff08;AI&#xff09;领域的发展日新月异&#xff0c;不断刷新我们对技术边界的认知。从预训练模型的终结宣言到AI应用开发平台的受欢迎程度&#xff0c;再到AI在数据管理和…

CEF127 编译指南 MacOS 篇 - 安装 Git 和 Python(三)

1. 引言 在前面的文章中&#xff0c;我们已经完成了 Xcode 及基础开发工具的安装和配置。接下来&#xff0c;我们需要安装两个同样重要的工具&#xff1a;Git 和 Python。这两个工具在 CEF 的编译过程中扮演着关键角色。Git 负责管理和获取源代码&#xff0c;而 Python 则用于…

手机静态ip地址怎么获取?方法全解析‌

在数字化时代&#xff0c;智能手机已成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;手机都扮演着至关重要的角色。而在某些特定情境下&#xff0c;我们可能需要为手机设置一个静态IP地址。本文将详细介绍如何为手机获取静态IP地址。 一、通过手机设…

FlightAD 解读

一 文章相关信息 出处&#xff1a;ICPADS CCF C 会议&#xff08;代码未开源&#xff09;&#xff0c;COUTA 研究团队的另一研究 二 Methodology 1. 整体架构&#xff1a; 2. Multi-Scale Sampling&#xff08;多尺度&#xff09; 实际上&#xff0c;就是对每个单通道作 “多…

【考前预习】4.计算机网络—网络层

往期推荐 【考前预习】3.计算机网络—数据链路层-CSDN博客 【考前预习】2.计算机网络—物理层-CSDN博客 【考前预习】1.计算机网络概述-CSDN博客 目录 1.网络层概述 2.网络层提供的两种服务 3.分类编址的IPV4 4.无分类编址的IPV4—CIDR 5.IPV4地址应用规划 5.1使用定长子…

github配置pages并配置自定义域名

有cloudflare的话实现的效果更好&#xff0c;可以使用自己的域名&#xff0c;实现白嫖一个网站服务器 1、配置git&#xff08;可选步骤&#xff09; git init git config --global user.name "sijia" git config --global user.email "devopsgame.vip"g…

vue3 结合 echarts 为tooltip绑定点击事件实现树形结构下动态添加子节点的效果

先看效果 具体实现代码如下&#xff1a; <template> <div ref"ecs" id"ecs" style"width: 800px;height:800px; background-color:white;"></div> </template><script setup> import {onMounted, ref} from &quo…

【JavaWeb后端学习笔记】Redis常用命令以及Java客户端操作Redis

redis 1、redis安装与启动服务2、redis数据类型3、redis常用命令3.1 字符串String3.2 哈希Hash3.3 列表List3.4 集合Set&#xff08;无序&#xff09;3.5 有序集合zset3.6 通用命令 4、使用Java操作Redis4.1 环境准备4.2 Java操作字符串String4.3 Java操作哈希Hash4.4 Java操作…

js:我要在template中v-for循环遍历这个centrerTopdata,我希望自循环前面三个就可以了怎么写

问&#xff1a; 我按在要在template中v-for循环遍历这个centrerTopdata&#xff0c;我希望自循环前面三个就可以了怎么写&#xff1f; 回答&#xff1a; 问&#xff1a; <div v-for"(item, index) in centrerTopdata.slice(0, 3)" :key"index"> d…

前端成长之路:CSS(1)

在前端三件套中&#xff0c;CSS的主要是用于美化网页、进行页面布局的。 HTML的局限性 HTML是一个非常单纯的语言&#xff0c;它只关心内容的语义&#xff1a; 比如看见h1标签&#xff0c;就表明这是一个大标题、看见p标签&#xff0c;就表明这是一个段落、看见img标签&#…

微服务SpringCloud链路追踪之Micrometer+Zipkin

视频教程&#xff1a; https://www.bilibili.com/video/BV12LBFYjEvR 效果演示 当我们发送一个请求给 Gateway 的时候&#xff0c;由 Micrometer trace 进行链路追踪和数据收集&#xff0c;由 Zipkin 进行数据展示。可以清楚的看到微服务的调用过程&#xff0c;以及每个微服务…

0001.基于springmvc简易酒店管理系统后台

一.系统架构 springmvcjsplayuimysql 二.功能特性 简单易学习&#xff0c;虽然版本比较老但是部署方便&#xff0c;tomcat环境即可启用&#xff1b;代码简洁&#xff0c;前后端代码提供可统一学习&#xff1b;祝愿您能成尽快为一位合格的程序员&#xff0c;愿世界没有BUG; …

Elasticsearch Kibana (windows版本) 安装和启动

目录 1.安装 2.启动 elasticsearch 3.启动 kibana 1.安装 elasticsearch下载&#xff0c;官网链接&#xff1a; Download Elasticsearch | Elastichttps://www.elastic.co/downloads/elasticsearch kibana下载&#xff0c;官网链接&#xff1a; Download Kibana Free | G…

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 CNN-BiGRU,即卷积神经网络(CNN)与双…

在C#中编程绘制和移动线段

这个示例允许用户绘制和移动线段。它允许您根据鼠标下方的内容执行三种不同的操作。 当鼠标位于某个线段上时&#xff0c;光标会变成手的形状。然后您可以单击并拖动来移动该线段。当鼠标位于线段的终点上时&#xff0c;光标会变成箭头。然后您可以单击并拖动以移动终点。当鼠…

Jenkins容器使用宿主机Docker(五)

DevOps之安装和配置 Jenkins (一) DevOps 之 CI/CD入门操作 (二) Sonar Qube介绍和安装&#xff08;三&#xff09; Harbor镜像仓库介绍&安装 &#xff08;四&#xff09; Jenkins容器使用宿主机Docker&#xff08;五&#xff09; Jenkins流水线初体验&#xff08;六&#…

网站被间歇性扫描,IP不断更换,我的应对方法

文章目录 背景应对方式封ip自动不响应策略代码为啥不上其他防护软件呢&#xff1f; 背景 我负责的一个网站&#xff0c;不出名&#xff0c;平时也没多少流量。1天有几百个就不错了。没想到&#xff0c;这么不起眼的网站也有被人盯上的时候。 一天&#xff0c;后台使用人员告诉…

WHY - 为什么选择 Rsbuild

目录 一、介绍二、工具对比三、性能 https://rsbuild.dev/zh/guide/start/index 一、介绍 Rsbuild 是由 Rspack 驱动的高性能构建工具&#xff0c;它默认包含了一套精心设计的构建配置&#xff0c;提供开箱即用的开发体验&#xff0c;并能够充分发挥出 Rspack 的性能优势。 二…