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为36

int a1 = 28;

int b1 = 36;

int result1 = a1 + b1; // 结果直接相加

std::cout << "a1 + b1 = " << result1 << std::endl; // 输出64

int result1_mod = result1 % 256; // 对256取模

std::cout << "mod(a1+b1, 256) = " << result1_mod << std::endl; // 输出64 (因为28+36小于或等于255)



案例2: 像素值a为255, 像素值b为58

int a2 = 255;

int b2 = 58;

int result2 = a2 + b2; // 结果直接相加

std::cout << "a2 + b2 = " << result2 << std::endl; // 输出313

int 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】程序的运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【java八股文】之Redis基础篇

【java八股文】之JVM基础篇-CSDN博客 【java八股文】之MYSQL基础篇-CSDN博客 【java八股文】之Redis基础篇-CSDN博客 【java八股文】之Spring系列篇-CSDN博客 【java八股文】之分布式系列篇-CSDN博客 【java八股文】之多线程篇-CSDN博客 【java八股文】之JVM基础篇-CSDN博…

OpenHarmony—Docker编译环境

Docker环境介绍 OpenHarmony为开发者提供了两种Docker环境&#xff0c;以帮助开发者快速完成复杂的开发环境准备工作。两种Docker环境及适用场景如下&#xff1a; 独立Docker环境&#xff1a;适用于直接基于Ubuntu、Windows操作系统平台进行版本编译的场景。基于HPM的Docker环…

视频和音频怎么合并在一起?分享3个轻松合并的实用技巧

视频和音频怎么合并在一起&#xff1f;在数字媒体时代&#xff0c;视频和音频是制作多媒体内容不可或缺的元素。有时我们需要将视频和音频合并在一起&#xff0c;以创建更丰富、更有趣的多媒体内容。那么&#xff0c;如何将视频和音频合并在一起呢&#xff1f;下面将介绍一些实…

【C++】__declspec含义

目录 一、__declspec(dllexport)如果这篇文章对你有所帮助&#xff0c;渴望获得你的一个点赞&#xff01; 一、__declspec(dllexport) __declspec(dllexport) 是 Microsoft Visual C 编译器提供的一个扩展&#xff0c;用于指示一个函数或变量在 DLL&#xff08;动态链接库&…

scrapy爬虫实战

scrapy爬虫实战 Scrapy 简介主要特性示例代码 安装scrapy&#xff0c;并创建项目运行单个脚本代码示例配置itemsetting 爬虫脚本 代码解析xpath基本语法&#xff1a;路径表达式示例&#xff1a;通配符和多路径&#xff1a;函数&#xff1a;示例&#xff1a; 批量运行附录1&…

自动化测试 - Web自动化测试原理

目前市面上有很多Web UI自动化测试框架&#xff0c;比如WatiN, Selinimu,WebDriver&#xff0c;还有VS2010中的Coded UI等等. 这些框架都可以操作Web中的控件&#xff0c;模拟用户输入&#xff0c;点击等操作&#xff0c;实现Web自动化测试。其实这些工具的原理都一样&#xff…

谷达冠楠:抖店新手小白适合卖什么

随着抖音平台的不断发展&#xff0c;越来越多的人开始尝试在抖音上开设自己的店铺&#xff0c;希望通过这个平台实现创业梦想。然而&#xff0c;对于新手小白来说&#xff0c;如何选择合适的商品进行销售是一个非常重要的问题。本文将为您介绍一些适合抖店新手小白销售的商品类…

若依框架实现排序【升序或降序】很简单

前端实现 1. 在表格上加监听函数sort-change。如下红框所示&#xff1a; 2. 在表行上加排序字:sort-orders&#xff0c;可排序字sortable。如下红框所示&#xff1a; 3. 添加监听函数实现。代码如下&#xff1a; handleSortChange(column) {this.queryParams.orderByColumn …

什么是云服务器ECS - 云服务器 ECS - 阿里云

阿里云服务器ECS英文全程Elastic Compute Service&#xff0c;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云百科aliyunbai…

云渲染农场渲染和自己搭建农场渲染怎么选?哪个更划算?

&#xfeff;当我们面临繁重或紧急的渲染任务时&#xff0c;通常会选择云渲染的解决方案。可能很多人会问&#xff0c;我们是否能够自行建立一个小型的个人农场进行渲染呢&#xff1f;与云渲染农场相比&#xff0c;哪个更划算&#xff1f;更方便&#xff1f;接下来就带大家看看…

Yii实现邮件发送

一&#xff1a;yiisoft/yii2-swiftmailer拓展安装 composer require yiisoft/yii2-swiftmailer github地址&#xff1a;https://github.com/yiisoft/yii2-swiftmailer 文档地址&#xff1a;https://www.yiichina.com/doc/guide/2.0/tutorial-mailing 二&#xff1a;开启邮箱…

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

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

线程之间如何传递上下文信息

文章目录 源码解读1. 扩展ThreadPoolExecutor2. 扩展Runnable3. 整体流程 源于工作中一个业务场景的需求。 源码 话不多说&#xff0c;先贴完整的源码&#xff1a; public class ContextPassingBetweenThread {private static ThreadLocal<String> CONTEXT new Thread…

如何构建高质量,低成本的移动机器人(AGV/AMR)?

中国移动机器人行业规模的不断扩大&#xff0c;低成本无人化是现市场需求突出的特点之一。然而研发一套完整的移动机器人导航方案不仅需要耗费大量的人力成本&#xff0c;还要经过漫长的市场验证&#xff0c;这将滞后整个产业的发展&#xff0c;并有可能错失市场的抢占先机。 如…

coala,一个超级实用的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超级实用的 Python 库 - coala。 Github地址&#xff1a;https://github.com/coala/coala/ 在现代软件开发中&#xff0c;代码质量和一致性是非常重要的。然而&#xff0c…

多合一小程序商城系统源码:支持全平台端口 附带完整的搭建教程

现如今&#xff0c;随着移动互联网的飞速发展&#xff0c;小程序已经成为电商行业的新宠。罗峰给大家分享一款多合一小程序商城系统源码。该系统旨在为商家提供一个功能强大、易于搭建和管理的电商平台&#xff0c;帮助商家快速占领市场&#xff0c;提高品牌影响力。 以下是部…

springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件

springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件 这是由于公司老项目转化springboot存在太多坑&#xff0c;特别是hibernate事务一条就坑到跑路&#xff0c;你又不想搞没听说过的国产中间件兼容&#xff0c;又不想搞weblogic、WebSphere等中间件的适配&#xff…

Linux信号之信号的保存

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目录 一、阻塞信号 1.信号递达、未决、阻塞 2.内核…

flutter给组件设置背景图的操作

可以设置背景图的组件只有一个&#xff0c;那就是Container容器&#xff0c;要想设置背景图&#xff0c;可以使用网路图片&#xff0c;也可以使用本地图片&#xff0c;要是使用本地图片&#xff0c;需要在本地添加一个资源路径&#xff0c;用来管理这些文件&#xff0c;在本地项…

大量文件重命名数字排序有什么好方法?快来看这里

随着数字时代的到来&#xff0c;我们每天都会处理大量的文件&#xff0c;无论是工作还是生活。为了更好地管理和查找这些文件&#xff0c;我们通常会使用数字排序来对它们进行排列。那么&#xff0c;为什么要给大量文件添加数字排序呢&#xff1f; 首先&#xff0c;数字排序可以…