OpenCV:入门(五)

图像梯度

图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也 较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情 况下,图像梯度计算的是图像的边缘信息。

严格来讲,图像梯度计算需要求导数,但是图像梯度一般通过计算像素值的差来得到梯度 的近似值(近似导数值)。

 例如,图 9-1 中的左右两幅图分别描述了图像的水平边界和垂直边界。

针对左图,通过垂直方向的线条 A 和线条 B 的位置,可以计算图像水平方向的边界:

  •  对于线条 A 和线条 B,其右侧像素值与左侧像素值的差值不为零,因此是边界。
  •  对于其余列,其右侧像素值与左侧像素值的差值均为零,因此不是边界。 针对右图,通过水平方向的线条 A 和线条 B 的位置,可以计算图像垂直方向的边界:
  •  对于线条 A 和线条 B,其下侧像素值与上侧像素值的差值不为零,因此是边界。
  •  对于其余行,其下侧像素值与上侧像素值的差值均为零,因此不是边界。

但是实际图像处理中肯定不会像上图一样好处理,所以我们也有相对复杂的算子:Sobel算子,Scharr算子,拉普拉斯算子等。 

一,Sobel算子

(1)原理

Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用 局部差分寻找边缘,计算所得的是一个梯度的近似值。

需要说明的是,滤波器通常是指由一幅图像根据像素点(x, y)临近的区域计算得到另外一幅 新图像的算法。因此,滤波器是由邻域及预定义的操作构成的。滤波器规定了滤波时所采用的 形状以及该区域内像素值的组成规律。滤波器也被称为“掩模”、“核”、“模板”、“窗口”、“算 子”等。一般信号领域将其称为“滤波器”,数学领域将其称为“核”。本章中出现的滤波器多 数为“线性滤波器”,也就是说,滤波的目标像素点的值等于原始像素值及其周围像素值的加权和。这种基于线性核的滤波,就是我们所熟悉的卷积。在本章中,为了方便说明,直接使用 “算子”来表示各种算子所使用的滤波器。例如,本章中所说的“Sobel算子”通常是指 Sobel 滤波器。  

1.计算水平方向偏导数的近似值

得到结果为:P5x = (P3-P1) + 2·(P6-P4) + (P9-P7)  

很明显,这些点都是x轴方向的点,而且离p5点越近权重越大。

那么垂直方向偏导数的近似值应该也很好理解了,我们只需要转置一下sobel算子就可以了。

2. 计算垂直方向偏导数的近似值 

P5y = (P7-P1) + 2·(P8-P2) + (P9-P3)

差不多,对吧? 

 (2)函数解析

dst = cv2.Sobel( src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]] )

  • dst 代表目标图像。
  • src 代表原始图像。
  • ddepth 代表输出图像的深度。其具体对应关系如表 9-1 所示。

  • dx 代表 x 方向上的求导阶数。
  • dy 代表 y 方向上的求导阶数。
  • ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。
  • scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
  • delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
  • borderType 代表边界样式。该参数的具体类型及值如表 9-2 所示。  

 1.参数ddepth

在函数 cv2.Sobel()的语法中规定,可以将函数 cv2.Sobel()内 ddepth 参数的值设置为-1,让 处理结果与原始图像保持一致。但是,如果直接将参数 ddepth 的值设置为-1,在计算时得到的 结果可能是错误的。 在实际操作中,计算梯度值可能会出现负数。如果处理的图像是 8 位图类型,则在 ddepth 的参数值为-1 时,意味着指定运算结果也是 8 位图类型,那么所有负数会自动截断为 0,发生信息丢失。为了避免信息丢失,在计算时要先使用更高的数据类型 cv2.CV_64F,再通过取绝 对值将其映射为 cv2.CV_8U(8 位图)类型。所以,通常要将函数 cv2.Sobel()内参数 ddepth 的 值设置为“cv2.CV_64F”

简而言之,就是计算梯度时会出现负数,这就会导致一些问题(部分图像无法显示),这部分会在代码示例部分更加详细讨论,我们可以通过参数调整让8位图先升高位数防止截断,当然也可以用abs取绝对值来解决,我们放在后续讨论。

2.方向

在函数 cv2.Sobel()中,参数 dx 表示 x 轴方向的求导阶数,参数 dy 表示 y 轴方向的求导阶 数。参数 dx 和 dy 通常的值为 0 或者 1,最大值为 2。如果是 0,表示在该方向上没有求导。当 然,参数 dx 和参数 dy 的值不能同时为 0。

