矩阵的掩膜操作

news2025/1/11 12:51:49

掩膜

矩阵上的掩码操作其实很简单,其思路是我们根据掩膜矩阵(即内核)重新计算图像中每个像素的值,此掩码保存的值将调整相邻像素(和当前像素)对新像素值的影响程度。从数学的角度来看,我们用我们指定的值做一个加权平均。

掩码相当于是在图片上增加了一个过滤膜,其实就是用选定的图像、图形或物体,对待处理的图像(局部或全部)进行遮挡来控制图像处理的区域或处理过程。

测试案例

让我们考虑图像对比度增强方法的问题。基本上,我们是对图像的每个像素应用以下公式:
第一个是公式法,第二个是掩膜
第一种表示法是使用公式,而第二种表示法是第一种表示法的压缩版本,使用掩码。通过将掩码矩阵的中心(由0 - 0索引标注的大写字母)放在要计算的像素上,并将像素值与重叠的矩阵值相乘,从而使用掩码。这是一样的,但是在大矩阵的情况下后一种符号更容易看。

代码

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
 
using namespace std;
using namespace cv;
 
static void help(char* progName)
{
 cout << endl
 << "This program shows how to filter images with mask: the write it yourself and the"
 << "filter2d way. " << endl
 << "Usage:" << endl
 << progName << " [image_path -- default lena.jpg] [G -- grayscale] " << endl << endl;
}
 
 
void Sharpen(const Mat& myImage,Mat& Result);
 
