<图像处理> 可分离滤波器核

可分离滤波器核

空间滤波器核是一个二维矩阵,若它能够表示为两个一维矩阵的乘积时,则表示该滤波器核是可分离的。
例如,一个3x3的核,
w = [ 1 1 1 1 1 1 1 1 1 ] w=\begin{bmatrix} 1 & 1 & 1\\ 1 & 1& 1\\ 1 & 1& 1\\ \end{bmatrix} w= 111111111
它可以表示为两个一维矩阵的乘积
c = [ 1 1 1 ] c=\begin{bmatrix} 1 & 1 & 1\\ \end{bmatrix} c=[111]
r = [ 1 1 1 ] r=\begin{bmatrix} 1 & 1 & 1\\ \end{bmatrix} r=[111]

w = c r T w=cr^T w=crT

性质

可分离核的重要性是卷积结合律性质导致的计算优势,如果有一个核 w w w,它可以分为两个简单的核并满足 w = w 1 ∗ w 2 w=w_1*w_2 w=w1w2,则其满足
w ∗ f = ( w 1 ∗ w 2 ) ∗ f = ( w 2 ∗ w 1 ) ∗ f = w 2 ∗ ( w 1 ∗ f ) = ( w 1 ∗ f ) ∗ w 2 w*f=(w_1*w_2)*f=(w_2*w_1)*f=w_2*(w_1*f)=(w_1*f)*w_2 wf=(w1w2)f=(w2w1)f=w2(w1f)=(w1f)w2
对于一个大小为 M ∗ N M*N MN的图像与大小为 m ∗ n m*n mn的核实现卷积,需要 M N m n MNmn MNmn次加法和乘法,如果核是可分离的,则需要 M N ( m + n ) MN(m+n) MN(m+n)次,可加速计算。

必要条件

要确定一个核是否可分离,只需要确定其秩是否为1。 因此确定某个矩阵的秩为1后,能够计算其两个分离的一维核,步骤如下

  1. 在核中找到任意一个非零元素,并将其表示为E;
  2. 找他该元素所在的行和列,表示为 c , r c,r c,r
  3. 可以得出两个一维核为 c c c r / E r/E r/E

示例

以x方向上的Sobel滤波核进行性能测试,比较 M N m n MNmn MNmn以及 M N ( m + n ) MN(m+n) MN(m+n)的处理时间,并与自带opencv 的cv::filter2D与cv::Sobel算子进行比较滤波效果。

int main()
{//x方向的Sobel核Mat kernel = (Mat_<char>(3, 3) <<-1, 0, 1,-2, 0, 2,-1, 0, 1);const char* imageName = ".....";Mat src = imread(imageName, IMREAD_GRAYSCALE);Mat srcBorder;copyMakeBorder(src, srcBorder, kernel.cols / 2, kernel.cols / 2, kernel.rows / 2, kernel.rows / 2, cv::BORDER_CONSTANT);//填充边缘clock_t start, end;//1.MNmnMat dst(src.rows, src.cols, CV_8UC1);start = clock();int sum = 0;for (int i = 1;i <= dst.rows;i++){for (int j = 1;j <= dst.cols;j++){sum = 0;for (int m = 0;m < kernel.rows;m++){for (int n = 0;n < kernel.cols;n++){sum += (int)(srcBorder.ptr<uchar>(i + m - 1)[j + n - 1] * kernel.ptr<char>(m)[n]);}}dst.ptr<uchar>(i - 1)[j - 1] = (uchar)(sum < 0 ? 0 : (sum > 255 ? 255 : sum));}}end = clock();std::cout << "1.常规计算(MNmn):" << end - start << std::endl;//2.可分离滤波计算Mat _src2(src.rows + kernel.rows / 2 + 1, src.cols + kernel.cols / 2 + 1, CV_32SC1);_src2 = Scalar::all(0);Mat dst2(src.rows, src.cols, CV_8UC1);start = clock();//分离卷积核char kernelRow[3] = { 1,0,-1 };char kernelCol[3] = { -1,-2,-1 };for (int i = 1;i <= dst2.rows;i++){for (int j = 1;j <= dst2.cols;j++){sum = 0;for (int m = 0;m < 3;m++){sum += (int)(srcBorder.ptr<uchar>(i)[j + m - 1] * kernelRow[m]);}_src2.ptr<short>(i)[j] = sum;}}for (int i = 1;i <= dst2.rows;i++){for (int j = 1;j <= dst2.cols;j++){sum = 0;for (int n = 0;n < 3;n++){sum += (int)(_src2.ptr<short>(i + n - 1)[j] * kernelCol[n]);}dst2.ptr<uchar>(i - 1)[j - 1] = (uchar)(sum < 0 ? 0 : (sum > 255 ? 255 : sum)); //防止溢出。opencv中使用内联函数saturate_cast<T>()}}end = clock();std::cout << "2.可分离核计算MN(m+n):" << end - start << std::endl;//3.opencv-filter2D计算Mat dst3;start = clock();cv::filter2D(src, dst3, -1, kernel, Point(-1, -1), 0.0, BORDER_CONSTANT);end = clock();std::cout << "3.opencv-filter2D计算:" << end - start << std::endl;//4.opencv-sobel计算Mat dst4;start = clock();cv::Sobel(src, dst4, -1, 1, 0, 3, 1.0, 0.0, BORDER_CONSTANT);end = clock();std::cout << "4.opencv-sobel计算:" << end - start << std::endl;// 效果比较Mat findzero1 = dst2 != dst4; //方法一和方法二比较效果Mat findzero2 = dst2 != dst4; //方法二和方法三比较效果Mat findzero3 = dst2 != dst4; //方法二和方法四比较效果vector<cv::Point> veczero1;vector<cv::Point> veczero2;vector<cv::Point> veczero3;cv::findNonZero(findzero1, veczero1);cv::findNonZero(findzero2, veczero2);cv::findNonZero(findzero3, veczero3);int num1 = veczero1.size();int num2 = veczero2.size();int num3 = veczero3.size();std::cout << "方法一和方法二逐像素比较,像素不同个数:" << num1 << std::endl;std::cout << "方法二和方法三逐像素比较,像素不同个数:" << num2 << std::endl;std::cout << "方法二和方法四逐像素比较,像素不同个数:" << num3 << std::endl;system("pause");return 0;
}

