《opencv实用探索·十一》opencv之Prewitt算子边缘检测,Roberts算子边缘检测和Sobel算子边缘检测

1、前言

边缘检测:
图像边缘检测是指在图像中寻找灰度、颜色、纹理等变化比较剧烈的区域,它们可能代表着物体之间的边界或物体内部的特征。边缘检测是图像处理中的一项基本操作,可以用于人脸识别、物体识别、图像分割等多个领域。

边缘检测实质上是计算当前点和周围点灰度的差别。

图像边缘检测流程主要分为以下几个步骤:
(1)读取待处理图像;
(1)图像滤波,例如使用高斯滤波器,平滑图像,去除噪声;
(2)计算图像中每个像素点的梯度强度和方向;
(3)应用非极大值抑制(Non-Maximum Suooression),保留梯度方向上的局部最大值,抑制非边缘点,消除边缘检测带来的杂散响应;
(4)应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘,即将梯度幅值映射到两个阈值,根据梯度值高于高阈值或在高低阈值之间的情况,将像素标记为强边缘、弱边缘或非边缘。
(5)边缘连接,通过连接相邻的强边缘像素和与之相连的弱边缘像素,形成最终的边缘图像;
(6)显示结果。

在介绍各种边缘检测算子之前先简单阐述下怎么寻找边缘。

下面左图是一张黑白相间的图,右图是左图的每个像素的灰度值
在这里插入图片描述
我们设定一个卷积核如下(关于卷积的介绍请看之前的文章):
在这里插入图片描述
原图在通过卷积核进行卷积计算后得到的图像如下:
可以看到原图在卷积运算后黑色向白色突变的边缘被很好的保留了下来,因此可以通过这个卷积核找到图像中垂直的边缘。
在这里插入图片描述
同理,如果我们用下面的卷积核也可以找到图像中水平的边缘。
在这里插入图片描述
卷积运算后:
在这里插入图片描述

2、Prewitt算子边缘检测
如果我们把上面两个卷积核组合起来再对图像进行卷积便可以同时找到图像中水平和垂直的边缘,这种卷积核就是prewitt算子。
在这里插入图片描述

标准的 Prewitt 边缘检测算子由以下两个卷积核组成。
在这里插入图片描述
下面是用prewitt算子进行边缘检测的案例:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>using namespace cv;int main() {// 读取图像Mat image = imread("your_image.jpg", IMREAD_GRAYSCALE);// 定义Prewitt算子Mat prewitt_x = (Mat_<float>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);Mat prewitt_y = (Mat_<float>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1);// 对图像应用Prewitt算子Mat edges_x, edges_y;filter2D(image, edges_x, CV_64F, prewitt_x);filter2D(image, edges_y, CV_64F, prewitt_y);// 计算梯度幅值和方向Mat gradient_magnitude, gradient_direction;magnitude(edges_x, edges_y, gradient_magnitude);phase(edges_x, edges_y, gradient_direction, true);// 归一化梯度幅值cv::normalize(gradient_magnitude, gradient_magnitude, 0, 1, cv::NORM_MINMAX);// 显示结果imshow("Original Image", image);  //原灰度图imshow("Gradient Magnitude", gradient_magnitude);  //prewitt算子边缘检测图waitKey(0);destroyAllWindows();return 0;
}

代码解读:
(1)在代码中我们先分别定义一个水平方向和垂直方向的prewitt算子edges_x和edges_y
(2)filter2D是对图像进行卷积操作,即获取prewitt算子与原图像卷积后的图像edges_x和edges_y
(3)magnitude 函数的主要用途是计算两个输入数组的逐元素平方和的平方根。在图像处理中,常常用于计算图像中每个像素点的梯度幅值。相位(Phase)在图像处理中通常指的是梯度的方向(边缘方向)。在梯度计算中,梯度向量的方向表示图像在该点上灰度变化最快的方向。在梯度计算中,通常使用 magnitude 函数计算梯度的幅值,使用 phase 函数计算梯度的方向。这两个信息一起构成了梯度向量,提供了有关图像局部变化的重要信息。
(4)最后归一化梯度幅值图像,因为64位图像显示范围为0-1。

