【OpenCV学习】第16课:图像边缘提取 - Sobel算子详细剖析(图像梯度)

news2024/11/21 1:32:27

仅自学做笔记用,后续有错误会更改

理论

  1. 卷积的应用 - 图像边缘提取:
  • 边缘是什么:是像素值发生跃迁的地方, 是图像的显著特征之一, 再图像特征提取丶对象检测丶模式识别等方面都有重要作用
  • 如何捕捉/提取边缘:对图像求它的一阶导数,delta = f(x) - f(x-1), delta值越大, 说明像素在x方向变化越大,边缘信号越强
    在这里插入图片描述
  • 如果你已经忘记了数学求导什么的概念, 也不用担心, 直接用Sobel算子进行卷积操作就可以了!
  1. Sobel算子
  • 是离散微分算子(discrete differentiation operator), 用来计算图像灰度的近似梯度
  • Sobel算子功能集合了 高斯模糊和微分求导
  • 又被称为一阶微分算子,求导算子,在水平和垂直两个方向求导,得到图像X方向与Y方向的梯度图像
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/62e69e82e0e649c9b236b0bae34379f6.png
  • 求取导数的近似值(上图的实际应用公式), kernel=3时不是很准确,容易受到干扰, Opencv使用改进版本Scharr函数, 算子如下:
    在这里插入图片描述
  1. Sobel算子边缘提取步骤:
  • 先把原图像进行高斯模糊操作
  • 再把图像转灰度图
  • 再通过Sobel算子求X梯度和Y梯度
  • 线性混合X与Y的梯度图(可以不使用addweighted接口,而是手动去写, 去掉权重α与1-α的影响,可以使最后的图更明显),得到最终的振幅图像

相关API

cv::Sobel(
InputArray src, //输入图像
OutputArray dst, //输出图像
int depth, //输出图像深度,填-1表示跟输入图像一致, 由于灰度图是CV_8U,所以Sobel一般使用CV_16S/CV_32F, 需要比输入的灰度图的深度更高, 结果才会更明显
int dx, //x方向,几阶导数, sobel取1
int dy, //y方向,几阶导数, sobel取1
int ksize, //算子(kernel)大小,Sobel算子必须是奇数, 常见的是3
double scale = 1, //输出图像放大或缩小倍数
double delta = 0, //偏移量
int borderType = BORDER_DEFAULT
)

cv::Scharr(
InputArray src, //输入图像
OutputArray dst, //输出图像
int depth, //输出图像深度,填-1表示跟输入图像一致, 由于灰度图是CV_8U,所以Sobel一般使用CV_16S/CV_32F, 需要比输入的灰度图的深度更高, 结果才会更明显
int dx, //x方向,几阶导数, sobel取1
int dy, //y方向,几阶导数, sobel取1
int ksize, //算子(kernel)大小,Sobel算子必须是奇数, 常见的是3
double scale = 1, //输出图像放大或缩小倍数
double delta = 0, //偏移量
int borderType = BORDER_DEFAULT
)

代码示例

using namespace cv;
int main(int argc, char** argv){
	Mat src,dst;
	int ksize = 0;
	src = imread(...);
	if( !src.data ){
		return -1;
	}
	//原图
	char INPUT_WIN[] = "input image";
	namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_WIN, src);
	//先高斯模糊, 再转灰度图
	Mat gray_src;
	GaussianBlur(src, dst, Size(3,3), 0, 0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);
	imshow("gray image",gray_src);
	
	/*//cv::Scharr操作,  可以看最后的效果截图, 它的提取效果非常强烈, 根本不怕干扰
	Mat xgrad, ygrad;
	Scharr(gray_src, xgrad, CV_16S, 1, 0);
	Scharr(gray_src, ygrad, CV_16S, 0, 1);*/
	//cv::Sobel操作(输出深度为CV_16S,且有convertScaleAbs转换)
	Mat xgrad, ygrad;
	Scharr(gray_src, xgrad, CV_16S, 1, 0);
	Scharr(gray_src, ygrad, CV_16S, 0, 1);
	Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);	//这里为什么用CV_16S, 因为灰度图是CV_8U,我们设置输出图像的深度比灰度图更大, 就可以容纳更大的特征值, 提取效果也就更明显, 你也可以填-1等同于输入图像的深度,但是反正不能小于输入图像的深度。
	Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
	convertScaleAbs(xgrad, xgrad);			    //这个函数的作用是保证Sobel算子操作过后有些负数结果值不被置为0, 也就是不被截取掉
	convertScaleAbs(ygrad, ygrad);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);
	
	/*//cv::Sobel操作(输出深度填-1,且没有convertScaleAbs转换)
	Mat xgrad, ygrad;
	Sobel(gray_src, xgrad, -1, 1, 0, 3);
	Sobel(gray_src, ygrad, -1, 0, 1, 3);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);*/


	//最终线性混合图:手动写线性混合,去掉权重影响, 可以看最后的效果截图,更明显
	Mat xygrad = Mat(xgrad.size(), xgrad.type());
	int width = xgrad.cols;
	int height = ygrad.rows;
	for(int row = 0; row < weight; row++){
		for(int col = 0;col < width;col++){
			int xg = xgrad.at<uchar>(row, col);
			int yg = ygrad.at<uchar>(row, col);										//因为灰度图是CV_8U,所以用uchar
			int xy = xg + yg;																	//直接相加, 没有权重影响, 更亮更明显
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);	//saturate_cast这个东西的作用是保证最终值不超过0~255
		}
	}
	imshow("Final Result", xygrad);
	
	/*//最终线性混合图:直接调用addWeighted接口
	Mat xygrad;
	addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
	imshow("Final Result", xygrad);*/

	waitKey(0);
	return 0;
}

