参考转载:OpenCV 笔记(24):图像金字塔
志哥先读:
其实图像的尺度空间可以理解为 模拟人眼远近视觉效果的一种方式。这一理论主要基于人眼在观察不同距离的物体时,对物体细节和整体轮廓的感知能力会发生变化。具体来说,图像的尺度空间是指图像经过几个不同高斯核后形成的模糊图片的集合,这些图片模拟了人眼在不同距离观察物体时的视觉效果。
- 尺度:在图像处理中,尺度指的是图像内容的粗细程度,用于模拟观察者距离物体的远近程度。当观察者距离物体较远时,只能看到物体的大概轮廓;而当距离较近时,则能更清晰地看到物体的细节,如纹理、表面的粗糙度等。
- 尺度空间:因此,图像的尺度空间就是一幅图像在不同尺度(即不同模糊程度)下的表示集合。这些表示通过应用不同参数的高斯核进行高斯滤波得到,从而模拟了人眼在不同距离下对物体的感知。
反正记住一点,尺度不是指图像分辨率尺寸,是模拟人眼的观察距离。或者再用一个更容易理解的举例,就是模拟人类不同的近视眼度数!
0. 尺度空间和图像金字塔
尺度空间是图像在不同尺度下的连续表示。其中最常见的是使用高斯核对图像进行卷积。高斯滤波可以平滑图像,从而消除图像中的细微细节。随着高斯滤波核尺度的增加,图像变得越来越平滑,直到只剩下最基本的特征。
图像金字塔是尺度空间的一种具体实现方式。它是由一系列不同分辨率的图像组成,这些图像以金字塔的形状排列如下图所示。
常见的图像金字塔有以下几种:
-
高斯金字塔(Gaussian Pyramid):高斯金字塔是通过对图像进行高斯滤波和下采样来构建的。高斯滤波可以平滑图像,下采样可以降低图像的分辨率。高斯金字塔具有尺度不变性,可以用于尺度不变的图像处理任务。
-
DoG 金字塔(Difference of Gaussians Pyramid):DoG 金字塔是通过对高斯金字塔相邻层进行差分来构建的。DoG 金字塔可以捕捉图像的局部特征,可以用于目标检测和边缘检测等任务。
-
拉普拉斯金字塔(Laplacian Pyramid):拉普拉斯金字塔是通过对高斯金字塔进行差分来构建的。拉普拉斯金字塔可以捕捉图像的边缘和细节信息,可以用于图像融合和特征提取等任务。
-
SIFT 金字塔(Scale-Invariant Feature Transform Pyramid):SIFT 金字塔是通过对图像进行高斯滤波和 DoG 滤波来构建的。SIFT 金字塔具有尺度不变性和旋转不变性,可以用于图像匹配和目标识别等任务。
图像金字塔通常通过对图像进行下采样或上采样来构建。下采样可以降低图像的分辨率,上采样可以提高图像的分辨率。
尺度空间和图像金字塔在计算机视觉和图像处理领域有着广泛的应用。尺度空间可以用于尺度不变的图像处理任务,例如图像匹配和目标检测。图像金字塔可以用于图像融合、图像配准和特征提取等任务。
1. 高斯金字塔
高斯金字塔通过对图像进行高斯滤波和下采样获得一系列下采样图像。高斯金字塔的下采样是对高斯滤波后的图像进行,以降低图像的分辨率。下采样可以通过以下几种方式实现:
-
平均池化:对图像的每个局部区域进行平均操作,从而得到一个像素值。
-
最大池化:对图像的每个局部区域进行最大值操作,从而得到一个像素值。
-
双线性插值:通过对相邻像素进行插值来得到新的像素值。
高斯金字塔的构建过程如下:
-
将原图作为高斯金字塔的第 0 层图像
-
对高斯金字塔的第 i 层(i = 0,1,2...)图像进行高斯滤波
-
对高斯滤波后的图像进行亚采样,生成高斯金字塔的第 i+1 层图像
高斯金字塔的第 i 层图像的尺寸如下公式所示,其中width0 和 height0 是原始图像的宽度和高度:
#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;
}
}
OpenCV 提供了 pyrDown()
函数来构建高斯金字塔,该函数先对图像进行高斯滤波然后对图像进行下采样。
// 构建高斯金字塔
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;
}
}
2. DoG金字塔
DoG 金字塔(Difference of Gaussians Pyramid)是指通过对相邻空间尺度的高斯金字塔进行差分来构建的图像金字塔。DoG 金字塔可以捕捉图像的局部特征,例如边缘和角点,可以用于目标检测和边缘检测等任务。
DoG 金字塔的构建过程如下:
-
对原始图像进行高斯滤波,得到不同尺度的高斯金字塔。(注意不用进行缩放)
-
对相邻尺度的高斯金字塔进行差分,得到 DoG 金字塔。
-
确定极值点,对 DoG 金字塔进行极值点检测,找到图像的局部特征点。
DoG 金字塔的第 i 层可以表示为:
DoG(i) = G(i) - G(i-1)
DoG 金字塔的应用:
-
目标检测:它可以捕捉图像的局部特征,例如边缘和角点。
-
边缘检测:它可以捕捉图像的边缘信息。
3. 拉普拉斯金字塔
拉普拉斯金字塔它可以捕捉图像的边缘和细节信息,它也是基于高斯金字塔构建的,常用于图像融合和特征提取等任务。
拉普拉斯金字塔的构建步骤如下:
-
构建高斯金字塔。
-
对高斯金字塔进行差分,得到拉普拉斯金字塔。
拉普拉斯金字塔的第 i 层可以表示为:
Laplacian(i) = G(i) - Expand(G(i+1))
其中,G(i) 是高斯金字塔的第 i 层,Expand() 是图像的上采样操作。拉普拉斯金字塔捕捉了高斯金字塔连续层之间的细节差异,强调了原始图像中存在的边缘和高频分量。
下面的代码展示了如何基于高斯金字塔构建拉普拉斯金字塔:对第 i+1 层图像通过双线性插值实现上采样,然后用第 i 层金字塔的图像 - 刚才上采样的图像,得到第 i 层拉普拉斯金字塔的图像。
#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) {
// ... 参照上方内容 ...
}
// 构建拉普拉斯金字塔
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()
不是互逆的操作。
// 构建拉普拉斯金字塔
void buildLaplacianPyramid2(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;
}
}
总结
不同类型的图像金字塔比较: