C++结合OpenCV:图像的加法运算

一、图像运算

针对图像的加法运算、位运算都是比较基础的运算。但是,很多复杂的图像处理功能正是借助这些基础的运算来完成的。所以,牢固掌握基础操作,对于更好地实现图像处理是非常有帮助的。本章简单介绍了加法运算、位运算,并使用它们实现了位平面分解、图像异或加密、数字水印、脸部打码/解码等实例。

1.图像加法运算

在图像处理过程中,经常需要对图像进行加法运算。可以通过加号运算符“+”对图像进行加法运算,在c++中也可以利用cv::add()对图像进行加法运算。

通常情况下,在灰度图像中,像素用8个比特位(一个字节)来表示,像素值的范围是[0,255]。两个像素值在进行加法运算时,求得的和很可能超过255。上述两种不同的加法运算方式,对超过255的数值的处理方式是不一样的。

加号运算符

使用加号运算符“+”对图像a(像素值为a)和图像b(像素值为b)进行求和运算时,遵循以下规则:

式中,mod()是取模运算,“mod(a+b, 256)”表示计算“a+b的和除以256取余数”。

根据上述规则,两个点进行加法运算时:

● 如果两个图像对应像素值的和小于或等于255,则直接相加得到运算结果。例如,像素值28和像素值36相加,得到计算结果64。

● 如果两个图像对应像素值的和大于255,则将运算结果对256取模。例如255+58=313,大于255,则计算(255+58)% 256=57,得到计算结果57。

当然,上述公式也可以简化为a+b=mod(a+b,256),在运算时无论相加的和是否大于255,都对数值256取模。

【例4.4.1】假设我们有两个8位灰度图像,图像a的像素值为a,图像b的像素值为b。

1.像素值a为28,像素值b为36。

2.像素值a为255,像素值b为58。

#include <iostream>#include <cmath>int main() {// 案例1: 像素值a为28, 像素值b为36int a1 = 28;int b1 = 36;int result1 = a1 + b1; // 结果直接相加std::cout << "a1 + b1 = " << result1 << std::endl; // 输出64int result1_mod = result1 % 256; // 对256取模std::cout << "mod(a1+b1, 256) = " << result1_mod << std::endl; // 输出64 (因为28+36小于或等于255)案例2: 像素值a为255, 像素值b为58int a2 = 255;int b2 = 58;int result2 = a2 + b2; // 结果直接相加std::cout << "a2 + b2 = " << result2 << std::endl; // 输出313int result2_mod = result2 % 256; // 对256取模std::cout << "mod(a2+b2, 256) = " << result2_mod << std::endl; // 输出57 (因为255+58大于255)return 0;}

上述代码演示了如何根据给定的规则对两个图像的像素值进行加法运算。对于每个案例,它首先计算直接相加的结果,然后计算对256取模的结果,以验证规则的正确性。

【例4.4.2】在c++中分别使用加号运算符和opencv库中的函数cv2.add()计算两幅灰度图像的像素值之和,观察处理结果。

#include <opencv2/opencv.hpp>#include <opencv2/highgui/highgui.hpp>int main() { // 读取图像cv::Mat a = cv::imread("lena.bmp", cv::IMREAD_GRAYSCALE);if (a.empty()) { std::cout << "无法读取图像" << std::endl; return -1; } // 创建图像的副本cv::Mat b = a.clone(); // 计算图像的和cv::Mat result1;cv::add(a, b, result1); // 使用函数cv2.add()计算a和b之和cv::Mat result2 = a + b; // 使用加号运算符计算a和b之和 // 显示原始图像和结果cv::namedWindow("Original",cv::WINDOW_NORMAL);cv::imshow("Original",a);cv::namedWindow("Result1", cv::WINDOW_NORMAL);cv::imshow("Result1", result1);cv::namedWindow("Result2",cv::WINDOW_NORMAL);cv::imshow("Result2", result2);cv::waitKey(0);cv::destroyAllWindows();return 0;}

在本例中,首先读取了图像lena并将其标记为变量a;接下来,使用语句“b=a”将图像lena复制到变量b内;最后,分别使用“+”cv::add()计算a和b之和。

运行程序,得到如图3-1所示的运行结果,其中:

图4-11 【例4.4.2】程序运行结果图

● 左图是原始图像lena。

● 中间的图是使用加号运算符将图像lena自身相加的结果。

● 右图是使用函数cv2.add()将图像lena自身相加的结果。从上述运算结果可以看出

● 使用加号运算符计算图像像素值的和时,将和大于255的值进行了取模处理,取模后大于255的这部分值变得更小了,导致本来应该更亮的像素点变得更暗了,相加所得的图像看起来并不自然。

● 使用函数cv::add()计算图像像素值的和时,将和大于255的值处理为饱和值255。图像像素值相加后让图像的像素值增大了,图像整体变亮。

2.图像加权和

所谓图像加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,可以用公式表示为:

dst=saturate(src1×α+src2×β+γ)

式中,saturate()表示取饱和值(最大值)。图像进行加权和计算时,要求src1和src2必须大小、类型相同,但是对具体是什么类型和通道没有特殊限制。它们可以是任意数据类型,也可以有任意数量的通道(灰度图像或者彩色图像),只要二者相同即可。

