OpenCV金字塔图像分辨率重建与融合
Posted OpenCV学堂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV金字塔图像分辨率重建与融合相关的知识,希望对你有一定的参考价值。
图像高斯金字塔
图像金字塔是对一张输入图像先模糊再下采样为原来宽高的1/2(宽高缩小一半)、不断重复模糊与下采样的过程就得到了不同分辨率的输出图像,叠加在一起就形成了图像金字塔、所以图像金字塔是图像的空间多分辨率存在形式。这里的模糊是指高斯模糊,所以这个方式生成的金字塔图像又称为高斯金字塔图像。高斯金字塔图像有两个基本操作
reduce 是从原图生成高斯金字塔图像、生成一系列低分辨图像,OpenCV对应的相关API为:
pyrDown(
InputArray src,
OutputArray dst,
const Size & dstsize = Size(),
int borderType = BORDER_DEFAULT
)
其中输出的图像dst大小必须满足下面的要求:
expand是从高斯金字塔图像反向生成高分辨率图像,其OpenCV对应的API为:
pyrUp(
InputArray src,
OutputArray dst,
const Size & dstsize = Size(),
int borderType = BORDER_DEFAULT
)
其中输出的图像dst大小必须满足下面的要求:
拉普拉斯金字塔
对输入图像实现金字塔的reduce操作就会生成不同分辨率的图像、对这些图像进行金字塔expand操作,然后使用reduce减去expand之后的结果就会得到图像拉普拉斯金字塔图像。举例如下:
输入图像G(0)
金字塔reduce操作生成 G(1), G(2), G(3)
拉普拉斯金字塔:
L0 = G(0)-expand(G(1))
L1 = G(1)-expand(G(2))
L2 = G(2)–expand(G(3))
G(0)减去expand(G(1))得到的结果就是两次高斯模糊输出的不同,所以L0称为DOG(高斯不同)、它约等于LOG所以又称为拉普拉斯金字塔。所以要求的图像的拉普拉斯金字塔,首先要进行金字塔的reduce操作,然后在通过expand操作,最后相减得到拉普拉斯金字塔图像。
拉普拉斯金字塔图像重建
我们从拉普拉斯金字塔的定义知道,拉普拉斯金字塔的每一层都是一个高斯分差图像(DOG),以第L0层为例:
拉普拉斯金子图 L0 层 = 原图 – expand(高斯金字塔G1层)
对上面的共识变换,得到如下的结果:
原图 = 拉普拉斯金子图 L0 层 + expand(高斯金字塔G1层)
也就是说我们可以基于低分辨率的图像与它的高斯差分图像,重建生成一个高分辨率的图像。
上图左侧是对两幅输入图像生成高斯金子图,在最小分辨率的时候对他们进行图像融合生成一个低分辨率版本的融合图像,同时生成它们的拉普拉斯金字塔的融合图像,右侧的图像是根据低分辨率版本的融合图像以及它们的拉普拉斯差分图像,不断重建生成了最终的高分辨融合重新的近似原图。
建立图像高斯金字塔并生成最小分辨率图像代码如下:
vector<Mat> buildGaussianPyramid(Mat &image) {
vector<Mat> pyramid;
Mat copy = image.clone();
pyramid.push_back(image.clone());
Mat dst;
for (int i = 0; i<level; i++) {
pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));
dst.copyTo(copy);
pyramid.push_back(dst.clone());
}
smallestLevel = dst;
return pyramid;
}
建立拉普拉斯金字塔并生成最小分差图像代码如下:
vector<Mat> buildLapacianPyramid(Mat &image) {
vector<Mat> lp;
Mat temp;
Mat copy = image.clone();
Mat dst;
for (int i = 0; i<level; i++) {
pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));
pyrUp(dst, temp, copy.size());
Mat lapaian;
subtract(copy, temp, lapaian);
lp.push_back(lapaian);
copy = dst.clone();
}
smallestLevel = dst;
return lp;
}
实现对每一层融合生成新图的代码如下:
Mat blend(Mat &a, Mat &b, Mat &m) {
int width = a.cols;
int height = a.rows;
Mat dst = Mat::zeros(a.size(), a.type());
Vec3b rgb1;
Vec3b rgb2;
int r1 = 0, g1 = 0, b1 = 0;
int r2 = 0, g2 = 0, b2 = 0;
int red = 0, green = 0, blue = 0;
int w = 0;
float w1 = 0, w2 = 0;
for (int row = 0; row<height; row++) {
for (int col = 0; col<width; col++) {
rgb1 = a.at<Vec3b>(row, col);
rgb2 = b.at<Vec3b>(row, col);
w = m.at<uchar>(row, col);
w2 = w / 255.0f;
w1 = 1.0f - w2;
b1 = rgb1[0] & 0xff;
g1 = rgb1[1] & 0xff;
r1 = rgb1[2] & 0xff;
b2 = rgb2[0] & 0xff;
g2 = rgb2[1] & 0xff;
r2 = rgb2[2] & 0xff;
red = (int)(r1*w1 + r2*w2);
green = (int)(g1*w1 + g2*w2);
blue = (int)(b1*w1 + b2*w2);
// output
dst.at<Vec3b>(row, col)[0] = blue;
dst.at<Vec3b>(row, col)[1] = green;
dst.at<Vec3b>(row, col)[2] = red;
}
}
return dst;
}
根据拉普拉斯金字塔重新高分辨率近似原图的代码如下:
// 重建拉普拉斯金字塔
vector<Mat> ls;
for (int i = 0; i<level; i++) {
Mat a = la[i];
Mat b = lb[i];
Mat m = maskPyramid[i];
ls.push_back(blend(a, b, m));
}
// 重建原图
Mat temp;
for (int i = level - 1; i >= 0; i--) {
pyrUp(currentImage, temp, ls[i].size());
add(temp, ls[i], currentImage);
}
最终输入两张图像:
重建融合效果如下:
【推荐阅读】
无冥冥之志者,无昭昭之明
无惛惛之事者,无赫赫之功
关注【OpenCV学堂】
长按或者扫码二维码即可关注
以上是关于OpenCV金字塔图像分辨率重建与融合的主要内容,如果未能解决你的问题,请参考以下文章
youcans 的 OpenCV 例程200篇188.基于拉普拉斯金字塔的图像融合
youcans 的 OpenCV 例程200篇189.基于掩模的拉普拉斯金字塔图像融合
PANet:基于金字塔注意力网络的图像超分辨率重建(Pytorch实现)
图像融合基于matlab高斯金字塔+拉普拉斯金字塔彩色水下图像融合含Matlab源码 1629期