参数 dx 和参数 dy 可以有多种形式的组合,主要包含:

  • 计算 x 方向边缘(梯度):dx=1, dy=0。
  • 计算 y 方向边缘(梯度):dx=0, dy=1。
  • 参数 dx 与参数 dy 的值均为 1:dx=1, dy=1(这个效果不是很好,一般分别计算x,y方向梯度再计算)
  • 计算 x 方向和 y 方向的边缘叠加:通过组合方式实现。

(3)代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

circle = cv2.imread("circle.jpg")
kernel = np.ones((5, 5), np.uint8)
circle = cv2.erode(circle,kernel=kernel,iterations=2)
sobel_x = cv2.Sobel(circle,cv2.CV_64F,1,0,ksize=5)
sobel_x_abs = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.Sobel(circle,cv2.CV_64F,0,1,ksize=5)
sobel_y_abs = cv2.convertScaleAbs(sobel_y)
sobel_x_y = cv2.Sobel(circle,cv2.CV_64F,1,1,ksize=5)
sobel_x_y_mix = cv2.addWeighted(sobel_x_abs,0.5,sobel_y_abs,0.5,0)
plt.subplot(231), plt.imshow(sobel_x), plt.title("Sobel_X")
plt.subplot(232), plt.imshow(sobel_y), plt.title("Sobel_Y")
plt.subplot(233), plt.imshow(sobel_x_y), plt.title("Sobel_X_Y")#不建议直接计算
plt.subplot(234), plt.imshow(sobel_x_abs), plt.title("Sobel_X_ABS")
plt.subplot(235), plt.imshow(sobel_y_abs), plt.title("Sobel_Y_ABS")
plt.subplot(236), plt.imshow(sobel_x_y_mix), plt.title("Sobel_X_Y_MIX")
plt.show()

和上文提及一般,对比sobel_x和sobel_x_abs图像,我们发现sobel_x图像出现缺失,这是因为计算出负值后出现的截断,导致值为0,对应就是黑点,无法显示出来,这里我们采用取绝对值解决了这个问题。

同样地,我们对比sobel_x_y和sobel_x_y_mix两幅图,前者是通过直接在函数中设置参数dx,dy=1产生的效果,后者是分别计算后叠加在一起的图像,采用的是addweighted方法。

二,Scharr算子

(1)原理

Scharr算子的原理和Sobel算子很相似,就是换了一个滤波器(核),不过Scharr算子精度更高一些。

如图:

(2)函数解析

dst = cv2.Scharr( src, ddepth, dx, dy[, scale[, delta[, borderType]]] ) 

  • dst 代表输出图像。
  • src 代表原始图像。
  • ddepth 代表输出图像深度。该值与函数 cv2.Sobel()中的参数 ddepth 的含义相同,具体可 以参考表 9-1。
  • dx 代表 x 方向上的导数阶数。
  • dy 代表 y 方向上的导数阶数。
  • scale 代表计算导数值时的缩放因子,该项是可选项,默认值是 1,表示没有缩放。
  • delta 代表加到目标图像上的亮度值,该项是可选项,默认值为 0。
  • borderType 代表边界样式。具体可以参考表 9-2。  

(3)代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':     
        circle = cv2.imread("circle.jpg")
        kernel = np.ones((5, 5), np.uint8)
        circle = cv2.erode(circle,kernel=kernel,iterations=2)
        scharr_x = cv2.Scharr(circle,cv2.CV_64F,1,0)
        scharr_x_abs = cv2.convertScaleAbs(scharr_x)
        scharr_y = cv2.Scharr(circle,cv2.CV_64F,0,1)
        scharr_y_abs = cv2.convertScaleAbs(scharr_y)
        scharr_x_y_mix = cv2.addWeighted(scharr_x_abs,0.5,scharr_y_abs,0.5,0)
        plt.subplot(231), plt.imshow(scharr_x), plt.title("Scharr_X")
        plt.subplot(232), plt.imshow(scharr_y), plt.title("Scharr_Y")
        plt.subplot(234), plt.imshow(scharr_x_abs), plt.title("Scharr_X_ABS")
        plt.subplot(235), plt.imshow(scharr_y_abs), plt.title("Scharr_Y_ABS")
        plt.subplot(236), plt.imshow(scharr_x_y_mix), plt.title("Scharr_X_Y_MIX")
        plt.show()
        cv2.waitKey(0)

对比Sobel图像:

我们发现Scharr算子显然更加精细一些,效果也要好一些,当然有兴趣的话可以使用其他图片进行更好的观察。 

三, Laplacian算子

(1)原理

Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向 的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。例如,一个 3×3 大小的 Laplacian 算子如图 9-24 所示。

Laplacian 算子类似二阶 Sobel 导数,需要计算两个方向的梯度值。例如,在图 9-25 中:

  • 左图是 Laplacian 算子。
  • 右图是一个简单图像,其中有 9 个像素点。  

