1. 尺度空间和图像金字塔
尺度空间是图像在不同尺度下的连续表示。其中最常见的是使用高斯核对图像进行卷积。高斯滤波可以平滑图像,从而消除图像中的细微细节。随着高斯滤波核尺度的增加,图像变得越来越平滑,直到只剩下最基本的特征。
图像金字塔是尺度空间的一种具体实现方式。它是由一系列不同分辨率的图像组成,这些图像以金字塔的形状排列如下图所示。
常见的图像金字塔有以下几种:
- 高斯金字塔(Gaussian Pyramid):高斯金字塔是通过对图像进行高斯滤波和下采样来构建的。高斯滤波可以平滑图像,下采样可以降低图像的分辨率。高斯金字塔具有尺度不变性,可以用于尺度不变的图像处理任务。
- DoG 金字塔 (Difference of Gaussians Pyramid):DoG 金字塔是通过对高斯金字塔相邻层 进行差分来构建的。DoG 金字塔可以捕捉图像的局部特征,可以用于目标检测和边缘检测等任务。
- 拉普拉斯金字塔 (Laplacian Pyramid):拉普拉斯金字塔是通过对高斯金字塔进行差分来构建的。拉普拉斯金字塔可以捕捉图像的边缘和细节信息,可以用于图像融合和特征提取等任务。
- SIFT 金字塔(Scale-Invariant Feature Transform Pyramid):SIFT 金字塔是通过对图像进行高斯滤波和 DoG 滤波来构建的。SIFT 金字塔具有尺度不变性和旋转不变性,可以用于图像匹配和目标识别等任务。
图像金字塔通常通过对图像进行下采样 或上采样来构建。下采样可以降低图像的分辨率,上采样可以提高图像的分辨率。
尺度空间和图像金字塔在计算机视觉和图像处理领域有着广泛的应用。尺度空间可以用于尺度不变的图像处理任务,例如图像匹配和目标检测。图像金字塔可以用于图像融合、图像配准和特征提取等任务。
2. 高斯金字塔
高斯金字塔 通过对图像进行高斯滤波和下采样获得一系列下采样图像。高斯金字塔的下采样是对高斯滤波后的图像进行,以降低图像的分辨率。下采样可以通过以下几种方式实现:
- 平均池化:对图像的每个局部区域进行平均操作,从而得到一个像素值。
- 最大池化:对图像的每个局部区域进行最大值操作,从而得到一个像素值。
- 双线性插值:通过对相邻像素进行插值来得到新的像素值。
高斯金字塔的构建过程如下:
- 将原图作为高斯金字塔的第 0 层图像
- 对高斯金字塔的第 i 层(i = 0,1,2...)图像进行高斯滤波
- 对高斯滤波后的图像进行亚采样,生成高斯金字塔的第 i+1 层图像
高斯金字塔的第 i 层图像的尺寸为:
<math xmlns="http://www.w3.org/1998/Math/MathML"> w i d t h i = w i d t h 0 2 i width_i = \frac{width_0}{2^i} </math>widthi=2iwidth0
<math xmlns="http://www.w3.org/1998/Math/MathML"> h e i g h t i = h e i g h t 0 2 i height_i = \frac{height_0}{2^i} </math>heighti=2iheight0
其中, <math xmlns="http://www.w3.org/1998/Math/MathML"> w i d t h 0 width_0 </math>width0 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> h e i g h t 0 height_0 </math>height0 是原始图像的宽度和高度。
- 重复前面两步,直到达到预定的金字塔层数。
下面的代码展示了上述步骤,通过 GaussianBlur()
实现高斯滤波,通过双线性插值实现下采样,最终完成构建高斯金字塔。
cpp
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 构建高斯金字塔
void buildGaussianPyramid(Mat& image, vector<Mat>& pyramid, int levels) {
Mat temp = image.clone();
pyramid.push_back(temp);
for (int i = 1; i < levels; i++) {
// 高斯滤波
Mat blurred;
GaussianBlur(temp, blurred, Size(5, 5), 0);
Mat downSampled(blurred.rows / 2, blurred.cols / 2, blurred.type());
resize(blurred, downSampled, downSampled.size(), 0, 0, INTER_LINEAR);
pyramid.push_back(downSampled);
temp = downSampled;
}
}
int main() {
Mat src = imread(".../lotus.jpg");
int numLevels = 4;
vector<Mat> pyramid;
buildGaussianPyramid2(src,pyramid,numLevels);
for (int i = 0; i < numLevels; i++) {
imshow("Gaussian Pyramid Level " + to_string(i), pyramid[i]);
}
waitKey(0);
return 0;
}
OpenCV 提供了 pyrDown()
函数来构建高斯金字塔,该函数先对图像进行高斯滤波然后对图像进行下采样。
cpp
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 构建高斯金字塔
void buildGaussianPyramid2(Mat& image, vector<Mat>& pyramid, int levels) {
Mat temp = image.clone();
pyramid.push_back(temp);
for (int i = 1; i < levels; i++) {
Mat downSampled;
pyrDown(temp, downSampled);
pyramid.push_back(downSampled);
temp = downSampled;
}
}
int main() {
Mat src = imread(".../lotus.jpg");
int numLevels = 4;
vector<Mat> pyramid;
buildGaussianPyramid2(src,pyramid,numLevels);
for (int i = 0; i < numLevels; i++) {
imshow("Gaussian Pyramid Level " + to_string(i), pyramid[i]);
}
waitKey(0);
return 0;
}
3. DoG 金字塔
在该系列的第十一篇文章中,曾经介绍过 DoG 算子。
DoG 金字塔(Difference of Gaussians Pyramid)是指通过对相邻尺度的高斯金字塔进行差分来构建的图像金字塔。DoG 金字塔可以捕捉图像的局部特征,例如边缘和角点,可以用于目标检测和边缘检测等任务。
DoG 金字塔的构建过程如下:
- 对原始图像进行高斯滤波,得到不同尺度的高斯金字塔。
- 对相邻尺度的高斯金字塔进行差分,得到 DoG 金字塔。
DoG 金字塔的第 i 层可以表示为:
scss
DoG(i) = G(i) - G(i-1)
- 确定极值点,对 DoG 金字塔进行极值点检测,找到图像的局部特征点。
DoG 金字塔的应用:
- 目标检测:它可以捕捉图像的局部特征,例如边缘和角点。
- 边缘检测:它可以捕捉图像的边缘信息。
4. 拉普拉斯金字塔
拉普拉斯金字塔它可以捕捉图像的边缘和细节信息,它也是基于高斯金字塔构建的,常用于图像融合和特征提取等任务。
拉普拉斯金字塔的构建步骤如下:
- 构建高斯金字塔。
- 对高斯金字塔进行差分,得到拉普拉斯金字塔。拉普拉斯金字塔的第 i 层可以表示为:
scss
Laplacian(i) = G(i) - Expand(G(i+1))
其中,G(i) 是高斯金字塔的第 i 层,Expand() 是图像的上采样操作。拉普拉斯金字塔捕捉了高斯金字塔连续层之间的细节差异,强调了原始图像中存在的边缘和高频分量。
不同类型的图像金字塔比较:
金字塔类型 | 特性 | 构建方式 | 应用 |
---|---|---|---|
高斯金字塔 | 提供图像的多尺度表示 | 高斯模糊和下采样 | 尺度不变性、图像压缩 |
DoG 金字塔 | 比较高斯金字塔的相邻级别,强调模糊差异并捕获角点和斑点等局部特征。 | 高斯金字塔中相邻层的差异 | 目标检测、边缘检测 |
拉普拉斯金字塔 | 关注不同尺度下图像中存在的所有边缘和细节。 | 通过获取高斯金字塔中相邻级别之间的差异来计算拉普拉斯金字塔,涉及对上一层的金字塔图像进行上采样。 | 图像融合、增强、纹理分析 |
下面的代码展示了如何基于高斯金字塔构建拉普拉斯金字塔:对第 i+1 层图像通过双线性插值实现上采样,然后用第 i 层金字塔的图像 - 刚才上采样的图像,得到第 i 层拉普拉斯金字塔的图像。
cpp
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 构建高斯金字塔
void buildGaussianPyramid(Mat& image, vector<Mat>& pyramid, int levels) {
Mat temp = image.clone();
pyramid.push_back(temp);
for (int i = 1; i < levels; i++) {
// 高斯滤波
Mat blurred;
GaussianBlur(temp, blurred, Size(5, 5), 0);
Mat downSampled(blurred.rows / 2, blurred.cols / 2, blurred.type());
resize(blurred, downSampled, downSampled.size(), 0, 0, INTER_LINEAR);
pyramid.push_back(downSampled);
temp = downSampled;
}
}
// 构建拉普拉斯金字塔
void buildLaplacianPyramid(vector<Mat>& pyramid,vector<Mat>& laplacianPyramid) {
for (int i = 0; i < pyramid.size()-1; i++) {
Mat upSampled(pyramid[i+1].rows * 2, pyramid[i+1].cols * 2, pyramid[i+1].type());
resize(pyramid[i+1], upSampled, upSampled.size(), 0, 0, INTER_LINEAR);
Mat lap;
subtract(pyramid[i], upSampled, lap);
laplacianPyramid.push_back(lap);
}
}
int main() {
Mat src = imread(".../lotus.jpg");
int numLevels = 4;
vector<Mat> pyramid;
buildGaussianPyramid(src,pyramid,numLevels);
vector<Mat> laplacianPyramid;
buildLaplacianPyramid(pyramid,laplacianPyramid);
for (int i = 0; i < laplacianPyramid.size(); i++) {
imshow("Laplacian Pyramid Level " + to_string(i), laplacianPyramid[i]);
}
waitKey(0);
return 0;
}
OpenCV 也提供了 pyrUp()
函数来构建拉普拉斯金字塔,该函数先对图像进行升采样(将图像尺寸行和列方向增大一倍),然后再进行高斯平滑。
pyrUp()
和pyrDown()
不是互逆的操作。
cpp
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 构建拉普拉斯金字塔
void buildLaplacianPyramid(Mat& image, vector<Mat>& laplacianPyramid, int levels) {
Mat temp = image.clone();
for (int i = 0; i < levels; i++) {
Mat downSampled,upSampled;
pyrDown(temp, downSampled);
pyrUp(downSampled,upSampled);
Mat lap;
subtract(temp, upSampled, lap);
laplacianPyramid.push_back(lap);
temp = downSampled;
}
}
int main() {
Mat src = imread(".../lotus.jpg");
vector<Mat> laplacianPyramid;
buildLaplacianPyramid(src,laplacianPyramid,3);
for (int i = 0; i < laplacianPyramid.size(); i++) {
imshow("Laplacian Pyramid Level " + to_string(i), laplacianPyramid[i]);
}
waitKey(0);
return 0;
}
5. 总结
图像金字塔是一种重要的图像处理技术,它具有尺度不变性、特征提取、图像融合、图像压缩和图像增强等多种用途。本文详细介绍了三种常见图像金字塔,它们的原理、应用场景以及构建方式。