效果截图:
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换) x梯度图y梯度图
在这里插入图片描述
使用cv::Sobel(两个方向的输出深度都填-1且没有convertScaleAbs转换) x梯度图y梯度图
在这里插入图片描述
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 直接调用addWeighted接口) 最终线性混合图
在这里插入图片描述
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 手动写线性混合) 最终线性混合图
在这里插入图片描述
使用cv::Scharr(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 且手动写线性混合) 最终线性混合图
在这里插入图片描述

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

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

相关文章

关于LuaGC算法的演化概述

2年不用&#xff0c;就忘了&#xff0c;在这记录下。 5.0版本的双色标记清除算法 此算法中&#xff0c;每个对象会有两种标记态&#xff1a;白色和黑色&#xff1b;新创建的对象都是白色 过程&#xff1a; 1.初始化阶段&#xff1a;将root链表中的所有对象放入待检链表中&am…

0204隐函数及由参数方程所确定的函数的导数相关变化率-导数与微分

1 隐函数 定义&#xff1a;设有两个非空数集A,BA,BA,B.对于∀x∈A\forall x\in A∀x∈A&#xff0c;由二元方程F(x,y)0F(x,y)0F(x,y)0对应唯一的y∈By\in By∈B,称此对应关系是二元方程F(X,y)0F(X,y)0F(X,y)0确定的隐函数。 相应的由yf(x)yf(x)yf(x)确定的对应关系称为显函数。…

vue.js:作用域插槽的使用案例

作用域插槽的使用理解 父组件替换插槽的标签&#xff0c;但是内容是由子组件提供的。 案例需求 子组件中包含一组数据&#xff0c;比如&#xff1a;pLanguages&#xff1a;[‘Java’,‘c’,‘JavaScript’,‘python’,‘C语言’,‘Go’,‘C#’]现需要在多个页面进行操作&…

19.8 适配器概念、分类、范例与总结

一&#xff1a;适配器基本概念 把一个既有的东西进行适当的改造&#xff0c;比如增加点东西&#xff0c;或者减少点东西&#xff0c;就构成了一个适配器。 三种适配器&#xff1a;容器适配器、算法适配器、迭代适配器。 二&#xff1a;容器适配器 本章第三节学习过双端队列de…

个人有效:关于VMware虚拟机开机蓝屏问题的解决

文章目录前言禁用Hyper-V等服务Device 服务等启动相关是否需要VMware最新版本电脑虚拟化问题启用或关闭windows功能的设置关于VMware虚拟机的卸载参考前言 搜了海量文章&#xff0c;实操过大部分的方法&#xff0c;一顿折腾、最后莫名其妙的能跑了…。~~两天来急痛攻心&#xf…

Hot100-寻找重复数

1 前言 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一个重复的整数。 假设 nums 只有 一个重复的整数 &#xff0c;返回 这个重复的数 。 1.1 暴力解法 两次for循环&#xff1a…

spring——AOP面向切面编程—— 一般切面的 AOP 开发

一般切面的 AOP 开发 当我们在使用 Spring AOP 开发时&#xff0c;若没有对切面进行具体定义&#xff0c;Spring AOP 会通过 Advisor 为我们定义一个一般切面(不带切点的切面)&#xff0c;然后对目标对象(Target)中的所有方法连接点进行拦截&#xff0c;并织入增强代码。 工程依…