计算像素点 P5 的近似导数值,如下:

P5lap = (P2 + P4 + P6 + P8) - 4·P5  

(2)函数解析

dst = cv2.Laplacian( src, ddepth[, ksize[, scale[, delta[, borderType]]]] ) 

  • dst 代表目标图像。
  • src 代表原始图像。
  • ddepth 代表目标图像的深度。
  • ksize 代表用于计算二阶导数的核尺寸大小。该值必须是正的奇数。
  • scale 代表计算 Laplacian 值的缩放比例因子,该参数是可选的。默认情况下,该值为 1, 表示不进行缩放。
  • delta 代表加到目标图像上的可选值,默认为 0。
  • borderType 代表边界样式。 该函数分别对 x、y 方向进行二次求导,具体为: 

上式是当 ksize 的值大于 1 时的情况。当 ksize 的值为 1 时,Laplacian 算子计算时采用的 3×3 的核如下:

通过从图像内减去它的 Laplacian 图像,可以增强图像的对比度,此时其算子如图 9-27 所 示。  

(3)代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
        circle = cv2.imread("circle.jpg")
        laplacian = cv2.Laplacian(circle,cv2.CV_64F)
        laplacian_abs = cv2.convertScaleAbs(laplacian)
        plt.subplot(121),plt.imshow(laplacian),plt.title("Laplacian")
        plt.subplot(122),plt.imshow(laplacian_abs),plt.title("Laplacian_abs")
        plt.show()
        cv2.waitKey(0)

四,算子总结

Sobel 算子、Scharr 算子、Laplacian 算子都可以用作边缘检测,它们的核如图 9-29 所示。

Sobel 算子和 Scharr 算子计算的都是一阶近似导数的值。通常情况下,可以将它们表示为:

Sobel 算子= |左-右| / |下-上|

Scharr 算子= |左-右| / |下-上|

式中“|左-右|”表示左侧像素值减右侧像素值的结果的绝对值,“|下-上|”表示下方像素值减上 方像素值的结果的绝对值。

Laplacian 算子计算的是二阶近似导数值,可以将它表示为:

Laplacian 算子= |左-右| + |左-右| + |下-上| + |下-上|

通过公式可以发现,Sobel 算子和 Scharr 算子各计算了一次“|左-右|”和“|下-上|”的值, 而 Laplacian 算子分别计算了两次“|左-右|”和“|下-上|”的值。  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux基础(四):Linux系统文件类型与文件权限

各位看官,好久不见,在正式介绍Linux的基本命令之前,我们首先了解一下,关于文件的知识。 目录 一、文件类型 二、文件权限 2.1 文件访问者的分类 2.2 文件权限 2.2.1 文件的基本权限 2.2.2 文件权限值的表示方法 三、修改文…

Kafka之【生产消息】

消息(Record) 在kafka中传递的数据我们称之为消息(message)或记录(record),所以Kafka发送数据前,需要将待发送的数据封装为指定的数据模型: 相关属性必须在构建数据模型时指定,其中…

近临算法(个人总结版)

背景 近邻算法(Nearest Neighbor Algorithm)是一种基本但非常有效的分类和回归方法。最早由Fix和Hodges在1951年提出,经过几十年的发展和改进,已成为数据挖掘、模式识别和机器学习领域的重要工具。近邻算法基于相似性原则&#x…

get和post的区别,二者是幂等的吗?

一、什么是幂等 所谓幂等性通俗的将就是一次请求和多次请求同一个资源产生相同的副作用。 维基百科定义:幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中一个幂等操作的特点是其任意多次执…

git分支常用命令

最近在用git提交代码的时候&#xff0c;发现有些命令不是很会&#xff0c;先记录几个常用分支命令&#xff0c;后续再补充&#xff0c;在执行git push命令提交代码的时候遇到报错&#xff0c;一并记录下。 1.git常用命令 新建分支&#xff1a; git branch <分支名称> 比…

day16|二叉树的属性

相关题目 ● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数 二叉树的深度与高度 如图&#xff0c; 二叉树的深度表示&#xff1a;任意一个叶子节点到根节点的距离&#xff0c;是从上往下计数的&#xff0c;因此使用前序遍历…

Transformer详解(2)-位置编码

位置编码公式 偶数位置用sin,奇数位置用cos. d_model 表示token的维度&#xff1b;pos表示token在序列中的位置&#xff1b;i表示每个token编码的第i个位置&#xff0c;属于[0,d_model)。 torch实现 import math import torch from torch import nn from torch.autograd im…

blender 烘焙渲染图片,已经导出fbx,导出贴图。插件生成图片

