OpenCV C++ 图像叠加线性混合 方法总结
// 操作系统: Windows 10 64bit
// 开发语言: C++
// IDE 版 本:Visual Studio 2019
// OpenCV版本:4.20
一丶利用感兴趣区域ROI实现图像叠加
ROI(region of interest),感兴趣区域。机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI。在Halcon、OpenCV、Matlab等机器视觉软件上常用到各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。
1 创建ROI区域
// 定义一个Mat类型,用于存放,图像的ROI
Mat imageROI;
//方法一
imageROI= image(Rect(800,350,logo.cols,logo.rows));
//方法二
//imageROI= image(Range(350,350+logo.rows),Range(800,800+logo.cols));
//在这里相当于用指针的知识将roi区域指向为image图像相应区域
Rect(x,y,w,h)
x,y是image的ROI区域左上角的坐标;image左上角的坐标(0,0)
x+logo.cols不能大于image对象图片的宽度
y+logo.rows不能大于image对象图片的高度
2 构建ROI区域掩膜(图像叠加的基础)
Mat ROI = image(Rect(200, 250, logo.cols, logo.rows));
Mat mask = imread("logo.jpg", 0);//掩膜必须为叠加图片的灰度图
logo.copyTo(ROI, mask);
3 代码实现及效果
下面显示如何利用ROI将一幅图加到另一幅图的指定位置
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main()
{
//【1】读入图像
Mat srcImage1 = imread("49.jpg");
Mat logoImage = imread("61.jpg");
//显示原图
namedWindow("【1】原图");
imshow("【1】原图", srcImage1);
namedWindow("【2】原图");
imshow("【2】logo", logoImage);
//【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI = srcImage1(Rect(320, 120, logoImage.cols, logoImage.rows));
//【3】加载掩模(必须是灰度图)
Mat mask = imread("61.jpg", 0);
//【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI, mask);
//【5】显示结果
namedWindow("【3】ROI图像叠加");
imshow("【3】ROI图像叠加", srcImage1);
waitKey();
return 0;
}
这个函数首先是载入了两张jpg图片到srcImage1和logoImage中,然后定义了一个Mat类型的imageROI,并使用cv::Rect设置其感兴趣区域为srcImage1中的一块区域,将imageROI和srcImage1关联起来。接着定义了一个Mat类型的的mask并读入dota_logo.jpg,顺势使用Mat:: copyTo把mask中的内容拷贝到imageROI中,于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。
图一 、图二原图
下面是叠加效果
二丶addWeighted函数实现图像线性混合
线性混合就是指两个图片或两段视频以某种函数关系叠加呈现。
对于输入的两张图像A和B,取它们相同位置处的像素值进行线性相加,然后将结果赋值给目标图像相同位置处的像素。其中参数α控制了两张图片在目标图像中的权重。
g(x)=αA(x)+(1−α)B(x)
图像的线性混合有什么作用呢?在幻灯片翻页或者电影制作中,经常需要产生画面叠加的效果。在上式中,只要使得α从1逐渐减小到0即可产生从图像I0过渡到图像I1时的叠加效果了。
OpenCV中提供了一个用于两张图像线性混合的API。API所依据的计算公式如下:
dst = src1[i] * α + src2[i] * β + γ;
addWeighted原函数
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1);**
第一个参数:要叠加的第一个图像Mat
第二个参数:标识第一个参数叠加的权重
第三个参数:表示第二个叠加的图像,他需要和第一个数组拥有同样的尺寸和通道数
第四个参数:表示第二个叠加图像的权重
第五个参数:输出参数,需要和前两个图像拥有同样的通道数和尺寸
第六个参数:一个加到权重总和上的标量值(填0就好)
第七个参数:输出阵列的深度有默认值-1, 当两张叠加图片深度相同时,参数为-1
// 将logo加到原图上
//【3】将logo加到原图上,利用线性混合构建掩膜,其中logo权重是0.3,原图中的ROI区域图像是0.5
addWeighted(imageROI, 0.5, logo, 0.5,0, imageROI);
值得注意的是:
两幅图像尺寸类型必须的一致,若果两幅图像不一致,那先用ROI提取尺寸较小的图像再来叠加吧。虽然没有强制两个权重相加必须为1,但通常都是那么干的。
代码实现
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main()
{
//【0】定义一些局部变量
double α = 0.4;
double β;
Mat srcImage2, srcImage3, dstImage;
//【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
srcImage2 = imread("67.jpg");
srcImage3 = imread("68.jpg");
//【2】做图像混合加权操作
β = (1.0 - α);
addWeighted(srcImage2, α, srcImage3, β, 0., dstImage);
//【3】创建并显示
namedWindow("<1>原图");
imshow("<1>原图", srcImage2);
namedWindow("<2>原图");
imshow("<2>原图", srcImage3);
namedWindow("<3>线性混合效果图");
imshow("<3>线性混合示效果图", dstImage);
waitKey();
return 0;
}
图一、图二原图(两张图片必须一样尺寸)
此处是截图图片,尺寸可能不一样,就无法运行
如果下载不到两幅完全相同的图片,可以参照此链接改变任意尺寸
https://blog.csdn.net/m0_51233386/article/details/112393204.
图三效果图
三、ROI和addWeighted结合图像混合操作
ROI(region of interest)感兴趣区域,在图像处理过程中,有时候我们希望对图像中的某些区域进行处理,也就是仅对某些区域感兴趣,那么ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main()
{
//-----------------------------------【一、初级图像混合】--------------------------------------
// 描述:二、初级图像混合
//--------------------------------------------------------------------------------------------------
//载入图片
Mat image = imread("49.jpg");
Mat logo = imread("61.jpg");
// 定义一个Mat类型,用于存放,图像的ROI
Mat imageROI;
//方法一
imageROI = image(Rect(300, 80, logo.cols, logo.rows));
//方法二
//imageROI= image(Range(320,320+logo.rows),Range(120,120+logo.cols));
// 将logo加到原图上
//【3】将logo加到原图上 ,利用线性混合构建掩膜,其中logo权重是0.8,原图中的ROI区域图像是0.2
addWeighted(imageROI, 1, logo, 0.5, 0, imageROI);
//显示结果
namedWindow("【3】49");
imshow("【3】49+61", image);
//-----------------------------------【二、图像的输出】--------------------------------------
// 描述:将一个Mat图像输出到图像文件
//-----------------------------------------------------------------------------------------------
//输出一张jpg图片到工程目录下
imwrite("由imwrite生成的图片.jpg", image);
waitKey();
return 0;
}
下面是叠加效果
此方法与 方法一 ROI叠加方法的基础上,增加了图像叠加权重
四 、直接相加(非线性)
函数为 add()
示例:add(src1, src2, dst_add);
代码实现及效果
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int Add() {
Mat src1, src2, dst_add;
add(src1, src2, dst_add);
//叠加函数图像的函数
imshow("src1", src1);
imshow("src2", src2);
imshow("dst_add", dst_add);
waitKey();
return 0;
}
int main()
{
Add(); //图像叠加
return 0;
}
叠加效果
//读入图像方法
//读入图像 方法一
src1 = imread("67.jpg");
src2 = imread("68.jpg");
//读入图像 方法二
const char* filename1 = "67.jpg";
const char* filename2 = "68.jpg";
imread(filename1).copyTo(src1);
if (src1.empty()) {
throw("Faild open file.");
}
imread(filename2).copyTo(src2);
if (src2.empty()) {
throw("Faild open file.");
}