图像金字塔
这个也可以看做金字塔,如果我们把一个小方格当成一个二值图像的像素,那么我们可以从最底层变到最高层,也可以从最高层变到最底层。
那如果这是一个图像的话,从上往下,我们就实现了图像的放大,从下往上就实现了图像的缩小。
这就想金字塔一样,是四棱锥
一个图像金字塔就是一系列的图像组成。最下方是尺寸最大,最上方是尺寸最小。
为什么要使用图像金字塔
几何变换同样能放大缩小(双线性差值、双立方差值)。
我们要通过图像金字塔来产生一系列不同分辨率的图像,然后在不同的尺度空间来寻找图像对应的特征。因为我们不知道我们输入的图像是什么情况。
图像的金字塔变换会保证图像的特征一直存在
我们可以利用这样的四棱锥进行进行图像的缩放,我们将这个四棱锥称之为:图像金字塔
而图像的放大与缩小分别称之为上采样和降采样或下采样
上采样与降采样
上采样就是放大图像,通过放大图像,我们可以增加图像的像素,从而可以得到更高的分辨率。
降采样就是缩小图像,通过缩小图像,我们可以减少图像的像素,一方面,我们可以生成对应图像的缩略图,另一方面,我们可以减少图像的大小,节约内存。
但是我们通过上采样的得到的图,和经过缩小的图像的原图还是有区别的,因为我们很难真正获得图像的原始位置的像素,所以通过上采样得到的图,可能会看着不是那么清晰,那么流畅,图像质量不是那么的好。
上采样与降采样不仅能改变图像的清晰度(分辨率),也能改变图像的大小
接下来我们着重讲两个图像金字塔:高斯金字塔和拉普拉斯金字塔
高斯金字塔
高斯金字塔是从底向上,用于对图像进行降采样。
高斯金字塔对原图像删除偶数行与列,即得到降采样之后上一层的图片。所以经过一次高斯金字塔,图像的行列变为原来的1/2 。
具体的步骤分为两步:
1.进行高斯模糊
2.删除当前层的偶数行与列。
即可得到上一层的图像,这样上一层跟下一层相比,都只有它的1/4大小。
高斯不同
做了高斯金字塔后,要得到每层中的图像特征。我们就可以通过高斯不同或拉普拉斯不同。
把同一张图像在不同的参数下做高斯模糊之后的结果相减,得到的输出图像。称为高斯不同(Difference of Gaussian-DOG)。
高斯不同是图像的内在特征,在灰度图像增强、角点检测中经常用到。
拉普拉斯金字塔
拉普拉斯金字塔很高斯金字塔不同,是用其上层的图像,获得其下层的图像
- 我们可以通过高斯金字塔进行图像的降采样
- 可以使用拉普拉斯金字塔进行图像的上采样
图像的金字塔变换会保证图像的特征一直存在
相关API
示例
pyrUp(Mat src, Mat dst, Size(src.cols*2, src.rows*2))
//生成的图像是原图在宽与高各放大两倍
pyrDown(Mat src, Mat dst, Size(src.cols/2, src.rows/2))
//生成的图像是原图在宽与高各缩小1/2
上采样
void pyrUp(
InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT
);
(1)InputArray类型的src ,输入图像。
(2)OutputArray类型的dst ,输出图像,图像的大小是规定的(根据参数3)和输入图像有相同的类型。
(3)Size类型的指针dstsize ,设定的输出图像大小。
(4)int类型的borderType ,像素外推方法,请参见cv::BorderTypes(仅支持BORDER_DEFAULT)。
降采样
void pyrDown(
InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT
);
(1)InputArray类型的src ,输入图像。
(2)OutputArray类型的dst ,输出图像,图像的大小是规定的(根据参数3)和输入图像有相同的类型。
(3)Size类型的指针dstsize ,设定的输出图像大小。
(4)int类型的borderType ,像素外推方法,请参见cv::BorderTypes(仅支持BORDER_DEFAULT)。
上采样函数和降采样函数的图像一般在使用过程中,我们只设置前三个参数。
上采样与降采样代码实现
代码
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img, src;
img = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");
if (!img.data)
{
cout << "could not load image !;"
return -1;
}
imshow("show img", img);
pyrUp(img, src, Size(img.cols * 2, img.rows * 2));
imshow("output up image", src);
pyrDown(img, src, Size(img.cols / 2, img.rows / 2));
imshow("output down image", src);
waitKey(0);
return 0;
}
效果
先降采样再上采样代码实现
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img;
img = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");
if (!img.data)
{
cout << "could not load image !";
return -1;
}
imshow("show img", img);
pyrDown(img, img, Size(img.cols / 2, img.rows / 2));
pyrUp(img, img, Size(img.cols * 2, img.rows * 2));
imshow("output down image", img);
waitKey(0);
return 0;
}
结果比之前模糊,可以达到一个图像压缩的效果。
高斯不同代码实现
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src;
src = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("show img", src);
//dog
Mat gray, img1, img2, dogimg, dst;
cvtColor(src, gray, CV_BGR2GRAY);
GaussianBlur(gray, img1, Size(3,3),0,0);
GaussianBlur(img1, img2, Size(3,3),0,0);
subtract(img1, img2, dogimg, Mat());
imshow("DOG img", dogimg);
//将dog图像映射到0~255,否则像素值小,看不清
normalize(dogimg, dst, 255, 0, NORM_MINMAX);
//第五个参数的含义,找出原图最大最小值差值▲,将输入图像每个像素减去最小值除以▲再乘最大值
imshow("DOG img dst", dst);
waitKey(0);
return 0;
}