计算结果显示,可分离核计算比常规计算快一倍左右,与OpenCV的sobel算子处理时间相当。

在这里插入图片描述

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

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

相关文章

木棒切割问题

题目很简单&#xff0c;就是我们在写二分的时候&#xff0c;会遇到这样的情况&#xff1a; mid left (right-left)/2; if (nums k)return mid;if (nums>k)left mid;if (nums<k)right mid-1; 若我们debug会发现其可能会一致卡在left mid&#xff0c;例如&#xff08…

框架分析(9)-Hibernate

框架分析&#xff08;9&#xff09;-Hibernate 专栏介绍Hibernate特性对象关系映射&#xff08;ORM&#xff09;数据库连接和事务管理查询语言&#xff08;HQL&#xff09;缓存机制透明的持久化操作对象的延迟加载事务管理 优缺点优点简化数据库操作跨数据库平台高度可定制性缓…

C#通过ModbusTcp协议读写西门子PLC中的浮点数

一、Modbus TCP通信概述 MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品&#xff0c;显而易见&#xff0c;它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC&#xff0c;I/…

PCL RANSAC分割提取多个空间圆

目录 一、概述二、代码实现三、结果展示1、原始数据2、提取结果四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 使用PCL分割提取多个空间圆,其核心原理仍然是RANSAC拟合空间圆,这里只是做简单修改…

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比 目录 时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现EEMD-SSA-LSTM、E…

uniapp制作——交友盲盒

在小程序端可以有很多好玩的小玩意&#xff0c;目前网上比较有趣的就是有一个交友盲盒&#xff0c;能抽出和找出对象的一个有趣的小程序&#xff0c;所以今天给大家带来用uniapp搭建的交友盲盒&#xff0c;大家再根据自己的情况去搭建自己的后端和数据库来完成自己的一个小项目…

FPGA实现电机转速PID控制

通过纯RTL实现电机转速PID控制&#xff0c;包括电机编码器值读取&#xff0c;电机速度、正反转控制&#xff0c;PID算法&#xff0c;卡尔曼滤波&#xff0c;最终实现对电机速度进行控制&#xff0c;使其能够渐近设定的编码器目标值。 一、设计思路 前面通过SOPC之NIOS Ⅱ实现电…

算法笔记:点四叉树

点四叉树是一种用于主要是针对空间点存储与索引的树形数据结构在点四叉树中&#xff0c;空间被分割成四个矩形&#xff0c;四个不同的多边形对应于SW、NW、SE、NE四个象限 1 基本操作 1.1 初始化 创建一个根节点&#xff0c;该节点代表整个二维空间区域 1.2 插入点 当一个新…

