OpenCV图像金字塔
图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。如下图所示。
常用的图像金字塔有高斯金字塔(Gaussian pyramid)和拉普拉斯金字塔(Laplacian pyramid)。高斯金字塔用来向下采样,而拉普拉斯金字塔用来从金字塔低层图像重建上层未采样图像。
高斯金字塔
下采样pyrDown
下采样,也叫做降采样,这个过程中是隔行隔列删去图像中的对应行和列,这样原图中那些精细的细节边缘等地方会变得锯齿状,产生失真,因此为了缩小之后的图像看起来自然,必须进行平滑。因此pyrDown函数在降采样之前要先对图像进行高斯模糊。此时采用的高斯核如下:
代码:
#include "stdafx.h"
#include <opencv2/opencv.hpp>
int main()
{
// 声明两个图像矩阵
cv::Mat img1, img2;
// 创建两个窗口
cv::namedWindow("image1", cv::WINDOW_AUTOSIZE);
cv::namedWindow("image2", cv::WINDOW_AUTOSIZE);
// 读取文件,并将原始图像显示在image1窗口
img1 = cv::imread("test.jpg");
cv::imshow("image1", img1);
// 对原始图像进行下采样和高斯滤波处理,长宽各缩小一半,并显示在imge2窗口
cv::pyrDown(img1, img2);
cv::imshow("image2", img2);
// 等待键盘事件
cv::waitKey(0);
// 关闭所有窗口,并释放关联内存
cv::destroyAllWindows();
return 0;
}
运行结果:
上采样pyrUp
上采样过程首先是将图像在每个方向上扩大为原来的两倍,新增的行和列都以0填充,然后使用下采样时用的高斯核乘以四与放大后的图像进行卷积,获得“新增像素”的近似值。因此处理后的图像尺寸变大,但是分辨率不变。
代码:
#include "stdafx.h"
#include <opencv2/opencv.hpp>
int main()
{
// 声明两个图像矩阵
cv::Mat img1, img2;
// 创建两个窗口
cv::namedWindow("image1", cv::WINDOW_AUTOSIZE);
cv::namedWindow("image2", cv::WINDOW_AUTOSIZE);
// 读取文件,并将原始图像显示在image1窗口
img1 = cv::imread("test.jpg");
cv::imshow("image1", img1);
// 对原始图像进行下采样和高斯滤波处理,长宽各放大一半,并显示在imge2窗口
cv::pyrUp(img1, img2);
cv::imshow("image2", img2);
// 等待键盘事件
cv::waitKey(0);
// 关闭所有窗口,并释放关联内存
cv::destroyAllWindows();
return 0;
}
运行结果:
拉普拉斯金字塔
拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:
式中: 代表第i层高斯图像;
代表第i+1层高斯图像;
代表上采样;
代表卷积运算符;
代表5 × 5的卷积内核。
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0,经常被用在图像压缩中。
代码:
#include "stdafx.h"
#include <opencv2/opencv.hpp>
int main()
{
// 声明两个图像矩阵
cv::Mat img1, img2, img3;
// 创建两个窗口
cv::namedWindow("image1", cv::WINDOW_AUTOSIZE);
cv::namedWindow("image2", cv::WINDOW_AUTOSIZE);
// 读取文件,并将原始图像显示在image1窗口
img1 = cv::imread("test.jpg");
cv::imshow("image1", img1);
// 对原始图像进行下采样和高斯滤波处理,长宽各放大一半,并显示在imge2窗口
cv::pyrDown(img1, img2);
cv::pyrDown(img2, img3);
cv::pyrUp(img3, img3);
img3 = img2 - img3;
cv::imshow("image2", img3);
// 等待键盘事件
cv::waitKey(0);
// 关闭所有窗口,并释放关联内存
cv::destroyAllWindows();
return 0;
}
运行结果:
金字塔图像融合
分析:
① 首先通过图1建立高斯金字塔;
② 然后通过得到的高斯金字塔生成拉普拉斯金字塔。以图1、图2和图4为例:图4是公式中的,图1是公式中的,图2是公式中的,则图4是由图1减去图2向上采样并高斯模糊的结果得到的。
③ 因为拉普拉斯图像是用来从金字塔低层图像重建上层未采样图像的,所以可以通过将其与上一层的上采样的结果相加来重建原图。以图4、图5和图6为例:图6=图4+pyrUp(图5)。
注:重建原图金字塔的塔顶和高斯金字塔的塔顶是一样的。
代码:
注:这里选取的图片最好是大小相同,且行数和列数是能除尽2的6次方的值,否则上采样后的行数和列数可能和原来的相差1,需再进行处理。
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
// 声明两个图像矩阵
cv::Mat img1, img2;
// 读取图片
img1 = cv::imread("apple.jpg");
img2 = cv::imread("orange.jpg");
// 创建三个窗口
cv::namedWindow("img1", cv::WINDOW_NORMAL);
cv::namedWindow("img2", cv::WINDOW_NORMAL);
cv::namedWindow("img", cv::WINDOW_NORMAL);
// 用apple图像生成高斯金字塔,共7层
cv::Mat gp1[7];
cv::Mat gtmp1 = img1;
gp1[0] = gtmp1;
for (int i = 1; i < 7; i++) {
cv::pyrDown(gtmp1, gtmp1);
gp1[i] = gtmp1;
}
// 用orange图像生成高斯金字塔,共7层
cv::Mat gp2[7];
cv::Mat gtmp2 = img2;
gp2[0] = gtmp2;
for (int i = 1; i < 7; i++) {
cv::pyrDown(gtmp2, gtmp2);
gp2[i] = gtmp2;
}
// 用apple图像生成拉普拉斯金字塔,共6层
cv::Mat lp1[7];
cv::Mat ltmp1;
lp1[6] = gp1[6];
for (int i = 5; i >= 0; i--) {
cv::pyrUp(gp1[i+1], ltmp1);
cv::subtract(gp1[i], ltmp1, lp1[i]);
}
// 用orange图像生成拉普拉斯金字塔,共6层
cv::Mat lp2[7];
cv::Mat ltmp2;
lp2[6] = gp2[6];
for (int i = 5; i >= 0; i--) {
cv::pyrUp(gp2[i+1], ltmp2);
cv::subtract(gp2[i], ltmp2, lp2[i]);
}
// 将apple拉普拉斯金字塔的左半边和orang拉普拉斯金字塔的右半边拼接,生成融合后的拉普拉斯金字塔
cv::Mat LS[7];
for (int i = 0; i < 7; i++) {
cv::Size shape = lp1[i].size();
int width = shape.width;
// 将apple拉普拉斯图像赋给融合图像
LS[i] = lp1[i];
// 获取orange拉普拉斯图像的右半边取出
cv::Mat roi2 = lp2[i].colRange(width / 2, width);
// 将取出的半边图像复制到融合图像的右半边,实现图像融合
roi2.copyTo(LS[i].colRange(width/2, width));
}
// 重建原图
cv::Mat ls_ = LS[6];
for (int i = 5; i >= 0; i--)
{
cv::pyrUp(ls_, ls_);
std::cout << ls_.size() << std::endl;
std::cout << LS[i].size() << std::endl;
cv::add(ls_, LS[i], ls_);
}
// 显示原图和重建图像
cv::imshow("img1", img1);
cv::imshow("img2", img2);
cv::imshow("img", ls_);
// 等待键盘事件
cv::waitKey(0);
// 关闭窗口,并释放相关联的内存
cv::destroyAllWindows();
return 0;
}
运行结果:
上一篇: OpenCV图像金字塔
下一篇: OpenCV图像金字塔