openCV跌撞笔记(一):图像融合

本文主要通过图像金字塔来实现图像融合。
(案例:苹果和橘子的左右融合)
在这里

原理

1. 高斯金字塔
高斯金字塔包含了一系列低通滤波器,可以对图像进行下采样(pyrDown)和上采样(pyrUp)

下采样:即缩小图片,会损失图像信息,具体步骤为:
①对图像进行高斯内核卷积
②将所有偶数行和列去除

上采样:即放大图片,具体步骤为:
①将图像在每个方向扩大为原来的两倍,新增的行和列以0填充
②使用先前同样的内核与放大后的图像卷积,获得 “新增像素”的近似值

2. 拉普拉斯金字塔
简单讲就是:原图像-先缩小后放大的图像,可以获得高频信息

具体关于金字塔方面的知识可以参考:一篇很好的入门教程~

3. 案例原理
网上有很多关于这方面的原理,这里就不一一赘述了,大致就是:
高斯金字塔上采样结果(低频信息)+拉普拉斯金字塔(高频信息)

代码

这里有用到以下素材:
mask:
在这里插入图片描述
apple:
在这里插入图片描述
orange:
在这里插入图片描述

#include <iostream>
#include "opencv.hpp"
using namespace cv;
using namespace std;

int main()
{
	Mat apple = imread("apple.png", IMREAD_ANYCOLOR); //读入无损源图像
	apple.convertTo(apple, CV_32F, 1.0 / 255.0);//进行色彩空间转换 scale=1.0/255.0归一
	Mat orange = imread("orange.png", IMREAD_ANYCOLOR);
	orange.convertTo(orange, CV_32F, 1.0 / 255.0);
	Mat mask = imread("mask.png");
	mask.convertTo(mask, CV_32F, 1.0 / 255.0);

	int level = 5;//金字塔层数
	vector <Mat> apple_LaplacianPyramid, apple_GaussianPyramid;
	vector <Mat> orange_LaplacianPyramid, orange_GaussianPyramid;
	vector <Mat> GaussianPyramid_mask;

	//继续生成橘子和苹果的拉普拉斯金字塔
	Mat apple1, apple2, apple3, Lap1, appleHighestLevel;
	apple.copyTo(apple1);
	for (int i = 0;i < level;i++)
	{
		pyrDown(apple1, apple2);//默认尺寸缩小一半
		apple_GaussianPyramid.push_back(apple2);//加入苹果高斯容器
		pyrUp(apple2, apple3, apple1.size());//默认尺寸增大一倍
		Lap1 = apple1 - apple3;	//原图apple1-先缩小后放大的图apple3
		apple_LaplacianPyramid.push_back(Lap1);	//加入苹果拉普拉斯容器
		apple1 = apple2;//重新赋值

	}
	apple1.copyTo(appleHighestLevel);//生成最高层


	Mat orange1, orange2, orange3, Lap2, orangeHighestLevel;
	orange.copyTo(orange1);
	for (int i = 0;i < level;i++)
	{
		pyrDown(orange1, orange2);
		orange_GaussianPyramid.push_back(orange2);
		pyrUp(orange2, orange3, orange1.size());
		Lap2 = orange1 - orange3;
		orange_LaplacianPyramid.push_back(Lap2);
		orange1 = orange2;
	}
	orange1.copyTo(orangeHighestLevel);

	//mask生成金字塔
	Mat mask1, mask2, maskHighestLevel;
	mask.copyTo(mask1);
	GaussianPyramid_mask.push_back(mask);//0-level
	for (int i = 0; i < level; i++)
	{
		pyrDown(mask1, mask2);	//缩小
		GaussianPyramid_mask.push_back(mask2);
		mask1 = mask2;//重新赋值 为下一个level做准备
	}
	mask1.copyTo(maskHighestLevel);

	//利用模板乘以两边的图形进行融合
	vector<Mat>Fusion;
	Mat fusion, fusionHighestLevel;

	//低频部分
	fusionHighestLevel = appleHighestLevel.mul(GaussianPyramid_mask.back())
		+ orangeHighestLevel.mul(Scalar(1.0, 1.0, 1.0) - GaussianPyramid_mask.back());

	//高频部分
	for (int i = 0;i < level;i++)
	{
		//resize保证大小一致
		resize(GaussianPyramid_mask[i], GaussianPyramid_mask[i], Size(apple_LaplacianPyramid[i].cols, apple_LaplacianPyramid[i].rows));
		fusion = GaussianPyramid_mask[i].mul(apple_LaplacianPyramid[i])
			+ (Scalar(1.0, 1.0, 1.0) - GaussianPyramid_mask[i]).mul(orange_LaplacianPyramid[i]);
		Fusion.push_back(fusion);
	}

	//金字塔重建与恢复
	Mat orapple = fusionHighestLevel;
	Mat up;
	for (int l = level - 1; l >= 0; l--)
	{
		pyrUp(orapple, up, Fusion[l].size());
		orapple = up + Fusion[l]; //模糊+细节
		//imshow("up", up);
		//imshow("Fusion[l]", Fusion[l]);
	}
	

	imshow("左半边", apple);
	imshow("右半边", orange);
	imshow("融合结果", orapple);
	waitKey(0);
}

注意点:

①我再学习写代码的时候,有找过网上代码运行,有些遇到融合后图片色调整体变暗的情况,如图
在这里插入图片描述
检查代码发现是因为只用了拉普拉斯层(高频信息)作为最终融合结果,改成上述代码即可!

②在测试不同图片融合结果的时候发现,有时候会报错:
在这里插入图片描述
错误信息:
OpenCV Error: Sizes of input arguments do not match (The operation is neither ‘array op array’ (where arrays have the same size and the same number of channels), nor ‘array op scalar’, nor ‘scalar op array’) in cv::arithm_op, file C:\build\2_4_winpack-build-win64-vc14\opencv\modules\core\src\arithm.cpp, line 1295
(os.什么乱七八糟)

然后发现其实是犯了一个低级错误,融合时.mul函数必须确保两边矩阵size相同,也就是说,在这里要确保左半边层、右半边层、mask层size相同,如果不同的话,我这里采用resize函数进行统一!

(鄙人小白一个,有问题欢迎指出,我虚心改正学习!!)
———————————————————END————————————————————

猜你喜欢

转载自blog.csdn.net/weixin_40614231/article/details/83413471