【GPT,Flask】用Python Flask结合OpenAI的GPT API构建一个可自主搭建的内容生成应用网站

【背景】 自己构建模型并进行训练需要很高的知识,技能和资源门槛。如今,通过OpenAI提供的API,则可以快速通过GPT能力构建可以提供内容生成服务的在线网站。这套框架可以提供给用户,用户可以利用该框架在自己的环境(比如自己的公司内)构建内容生成服务。你也可以自己上线…

mac建议装双系统吗,详细分析苹果电脑双系统的利弊

mac建议装双系统吗&#xff0c;Mac电脑上安装双系统有哪些利弊呢&#xff0c;一起来看看吧&#xff01; 苹果Mac电脑安装双系统利&#xff1a; 1、用来办公更加方便&#xff1a;苹果系统功能也是很强大的&#xff0c;但是用来办公非常不方便&#xff0c;是由于一些常用的exe软…

QTableView合并单元格

QtableView的功能 QTableView是Qt框架提供的用于显示表格数据的类。它是基于MVC&#xff08;模型-视图-控制器&#xff09;设计模式的一部分&#xff0c;用于将数据模型和界面视图分离。 以下是一些QTableView的主要特点和功能&#xff1a; 1. 显示表格数据&#xff1a; QTa…

奥本海默

&#xff08;1&#xff09;命 电影一开头&#xff0c;奥本海默不擅长做实验。但你看宿命凑巧不凑巧&#xff0c;奥本海默成了曼哈顿计划的工程负责人&#xff0c;偏偏要他一次性爆炸成功。 电影一开头&#xff0c;奥本海默因为不擅长做实验被导师指出引起其他同学哄堂大笑&…

无涯教程-JavaScript - DATE函数

描述 DATE函数返回特定日期的序列号。 语法 DATE (year, month, day)争论 Argument描述Required/Optionalyear year参数的值可以包含1-4位数字。 Excel会根据计算机使用的日期系统解释年份参数。 默认情况下,Microsoft Excel for Windows使用1900日期系统。 请参阅下面的注…

分类算法系列②:KNN算法

目录 KNN算法 1、简介 2、原理分析 数学原理 相关公式及其过程分析 距离度量 k值选择 分类决策规则 3、API 4、⭐案例实践 4.1、分析 4.2、代码 5、K-近邻算法总结 &#x1f343;作者介绍&#xff1a;准大三网络工程专业在读&#xff0c;努力学习Java&#xff0c;涉…

QT连接数据库

目录 数据库 数据库基本概念 常用的数据库 SQLite3基础 SQLite特性&#xff1a; QT连接数据库 1.1 QT将数据库分为三个层次 1.2 实现数据库操作的相关方法 sql语句&#xff08;常用&#xff09; 1&#xff09;创建表格 2&#xff09;删除表格 3&#xff09;插入记录 …

期权交易策略及案例的基本策略有哪些?

目前我国上市交易的期权品种日益丰富&#xff0c;期权的基础的交易方法是建立相应头寸再反向平仓&#xff0c;赚取权利金差价&#xff0c;也可以持有期权到期行权。除了基础的交易方法之外&#xff0c;期权还有一些组合策略&#xff0c;下文介绍期权交易策略及案例的基本策略有…

修改部署后的SSM项目配置文件

修改部署后的SSM项目配置文件 环境配置&#xff1a;window10&#xff0c;JDK8&#xff0c;项目采用SSM编写&#xff0c;部署在tomcat上&#xff0c;maven打包是打成war包 1、找到配置文件 打开tomcat目录 D:\Programming\apache-tomcat-8.5.58\webapps\MyPRO\WEB-INF\class…

docker安装redis实操记录

1.Docker拉取镜像 docker pull redis2.Docker挂载配置文件 创建挂载文件夹 mkdir -p /home/redis/data下载默认配置文件 redis.conf 3.启动redis 容器 docker run --restartalways --log-opt max-size100m --log-opt max-file2 -p 6379:6379 --name redis -v /home/redi…

react16之前diff算法的理解和总结

此篇文章所讨论的是 React 16 以前的 Diff 算法。而 React 16 启用了全新的架构 Fiber&#xff0c;相应的 Diff 算法也有所改变&#xff0c;本片不详细讨论Fiber。 fiber架构是为了支持react进行可中断渲染&#xff0c;降低卡顿&#xff0c;提升流畅度。 react16之前的版本&…

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及Apache Hive示例(6)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…