最后效果如下(左边是原灰度图,右边是边缘检测出的图像):
在这里插入图片描述

3、Roberts算子
常用来处理具有陡峭的低噪声图像,当图像边缘接近于正45度或负45度时,该算法处理效果更理想。其缺点是对边缘的定位不太准确,提取的边缘线条较粗。

下图左边为水平方向Roberts算子,也称正对角算子。右边为垂直方向Roberts算子,也称斜对角算子。
在这里插入图片描述
下面是Roberts算子的使用案例:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>int main() {// 生成一个简单的图像cv::Mat image = cv::Mat::zeros(100, 100, CV_8U);cv::rectangle(image, cv::Rect(20, 20, 60, 60), cv::Scalar(255), cv::FILLED);// 定义Sobel算子cv::Mat sobel_x = (cv::Mat_<float>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);cv::Mat sobel_y = (cv::Mat_<float>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);// 应用Sobel算子cv::Mat edges_x, edges_y;cv::filter2D(image, edges_x, CV_64F, sobel_x);cv::filter2D(image, edges_y, CV_64F, sobel_y);// 计算梯度幅值和方向cv::Mat gradient_magnitude, gradient_direction;cv::magnitude(edges_x, edges_y, gradient_magnitude);cv::phase(edges_x, edges_y, gradient_direction, true);  // true 表示计算角度的弧度值// 归一化梯度方向到[0, 1]范围cv::normalize(gradient_direction, gradient_direction, 0, 1, cv::NORM_MINMAX);// 显示结果cv::imshow("Original Image", image);cv::imshow("Gradient Magnitude", gradient_magnitude);cv::imshow("Gradient Direction", gradient_direction);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

最后效果如下(左边是原灰度图,右边是边缘检测出的图像):
在这里插入图片描述

4、Sobel算子边缘检测
Sobel算子在Prewitt算子的基础上增加了权重的概念,认为相邻点的距离远近对当前像素点的影响是不同的,距离越近的像素点对应当前像素的影响越大,从而实现图像锐化并突出边缘轮廓。但Sobel算子并不是基于图像灰度进行处理的,因为Sobel算子并没有严格地模拟人的视觉生理特性,因此图像轮廓的提取有时并不能让人满意。当对精度要求不是很高时,Sobel算子是一种较为常用的边缘检测方法。

它的水平和垂直方向的卷积核如下:
在这里插入图片描述
接口说明:

void cv::Sobel(InputArray src,OutputArray dst,int ddepth,int dx,int dy,int ksize = 3,double scale = 1,double delta = 0,int borderType = cv::BORDER_DEFAULT
);

src: 输入图像。可以是单通道(灰度图)或多通道图像。
dst: 输出图像,梯度的计算结果将存储在这里。
ddepth: 输出图像的深度,通常使用 CV_64F 或 CV_32F 表示。
dx: x方向上的导数阶数,设为1表示在水平方向上进行操作。
dy: y方向上的导数阶数,设为1表示在垂直方向上进行操作。
ksize: Sobel核的大小。默认为 3,表示一个 3x3 的核。通常使用奇数值。
scale: 可选的比例因子,用于调整梯度的幅值,也表示对比度。
delta: 可选的偏移值,用于调整输出图像的亮度。
borderType: 边界处理类型,可以使用 cv::BORDER_DEFAULT 或其他合适的边界处理标志。

Sobel算子边缘检测案例:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>int main() {// 读取图像cv::Mat image = cv::imread("your_image.jpg", cv::IMREAD_GRAYSCALE);if (image.empty()) {std::cerr << "Error: Could not read the image." << std::endl;return -1;}// 应用Sobel算子cv::Mat edges_x, edges_y;cv::Sobel(image, edges_x, CV_64F, 1, 0, 3); // 1表示在水平方向上进行操作cv::Sobel(image, edges_y, CV_64F, 0, 1, 3); // 1表示在垂直方向上进行操作// 计算梯度幅值cv::Mat gradient_magnitude;cv::magnitude(edges_x, edges_y, gradient_magnitude);// 归一化梯度方向到[0, 1]范围cv::normalize(gradient_magnitude, gradient_magnitude, 0, 1, cv::NORM_MINMAX);// 显示结果cv::imshow("Original Image", image);cv::imshow("Sobel Edges X", edges_x);cv::imshow("Sobel Edges Y", edges_y);cv::imshow("Gradient Magnitude", gradient_magnitude);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

C/C++,图算法——布伦特循环检测算法(Brent‘s cycle detection algorithm)的源程序

1 文本格式 // CPP program to implement Brents cycle // detection algorithm to detect cycle in // a linked list. #include <stdio.h> #include <stdlib.h> /* Link list node */ struct Node { int data; struct Node* next; }; /* Th…

导出Excel需要增加一个错误列, 通用类SheetWriteHandler

背景 如题 在业务中经常遇到这样的需求, 上传excel后对数据进行校验, 如果校验不通过, 需要提供excel下载, 并在后面一列提供错误原因. 常见的做法是在导出的方法中, 加一个字段然后在list中, 然后sheet写到返回流中. 但是如果需要统一样式就比较麻烦, 且每次都需要写这么一…

在Vivado 仿真器中搭建UVM验证环境(不需要联合modelsim)

Vivado 集成设计环境支持将通用验证方法学 (UVM) 应用于 Vivado 仿真器。Vivado 提供了预编译的 UVM V1.2 库。 &#xff08;1&#xff09;在 Vivado 2019.2 中创建新 RTL 工程。 &#xff08;2&#xff09;单击“添加目录 (Add Directories)”以将“src”和“verif”目录添加…

4.1 Docker 容器化和镜像管理

Docker 容器化和镜像管理 容器化的概念 介绍容器化的含义&#xff0c;将应用程序及其依赖项封装为一个独立的运行环境&#xff0c;实现隔离和可移植性。强调容器化的优势&#xff0c;如轻量、快速启动、一致性和可扩展性。 Docker 简介 解释 Docker 是一种主流的容器化技术&am…

CCF计算机软件能力认证202309-2坐标变换(其二)(C语言)

ccf-csp计算机软件能力认证202309-2坐标变换&#xff08;其二&#xff09;(C语言版) 题目内容&#xff1a; 问题描述 输入格式 输出格式 样例输入 10 5 2 0.59 2 4.956 1 0.997 1 1.364 1 1.242 1 0.82 2 2.824 1 0.716 2 0.178 2 4.094 1 6 -953188 -946637 1 9 96953…

计算机网络之网络传输,三次握手和四次挥手

网络传输通过高低电压 流 基本类型数组 低电压转高电压&#xff0c;通过网卡 传输模式&#xff1a; 全双工&#xff1a;互相传输且能同时传输 半双工&#xff1a;互相传输但是不能同时传输 单工&#xff1a;单向传输&#xff0c;&#xff08;键盘&#xff0c;显示器&#…

kubernetes详解——从入门到入土(更新中~)

k8s简介 编排工具&#xff1a;系统层面ansible、saltstackdocker容器docker compose docker swarm docker machinedocker compose&#xff1a;实现单机容器编排docker swarm&#xff1a;实现多主机整合成为一个docker machine&#xff1a;初始化新主机mesos marathonmesos …

微信小程序查看接口信息(抓包)

本文仅供交流学习使用 主要参考: https://cloud.tencent.com/developer/article/1833591 https://www.cnblogs.com/x1you/p/12033839.html 由于参考文章在baidu权重不高(google才查到的), 所以自己重新记录一篇, 方便他人, 也防止参考文章丢失. 背景 需要知道微信小程序的接口…

8、Broker进一步了解

1、Broker消息分发服务以及构建ConsumeQueue和IndexFile与消息清除 前面分析如何进行刷盘&#xff0c;本章分析Broker的消息分发以及构建ConsumerQueue和IndexFile&#xff0c;两者构建是为了能够提高效率&#xff0c;减少消息查找时间以及减少网络带宽与存储空间。 ConsumeQ…

线程与线程池

单核cpu与多核cpu&#xff1a; 线程的并发和并行问题 多线程的创建&#xff1a; 多线程程序创建&#xff1a;java.lang.Thread(实现了Runnable接口) // 1定义一个类实现Runnable接口&#xff0c;重写run方法&#xff08;run方法中设置线程任务&#xff09;…

W5500实现以太网通信

实现原理 嵌入式程序跑在STM32微控制器&#xff0c;通过片上SPI控制器与W5500进行通信&#xff0c;配置所需网络参数并与远端服务器建立链接&#xff08;TCP客户端&#xff09;之后发送接收数据&#xff1b;又或者是建立服务器&#xff08;TCP服务器&#xff09;等待建立链接之…

mac电池最大充电限制工具 AlDente Pro中文 for Mac

Pro 版特有功能 热保护&#xff1a;在电池温度较高时为电池充电会导致电池老化更快。启用热保护后&#xff0c;当电池温度过高时&#xff0c;充电将自动停止。 航行模式&#xff1a;通常情况下&#xff0c;即使激活了最大电池充电&#xff0c;您的 MacBooks 电池也会始终稍微充…

记一次校园双选会面试问到的题

创建对象方式 线程安全和那些锁 stringbuff build区别 反射原理 集合底层 存储引擎myisam和innodb B树&#xff0c;慢查询&#xff0c;sql优化 数据库三大范式 左右内连接分别的效果 谈谈boot和spring&#xff0c;常用注解 ioc aop redis里的锁&#xff0c;缓存击穿穿透血崩&am…

7.上传project到服务器及拉取服务器project到本地、更新代码冲突解决

1.上传project到SVN服务器 1.在eclipse中&#xff0c;从show view里调出SVN资源库视图 2.在SVN资源库窗口的空白位置右键选择新建资源库位置 3.填好服务器的地址 4.资源库导入成功,SVN资源库视图下出现导入的资源库 5.新建project 6.写好project的初始版本 7.右键project --&…

Java面试题(每天10题)-------连载(43)

目录 Spring篇 1、请举例说明Qualifier注解 2、构造方法注入和设值注入有什么区别&#xff1f; 3、Spring框架中有哪些不同类型的事件&#xff1f; 4、FileSystemResource和ClassPathResource有什么区别&#xff1f; 5、Spring框架中都用到了哪些设计模式&#xff1f; 6…

激光雷达生成的图像检测关键点用来辅助里程计的方案

文章&#xff1a;LiDAR-Generated Images Derived Keypoints Assisted Point Cloud Registration Scheme in Odometry Estimation 作者&#xff1a;Haizhou Zhang , Xianjia Yu, Sier Ha , Tomi Westerlund 编辑&#xff1a;点云PCL 欢迎各位加入知识星球&#xff0c;获取PDF…

数据结构与算法编程题41

线性表中各结点的检索概率不等时&#xff0c;可用如下策略提高顺序检索的效率&#xff1a; 若找到指定的结点&#xff0c;则将该结点和其前驱结点&#xff08;若存在&#xff09;交换&#xff0c;使得经常被检索 的结点尽量位于表的前端。试设计在顺序结构的线性表上实现上述策…

使用Vue写一个日期选择器

在 Vue 中实现日期选择器的方法有很多&#xff0c;下面提供一个简单的实现方法。 首先&#xff0c;在需要使用日期选择器的组件中引用 Vue 和 date-fns 库&#xff0c;date-fns 库是一个轻量级的 JavaScript 时间日期工具库&#xff0c;可以方便地处理日期的格式化和计算。 &…

DCGAN生成网络模型

DCGAN&#xff08;Deep Convolutional Generative Adversarial Network&#xff09;是一种生成对抗网络&#xff08;GAN&#xff09;的变体&#xff0c;专门设计用于生成图像。它结合了卷积神经网络&#xff08;CNN&#xff09;和生成对抗网络的概念&#xff0c;旨在生成具有高…

Java的接口和抽象类

在Java编程中&#xff0c;接口和抽象类是两个重要的概念。它们都用于实现面向对象编程中的抽象和封装&#xff0c;但在使用方式和功能上有所不同。本文将详细介绍Java中接口和抽象类的概念、用法和示例代码&#xff0c;帮助读者更好地理解和应用它们。 一、接口&#xff08;In…