int main( int argc, char* argv[])
{
 help(argv[0]);
 const char* filename = argc >=2 ? argv[1] : "lena.jpg";
 
 Mat src, dst0, dst1;
 
 if (argc >= 3 && !strcmp("G", argv[2]))
 src = imread( samples::findFile( filename ), IMREAD_GRAYSCALE);
 else
 src = imread( samples::findFile( filename ), IMREAD_COLOR);
 
 if (src.empty())
 {
 cerr << "Can't open image [" << filename << "]" << endl;
 return EXIT_FAILURE;
 }
 
 namedWindow("Input", WINDOW_AUTOSIZE);
 namedWindow("Output", WINDOW_AUTOSIZE);
 
 imshow( "Input", src );
 double t = (double)getTickCount();
 
 Sharpen( src, dst0 );
 
 t = ((double)getTickCount() - t)/getTickFrequency();
 cout << "Hand written function time passed in seconds: " << t << endl;
 
 imshow( "Output", dst0 );
 waitKey();
 
 Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,
 -1, 5, -1,
 0, -1, 0);
 
 t = (double)getTickCount();
 
 filter2D( src, dst1, src.depth(), kernel );
 t = ((double)getTickCount() - t)/getTickFrequency();
 cout << "Built-in filter2D time passed in seconds: " << t << endl;
 
 imshow( "Output", dst1 );
 
 waitKey();
 return EXIT_SUCCESS;
}
void Sharpen(const Mat& myImage,Mat& Result)
{
 CV_Assert(myImage.depth() == CV_8U); // accept only uchar images
 
 const int nChannels = myImage.channels();
 Result.create(myImage.size(),myImage.type());
 
 for(int j = 1 ; j < myImage.rows-1; ++j)
 {
 const uchar* previous = myImage.ptr<uchar>(j - 1);
 const uchar* current = myImage.ptr<uchar>(j );
 const uchar* next = myImage.ptr<uchar>(j + 1);
 
 uchar* output = Result.ptr<uchar>(j);
 
 for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
 {
 output[i] = saturate_cast<uchar>(5*current[i]
 -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
 }
 }
 
 Result.row(0).setTo(Scalar(0));
 Result.row(Result.rows-1).setTo(Scalar(0));
 Result.col(0).setTo(Scalar(0));
 Result.col(Result.cols-1).setTo(Scalar(0));
}

基本方法

使用**filter2D()**函数或者使用基础的像素获取方法来实现掩膜的使用。代码如下:

void Sharpen(const Mat& myImage,Mat& Result)
{
 //判断所获取的图像格式是否是uchar
 CV_Assert(myImage.depth() == CV_8U); 
 
 const int nChannels = myImage.channels();
 Result.create(myImage.size(),myImage.type());
 
 for(int j = 1 ; j < myImage.rows-1; ++j)
 {
 	const uchar* previous = myImage.ptr<uchar>(j - 1);
 	const uchar* current = myImage.ptr<uchar>(j );
 	const uchar* next = myImage.ptr<uchar>(j + 1);
 
 	uchar* output = Result.ptr<uchar>(j);
 
 	for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
 	{	
 		//计算锐化后的像素值
 		output[i] = saturate_cast<uchar>(5*current[i]-current[i-nChannels] 
 					- current[i+nChannels] - previous[i] - next[i]);
 	}
 }
 
 // 将结果图像的边界设置为0,确保图像边界不会因为锐化收到影响,避免异常值
 Result.row(0).setTo(Scalar(0));
 Result.row(Result.rows-1).setTo(Scalar(0));
 Result.col(0).setTo(Scalar(0));
 Result.col(Result.cols-1).setTo(Scalar(0));
 // 图像处理过程中,边界像素容易由于缺少领域信息而变得不可靠,因此需要将边界设为0,保持图像一致性。
}

filter2D函数

在opencv的图像处理中。使用这样的过滤器是如此的频繁以至于存在一个应用掩膜的函数。首先,我们需要定义一个掩膜的对象。

 Mat kernel = (Mat_<char>(3,3) 
 << 0, -1, 0,
 -1, 5, -1,
 0, -1, 0);

然后再调用**filter2D()**函数,使用该卷积。

filter2D( src, dst1, src.depth(), kernel );

该函数甚至还有第五个可选参数来指定内核的中心,第六个参数用于在将过滤后的像素存储在K中之前向其添加可选值,第七个参数用于确定在未定义操作的区域(边界)中执行什么操作。

这个函数更短、更简洁,而且由于进行了一些优化,它通常比手工编码的方法更快。例如,在我的测试中,第二个只花了13毫秒,而第一个花了31毫秒。差别很大。

在这里插入图片描述

此外,笔者在学习过程中发现了一个更好的例子,链接如下:

一个更好的例子

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

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

相关文章

最流行的后端框架:如何选择适合自己的框架

最流行的后端框架&#xff1a;如何选择适合自己的框架 在当今快节奏的数字环境中&#xff0c;软件开发需要高效、可扩展且可靠的解决方案。最流行的后端框架&#xff0c;这就是后端框架的用武之地。这些软件框架提供了构建 Web 应用程序的骨干&#xff0c;处理了从数据库交互到…

关于FPGA对 DDR4 (MT40A256M16)的读写控制 I

关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 I 语言 &#xff1a;Verilg HDL EDA工具&#xff1a;ISE、Vivado 关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 I一、引言二、DDR4的特性&#xff08;MT40A256M16&#xff09;&#xff08;1…

vue-echarts与echarts图标拐点点击及其图表任意点击方法

要求&#xff1a;两个图表分别点击获取X轴时间点 一、vue-echarts&#xff1a;点击事件&#xff08;拐点点击 图表任意点击&#xff09; 效果图&#xff1a; 图一&#xff1a; 图二&#xff1a; <v-chart autoresize ref"oneMyChart" class"chart"…

破布叶(Microcos paniculata)单倍型染色体级别基因组-文献精读22

Haplotype-resolved chromosomal-level genome assembly of Buzhaye (Microcos paniculata) 破布叶、布渣叶&#xff08;Microcos paniculata&#xff09;单倍型解析染色体级别基因组组装 摘要 布渣叶&#xff08;Microcos paniculata&#xff09;是一种传统上用作民间药物和…

如何用PlayCanvas打造一个令人惊叹的3D模型在线展示

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 使用 PlayCanvas 渲染 3D 模型 应用场景介绍 PlayCanvas 是一款用于创建交互式 3D 内容的跨平台引擎。它广泛应用于游戏开发、建筑可视化和虚拟现实体验等领域。 代码基本功能介绍 本代码演示了如何使用 Pl…

一文解答 | 代码签名证书怎么选

在当代软件开发中&#xff0c;代码签名证书对于确保软件的完整性、安全性及其可信度至关重要。它通过数字签名验证代码的来源和未被篡改的状态&#xff0c;向最终用户确保软件的可靠性。选择合适的代码签名证书既有利于保护软件开发商的声誉&#xff0c;也有助于建立用户对软件…

鸿蒙轻内核调测-内存调测-内存泄漏检测

1、基础概念 内存泄漏检测机制作为内核的可选功能&#xff0c;用于辅助定位动态内存泄漏问题。开启该功能&#xff0c;动态内存机制会自动记录申请内存时的函数调用关系&#xff08;下文简称LR&#xff09;。如果出现泄漏&#xff0c;就可以利用这些记录的信息&#xff0c;找到…

高温车间降温通风方案

高温车间降温&#xff0c;解决厂房高温闷热必须做到以下两点才能实现&#xff0c;否则即使安装中央空调也没用&#xff1a;一、解决厂房内部热量 通过通排风负压风机、环保空调、工业大风扇等常用排热降温设备&#xff0c;降低室内温度&#xff1b;二、屏蔽外部太阳热源 …

日本2024年最受欢迎的转职行业是IT 通信

2024年有关机构针对超1000名人力资源专业人士进行了“推荐转职行业”的调查。结果显示&#xff0c;日本目前最受欢迎的转职行业是 1、“IT/通信行业”&#xff08;45.9%&#xff09;&#xff0c; 2、其次是“互联网/广告/游戏”&#xff08;31.9%&#xff09;&#xff0c; 3、“…

【log4】log4cplus:使用详解(一)

1、源码下载 源码下载地址:https://sourceforge.net/projects/log4cplus/files/log4cplus-stable/ 最新稳定版本为2.1.1(2023-11-17) github中有最新的源码:https://github.com/log4cplus/log4cplus 2、源码编译 1)解压后,进入源码目录中,执行配置命令: ./confi…

智能制造前沿:ARMxy工控机在机器人控制中

机器人控制系统正逐步成为现代制造业的核心引擎。在这个过程中&#xff0c;ARMxy工业计算机以其独特的优势&#xff0c;成为了驱动这一变革的关键力量。本文将以自动化装配线机器人为例&#xff0c;探讨ARMxy如何通过其低功耗、高性能特性&#xff0c;以及高度灵活性的设计&…

【代码随想录算法训练营第三十五天】 | 1005.K次取反后最大化的数组和 134.加油站 135.分发糖果

贪心章节的题目&#xff0c;做不出来看题解的时候&#xff0c;千万别有 “为什么这都没想到” 的感觉&#xff0c;想不出来是正常的&#xff0c;转变心态 “妙啊&#xff0c;又学到了新的思路” &#xff0c;这样能避免消极的心态对做题效率的影响。 134. 加油站 按卡哥的思路…

【调试笔记-20240613-Linux-在 git 多分支间合并】

调试笔记-系列文章目录 调试笔记-20240613-Linux-在 git 多分支间合并 文章目录 调试笔记-系列文章目录调试笔记-20240613-Linux-在 git 多分支间合并 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS调试环境调试目标 二、调试步骤在远端 git 服务器建立多个分支在本…

车间降温设备怎么选?有哪些注意事项

在选择车间降温设备时&#xff0c;需要考虑多个因素以确保选择的设备能够满足降温需求&#xff0c;同时考虑成本、效率和维护的便捷性。以下是一些关键的注意事项和选择标准&#xff1a; 一、选择标准 厂房大小与结构 厂房的面积、高度和结构将影响空气流通和降温效果。例如&…

揭秘软件测试秘籍:测试用例设计方法大揭秘

文章目录 引言一、等价类划分1.1 定义1.2 步骤1.3 等价类划分优点和缺点 二、边界值分析法2.1 定义2.2 步骤2.3 边界值分析法的优点和缺点 三、判定表法3.1 定义3.2 步骤3.3 判定表组成不分3.4 判定表的优点和缺点 四、正交实验法4.1 定义4.2 步骤4.3 正交实验法的优点和缺点 五…

论文研读|以真实图像为参考依据的AIGC检测

前言&#xff1a;这篇文章介绍几篇AIGC检测的相关工作&#xff0c;其中前几篇文章是以真实图像的特征作为标准进行检测&#xff0c;最后一篇文章就当拓展一下知识边界吧&#xff5e; 目录 Detecting Generated Images by Real Images Only (202311 arXiv)Let Real Images be as…

WebGL渲染引擎优化方向 -- 内存管理的优化

作者&#xff1a;caven chen 对此系列感兴趣还可以看前文&#xff1a; WebGL渲染引擎优化方向 -- 加载性能优化 WebGL渲染引擎优化方向——渲染帧率的优化 前言 WebGL 是一种强大的图形渲染技术&#xff0c;可以在浏览器中快速渲染复杂的 3D 场景。但是&#xff0c;由于 W…

MySQL与PostgreSQL关键对比三(索引类型)

目录 索引类型 B-tree 索引 Hash 索引 Full-text 索引 GiST 索引 GIN 索引 BRIN 索引 索引创建示例 MySQL PostgreSQL 结论 以下SQL语句的执行如果需要开发工具支持&#xff0c;可以尝试使用SQLynx或Navicat来执行。 MySQL和PostgreSQL在索引方面有许多相似之处&am…

【kubernetes】k8s中包管理工具-----Helm 超详细解读

目录 一、Helm 1.1什么是 Helm 1.2Helm 有三个重要的概念 1.2.1Chart 1.2.2Repository&#xff08;仓库&#xff09; 1.2.3Release 1.3Helm3 与 Helm2 的区别 二、Helm 部署 2.1安装 helm 2.2命令补全 2.3使用 helm 安装 Chart 2.3.1添加常用的 chart 仓库 2.3.2…

vue 和 js写屏幕自适应

实现屏幕自适应的方式有很多种&#xff0c;可以通过插件本身提供的方法&#xff0c;可以通过flex布局等&#xff0c;今天我们来写写通过js实现屏幕自适应。 以下是在vue中实现的屏幕自适应 首先在data中定义一下屏幕的默认大小和缩放比例 然后在mounted中获取窗口的内置宽高&a…