OpenCV 库中提出了一个addWeighted()函数,用于执行两个图像的加权和操作。这个函数可以用来创建一幅新的图像,其中包含了两幅输入图像的加权组合。通常,这在图像融合和混合的应用中非常有用,该函数的语法格式为:

void cv::addWeighted(cv::InputArray src1,   // 第一个输入图像double alpha,          // 第一个输入图像的权重cv::InputArray src2,   // 第二个输入图像double beta,           // 第二个输入图像的权重double gamma,          // 加权和的可选标量cv::OutputArray dst,  // 输出图像int dtype = -1        // 输出图像的数据类型,默认为-1(与输入相同));

其中,参数alpha和beta是src1和src2所对应的系数,它们的和可以等于1,也可以不等于1。该函数实现的功能是dst = src1×alpha + src2×beta + gamma。需要注意,式中参数gamma的值可以是0,但是该参数是必选参数,不能省略。可以将上式理解为“结果图像=图像1×系数1+图像2×系数2+亮度调节量”。

参数说明:

  1. src1:第一个输入图像(可以是 cv::Mat 类型或类似的数据结构)。
  2. alpha:第一个输入图像的权重,一个双精度浮点数。
  3. src2:第二个输入图像。
  4. beta:第二个输入图像的权重,也是一个双精度浮点数。
  5. gamma:加权和的可选标量,通常是一个双精度浮点数。
  6. dst:输出图像,这里将存储加权和的结果。
  7. dtype:输出图像的数据类型,默认为-1,表示与输入图像的数据类型相同。

【例4.4.3】使用函数cv::addWeighted()对两幅图像进行加权混合,观察处理结果。根据题目要求,编写程序如下:

#include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat a = cv::imread("boat.bmp");cv::Mat b = cv::imread("lena.bmp"); // 检查图像是否正确读取if (a.empty() || b.empty()) {std::cout << "无法读取图像文件!" << std::endl;return -1;}// 计算加权和cv::Mat result;cv::addWeighted(a, 0.6, b, 0.4, 0, result); // 显示图像cv::namedWindow("boat", cv::WINDOW_NORMAL);cv::imshow("boat", a);cv::namedWindow("lena", cv::WINDOW_NORMAL);cv::imshow("lena", b);cv::namedWindow("result", cv::WINDOW_NORMAL);cv::imshow("result", result); // 等待按键,然后关闭窗口cv::waitKey(0); cv::destroyAllWindows();return 0;}

本程序使用cv2.addWeighted()函数,对图像boat和图像lena分别按照0.6和0.4的权重进行混合。运行程序,得到如图4-12所示的结果,其中:

● 左图是原始图像boat。

● 中间的图是原始图像lena。

● 右图是图像boat和图像lena加权混合后的结果图像。

图4-12 【例4.4.3】程序的运行结果

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

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

相关文章

自学Python笔记总结(更新中……)

自学Python笔记总结 网址数据类型类型查看类型&#xff0c;使用type内置类标识符 输出输入语句format函数的语法及用法数据类型的转换运算符算数运算符赋值运算符的特殊场景拆包 比较运算符逻辑运算符 与 短路位运算符运算符优先级 程序流程控制分支语句pass 占位 循环语句 whi…

DFT新手入门:VASPKIT生成模版INCAR

新手学习VASP计算时一般需要自行准备好VASP所需要的四个输入文件:INCAR POSCAR KPOINTS POTCAR。 其中POSCAR为计算任务的模型文件&#xff0c;POTCAR为与POSCAR中元素所对应的赝势&#xff0c;可根据要求选取。 KPOINTS的设置需要根据精度确定&#xff0c;一般通过vaspkit的1…

实现STM32烧写程序-(4) BIN文件结构

简介 BIN文件是一种二进制文件格式&#xff0c;用于存储和传输二进制数据。它包含了计算机或设备可以直接读取和执行的原始二进制数据。BIN文件通常用于存储程序、固件或其他二进制数据&#xff0c;例如嵌入式系统的固件、操作系统的映像文件等。 BIN文件的起源可以追溯到计算机…

获取本地IP网卡信息

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、获取本地IP&#xff0c;以及全部网卡信息总结 前言 一、获取本地IP&#xff0c;以及全部网卡信息 const os require(node:os) function getIPAdress(){/…

node-red实现ModBus-RTU 通信协议(RS485信号输出)的数据交互

node-red实现485型 - 温湿度变表数据转换 一、介绍二、 通讯协议2.1 通讯基本参数2.2 数据帧格式定义2.3 寄存器地址2.4 通讯协议示例以及解释 三、 node-red实现数据交互3.1 node-red读取数据3.2 node-red写回数据 本文参考《86 壳液晶温湿度变送器使用说明书&#xff08;485 …

html5+css3+bootstrap+js 新闻网页

新闻网页练习打卡&#xff01; 一、首页 二、社会 三、财经 四、视频展示 简易新闻网站&#xff08;期末作业&#xff09;

Cuda与Torch配置(For 集群服务器)超详细步骤

每次配置模型环境&#xff0c;无论是在windows&#xff0c;linux&#xff0c;集群服务器上都会在这里卡一段&#xff0c;为了未来配置方便&#xff0c;记录下配置注意事项 配置cuda和torch主要有几个要点&#xff0c;分别是&#xff1a; 显卡与驱动&#xff08;NIVIADA drive…

一刀切转为精细化,门店如何进行「体检式」巡查(一)

在品牌经营过程中&#xff0c;无论是直营店还是加盟商&#xff0c;都需要做好统一的品牌门店管理。比如总部对门店环境卫生、员工服务质量、货品质量等进行定期或不定期的巡检抽查&#xff0c;以确保各门店保持统一标准。 以往&#xff0c;传统巡店只能通过有纸质表格或微信汇报…

前端react入门day03-react获取dom与组件通信

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 受控表单绑定 React中获取DOM 组件通信 父传子 父传子-基础实现 父传子-props说明 父传子 - 特殊的…

FFmpeg之AVFilter

文章目录 一、概述二、重要结构体2.1、AVFilterGraph2.2、AVFilter2.3、AVFilterContext 三、流程梳理3.1、FFmpeg AVFilter 使用整体流程3.2、过滤器构建流程3.2.1、分配AVFilterGraph3.2.2、创建过滤器源3.2.3、创建接收过滤器3.2.4、生成源和接收过滤器的输入输出3.2.5、通过…

Java开发+Intellij-idea+Maven+工程构建

Java开发Intellij-ideaMaven工程构建 Intellij-idea是一款流行的Java集成开发环境&#xff0c;它支持Maven作为项目管理和构建工具。Maven可以帮助开发者自动下载项目依赖的jar包&#xff0c;执行编译、测试、打包等生命周期任务。本资源将介绍如何在Intellij-idea中创建、导入…

精品基于Uniapp+springboot车辆充电桩缴费管理系统管理系统App-地图

《[含文档PPT源码等]精品基于Uniappspringboot充电桩管理系统App》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 后台框架&#xff1a;springboot、ssm 安…

element + table 每两行对比相同值列合并

在开始之前先要明确几个概念&#xff1a; 保持不变&#xff1a;{ rowspan: 1, colspan: 1 } 删除一个单元格&#xff1a;{ rowspan: 0, colspan: 0 } 合并一个单元格&#xff1a;{ rowspan: 2, colspan: 1 } <template><div><el-table:data"tableData&quo…

Appium 自动化测试

1.Appium介绍 1&#xff0c;appium是开源的移动端自动化测试框架&#xff1b; 2&#xff0c;appium可以测试原生的、混合的、以及移动端的web项目&#xff1b; 3&#xff0c;appium可以测试ios&#xff0c;android应用&#xff08;当然了&#xff0c;还有firefoxos&#xff09;…

web自动化实现登录的几种方式

目录 前言 一、pythonunittest框架实现登录功能 二、pythonselenium实现登录功能 三、pythonrequests库实现登录功能 前言 今天主要想介绍python语言不同的自动化测试框架的结合方式来模拟登录功能。想了解自动化测试框架的同学不要错过哦&#xff01; 一、pythonunittest框…

Windows 下 QT开发环境的搭建:

下载QT:Index of /archive/qt/5.14 下载Cmake :CMake - Upgrade Your Software Build System (1)QT在windows,C, 打包exe&#xff1a; step1:window上安装QT软件&#xff1a; Windows下的QT系统开发环境搭建_qt windows-CSDN博客. step2:新建一个界面工程&#xff1a; (1)打…

【css】渐变效果

css渐变效果 使用 CSS 渐变可以在两种颜色间制造出平滑的渐变效果。 用它代替图片&#xff0c;可以加快页面的载入时间、减小带宽占用。同时&#xff0c;因为渐变是由浏览器直接生成的&#xff0c;它在页面缩放时的效果比图片更好&#xff0c;因此你可以更加灵活、便捷的调整页…

postgresql16 物理复制与逻辑复制的实现和对比

本文面向想要练习 PostgreSQL 中数据库复制基础知识但可能无法访问远程服务器的初学者。我认为学习新技术时&#xff0c;在自己的机器上运行示例以巩固概念是至关重要的。对于副本来说&#xff0c;这可能很困难&#xff0c;因为许多可用的资源假设用户具有一定的 PostgreSQL 经…

网页屏幕适配通透了

一&#xff0c;如果设计尺寸固定 那就按照固定尺寸开发 一般都是1920*1080 二&#xff0c;需要适配多种像素屏幕&#xff08;大屏可视化&#xff09; 可使用媒体查询设置多套css样式或者使用自适应单位&#xff0c;%&#xff0c;vw&#xff0c;vh 最好解决方案rem&#xff…

IPv6路由综合运用

一、基础配置: SWA: sw1(config)#host swA swA(config)#ipv6 ena swA(config)# vlan 100 swA(config-vlan100)#int vlan 100 swA(config-if-vlan100)#ipv6 ena swA(config-vlan100)#ip add 172.16.1.1 255.255.255.252 swA(config-if-vlan100)#int e1/0/24 swA(conf…