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函数实现图像线性混合

线性混合就是指两个图片或两段视频以某种函数关系叠加呈现。

扫描二维码关注公众号,回复: 12873548 查看本文章

对于输入的两张图像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.");
}

猜你喜欢

转载自blog.csdn.net/m0_51233386/article/details/113829240