Pytest----测试脚本上传git代码仓库

【原文链接】Pytest----测试脚本上传git代码仓库 在企业实战中&#xff0c;自动化测试脚本也要放在代码管理平台的&#xff0c;可以选择第三方公共的git代码托管平台&#xff0c;比如github、gitee等&#xff0c;当然也可以在企业内部搭建gitlab作为代码托管平台&#xff0c;他…

蓝桥杯模拟赛习题练习(一)

题目来源&#xff1a;第十四届蓝桥杯模拟赛第一期 注&#xff1a;代码都是自己写的&#xff0c;不是参考答案&#xff01; 1. 二进制位数 问题描述&#xff1a; 十进制整数2在十进制中是1位数&#xff0c;在二进制中对应10 &#xff0c;是2位数。 十进制整数22在十进制中是2位…

Linux系统调用实现简析

1. 前言 限于作者能力水平&#xff0c;本文可能存在的谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. 背景 本篇基于 Linux 4.14 ARM 32 glibc-2.31 进行分析。 3. 系统调用的实现 3.1 系统调用的发起 3.1.1 起于用户空间 我们随意挑选一个…

python学习之:妙用魔法函数 __dict___来调用对象中的方法,或者 python文件中的方法

文章目录场景原始写法升级写法面向对象的写法总结场景 原始写法 假设现在有一个文件 tool.py我想在外部输入一个 字符串 就调用这个字符串对应的函数如果你不是用 __dict__ 这个好用的函数&#xff0c;那么你大概率会以下面的方式去写 main 函数&#xff0c;给很多 if但是如果…

网络安全观察报告 态势总览

执行摘要 从 1987 年 9 月 14 日&#xff0c;中国向世界发出第一封电子邮件 到如今&#xff0c;中国的互联网发展已过去整整 31 个年头。从消费互联、产业互联到万物互联&#xff0c;互联网正在加速改变我们的交流方式和交易方式&#xff0c;一次次 004.重塑了国家的经济形态和…

创建型 - 单例模式(Singleton pattern)

单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a;确保一个类有且只有一个实例&#xff0c;并提供一个全局访问点。 文章目录懒汉式-线程不安全饿汉式-线程安全懒汉式-线程安全双重校验锁-线程安全静态内部类实现枚举实现实现方式总结使用场景JDK懒汉式-线程不安…

论文(world、WPS)插入参考文献引用详细教程

一、参考资料 如何在WPS中添加论文参考文献 【Word】怎样给论文添加引用参考文献 word添加各种引用 二、相关介绍 1. 参考文献的标注 参考文献的标注分为全部引用、局部引用、间接引用。 1.1 全部引用&#xff08;直接引用&#xff09; 需要双引号&#xff0c;无论冒号…

[附源码]Python计算机毕业设计SSM基于的社区疫情管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

ADI Blackfin DSP处理器-BF533的开发详解24:触摸屏的实现和应用(含源代码)

硬件准备** ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 使用到硬件模块原理图 功能介绍 四线电阻式触摸屏&#xff0c;拿笔和指甲划拉的&#xff0c;不是现在的容性触摸屏。 ADSP-EDU-BF53x 板卡的 …

《Docker》阿里云服务器docker部署nginx并配置https踩坑记录(完整)

前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 来个关注吧&#xff0c;点个赞…

# Docker说明、安装(Windows10家庭版)

Docker说明、安装&#xff08;Windows10家庭版&#xff09; Docker是什么&#xff1f;它是干嘛的&#xff1f; 开始&#xff0c;我就知道别人说是用来加工tar包的。tar包&#xff1f;又是干什么用的&#xff1f; tar包&#xff0c;个人粗俗的理解就是一个环境&#xff0c;里面…

CVPR2021 | VQGAN+:Taming Transformers for High-Resolution Image Synthesis

原文标题&#xff1a;Taming Transformers for High-Resolution Image Synthesis 主页&#xff1a;Taming Transformers for High-Resolution Image Synthesis 代码&#xff1a;https://github.com/CompVis/taming-transformers transformer比CNN缺少了归纳偏置和局部性&…

音视频编解码经典问题汇总(1)

前言&#xff1a; 大家好&#xff0c;今天给大家分享的内容是关于平时在做音频编解码会遇到的一些问题&#xff0c;比如说&#xff1a;解码播放的时候&#xff0c;播不出来解码播放的时候&#xff0c;画面有条纹编码的时候&#xff0c;修改分辨率大小&#xff0c;没有反应这三个…