1.新建一个模型。选择资产浏览器的材质&#xff0c;并拖动到模型身上&#xff0c;如下图。资产浏览器的材质可以网上找。 2.打开着色器面板。正下方着色器窗口中&#xff0c;点击空白取消选择&#xff0c;然后右击-添加-着色器-原理化BSDF&#xff0c;右击-添加-纹理-图像纹理。…

初阶数据结构之双向链表详解

目录 一&#xff1a;双向链表的概念 1.什么是双向链表&#xff1f; 2.双向链表的优点 3.双向链表的结构 二&#xff1a;双向链表的实现 1.定义链表结点 2.初始化双向链表 3.添加结点 4.尾插 5.头插 6.打印双向链表 7.查找链表结点 8.在指定结点后插入新结点 9.删…

力扣:92. 反转链表 II(Java)

目录 题目描述&#xff1a;示例 1&#xff1a;示例 2&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的…

TypeScript-搭建编译环境

搭建编译环境 TypeScript 编写的代码是无法直接在js引擎( 浏览器 / Nodejs )中运行的&#xff0c;最终还需要经过编译成js代码才可以正常运行 搭建手动编译环境 1️⃣ 全局安装 typescript 包&#xff08;编译引擎&#xff09; -> 注册 tsc 命令 npm i -g typescript 2…

如何解决vcruntime140.dll丢失问题,详细介绍5种靠谱的解决方法

vcruntime140.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;它为使用Visual C编译器开发的应用程序提供必要的运行时环境。该DLL文件包含了大量应用程序运行时需要调用的库函数&#xff0c;这些函数是实现C标准库、异常处理机制、RTTI&#xff08;运行…

2461. 长度为 K 子数组中的最大和(c++)

给你一个整数数组 nums 和一个整数 k 。请你从 nums 中满足下述条件的全部子数组中找出最大子数组和&#xff1a; 子数组的长度是 k&#xff0c;且子数组中的所有元素 各不相同 。 返回满足题面要求的最大子数组和。如果不存在子数组满足这些条件&#xff0c;返回 0 。 子数…

2024电工杯数学建模A题Matlab代码+结果表数据教学

2024电工杯A题保姆级分析完整思路代码数据教学 A题题目&#xff1a;园区微电网风光储协调优化配置 以下仅展示部分&#xff0c;完整版看文末的文章 %A_1_1_A % 清除工作区 clear;clc;close all;warning off; %读取参数%正常读取 % P_LOADxlsread(附件1&#xff1a;各园区典…

如何创建 Gala Games 账户:解决 Cloudflare 验证指南 2024

Gala Games 站在数字娱乐新时代的前沿&#xff0c;将区块链技术与游戏相结合&#xff0c;重新定义了所有权和奖励。本文将引导您创建 Gala Games 账户并使用 CapSolver 解决 Cloudflare 验证难题&#xff0c;确保您顺利进入这一创新的生态系统。 什么是 Gala Games&#xff1f…

debian nginx upsync consul 实现动态负载

1. consul 安装 wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_r…

微信小程序使用input标签遇到的问题

场景1&#xff1a;多个input标签切换无法聚焦问题 解决方案1&#xff1a; 在网上搜的用官方给的always-embed属性&#xff0c;但是也明确标注了只有ios可用 解决方案2&#xff1a; 使用focus属性&#xff1a;每次点击input标签都重新设置 wxml: <input adjust-position…

【YOLOv5/v7改进系列】替换激活函数为SiLU、ReLU、LeakyReLU、FReLU、PReLU、Hardswish、Mish、ELU等

一、导言 激活函数在目标检测中的作用至关重要&#xff0c;它们主要服务于以下几个关键目的&#xff1a; 引入非线性&#xff1a;神经网络的基本构建块&#xff08;如卷积层、全连接层等&#xff09;本质上是线性变换&#xff0c;而激活函数通过引入非线性&#xff0c;使得网络…

画图工具之PlantUML插件使用

文章目录 1 PlantUML插件1.1 引言1.2 什么是PlantUML1.3 PlantUML插件1.3.1 IntelliJ IDEA中插件1.3.2 VS Code中插件1.3.3 使用例子 1.4 PlantUML时序图语法1.4.1 声明参与者1.4.2 消息传递1.4.2.1 同步消息1.4.2.2 异步消息1.4.2.3 返回消息1.4.2.4 自调用 1.4.3 生命线&…

在Windows10中重命名文件和文件夹的6种方法,有你熟悉和不熟悉的

序言 你可以通过多种方式在Windows 10上重命名文件。如果每次你想更改文件名时仍右键单击并选择“重命名”,那么我们有一些技巧可以加快更改速度。 使用文件资源管理器重命名文件和文件夹 Windows 10的文件资源管理器是一个功能强大的工具。你知道吗,有四种不同的方法可以…