目录
高斯金字塔reduce | void cv::pyrDown() |
expand | void cv::pyrUp() |
1.高斯金字塔
图像金字塔是对一张输入图像先模糊再下采样为原来的高、宽的1/2,不断重复模糊与下采样的过程就得到了不同分辨率的输出图像,叠加在一起就形成了图像金字塔。
高斯金字塔便是先进行高斯模糊,再进行reduce和expand操作。高斯金字塔中的较高级别(低分辨率)是通过删除较低级别(较高分辨率)图像中的连续行和列而形成的。然后,较高级别的每个像素由基础级别的5个像素的贡献与高斯权重形成。通过这样做,M×N图像变成M/2×N/2图像。因此面积减少到原始面积的四分之一。它称为Octave。
cv::pryDown()
C++ void cv::pyrDown(cv::InputArray src, cv::OutputArray dst,
const cv::Size &dstsize = cv::Size(), int borderType = 4)
cv::pryUp()
C++ void cv::pyrUp(cv::InputArray src, cv::OutputArray dst,
const cv::Size &dstsize = cv::Size(), int borderType = 4)
2.拉普拉斯金字塔
在高斯金字塔的运算过程中,图像经过卷积和下采样操作会丢失部分高频细节信息。为描述这些高频信息,人们定义了拉普拉斯金字塔(Laplacian Pyramid, LP)。用高斯金字塔的每一层图像减去其上一层图像上采样并高斯卷积之后的预测图像,得到一系列的差值图像即为 LP 分解图像。首先要进行金字塔的reduce操作,再expand操作,最后相减得到拉普拉斯金字塔。 L0=G0-expand(reduce(G0))
代码1:
#include<opencv2/opencv.hpp>
#include<iostream>
#include<imgproc.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat image = imread("C:/Users/YY/Pictures/Saved Pictures/1.jpg");
Mat out;
imshow("原图", image);
pyrDown(image, out);
imshow("降采样", out);
pyrUp(out, out);
imshow("上采样", out);
subtract(image, out, out);
imshow("拉普拉斯金字塔", out);
waitKey(0);
destroyAllWindows();
return 0;
}
3.重建融合
金字塔的一种应用是图像融合。例如,在图像拼接中,需要将两个图像堆叠在一起,但是由于图像之间的不连续性,可能看起来不太好。在这种情况下,使用金字塔混合图像可以无缝混合,而不会在图像中保留大量数据。
设定下采样次数为level。
1.分别对两幅图生成高斯金字塔图,融合最小分辨率的两个高斯金字塔图像,得到G。
2.生成拉普拉斯金字塔,并对每个分辨率都进行融合,得到 level个 LS。
3. 由 原图=LS[0]+expand(G1) 可知,由上面步骤得到最小的G不断进行该操作,最终生成高分辨融合的近似原图。
代码2:
#include<opencv2/opencv.hpp>
#include<iostream>
#include<imgproc.hpp>
using namespace cv;
using namespace std;
extern int level = 3;
//高斯金字塔
vector<Mat>GPyramid(Mat& image) {
vector<Mat>GP;
Mat src = image.clone();
GP.push_back(src);
Mat dst_g,dst_l;
for (int i = 0; i < level; i++) {
pyrDown(src, dst_g, Size(src.cols / 2, src.rows / 2));
dst_g.copyTo(src);
//高斯金字塔
GP.push_back(dst_g.clone());
}
return GP;
}
//拉普拉斯金字塔
vector<Mat>LPyramid(Mat& image) {
vector<Mat>LP;
Mat src = image.clone();
Mat dst_g, dst_l;
for (int i = 0; i < level; i++) {
pyrDown(src, dst_g, Size(src.cols / 2, src.rows / 2));
pyrUp(dst_g, dst_l, src.size());
subtract(src, dst_l, dst_l);
//拉普拉斯金字塔
LP.push_back(dst_l.clone());
src = dst_g.clone();
}
return LP;
}
//两张图片 左右拼接
Mat blend(Mat& a, Mat& b) {
int width = a.cols;
int height = a.rows;
Mat dst = Mat::zeros(a.size(), a.type());
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
Vec3b rgb;
if (col<width/2) {
rgb = a.at<Vec3b>(row, col);
}
else {
rgb = b.at<Vec3b>(row, col);
}
dst.at<Vec3b>(row, col)[0] = (int)rgb[0];
dst.at<Vec3b>(row, col)[1] = (int)rgb[1];
dst.at<Vec3b>(row, col)[2] = (int)rgb[2];
}
}
return dst;
}
int main(int argc, char** argv) {
Mat image1 = imread("C:/Users/YY/Pictures/Saved Pictures/5.jpg");
Mat image2 = imread("C:/Users/YY/Pictures/Saved Pictures/6.jpg");
resize(image2, image2, image1.size());
imshow("A", image1);
imshow("B", image2);
//高斯金字塔
vector<Mat> ga, gb;
ga = GPyramid(image1);
gb = GPyramid(image2);
//拉普拉斯金字塔
vector<Mat>la, lb;
la = LPyramid(image1);
lb = LPyramid(image2);
//ls不同分辨率进行拼接
vector<Mat>ls;
Mat dst;
for (int i = 0; i < level; i++) {
Mat a = la[i];
Mat b = lb[i];
dst=blend(a, b);
ls.push_back(dst);
}
//最小分辨率的高斯图像融合
dst = blend(ga[level], gb[level]);
imshow("最小分辨率的高斯图像融合", dst);
//重建原图
Mat temp;
for (int i = level - 1; i >= 0; i--) {
pyrUp(dst, temp,ls[i].size());
add(temp, ls[i], dst);
}
imshow("图片融合结果", dst);
waitKey(0);
destroyAllWindows();
return 0;
}