前言
在上一章中描述了如何进行形态学操作(开操作、闭操作、形态学梯度、顶帽及黑帽),详细描述可点击查看(https://www.jianshu.com/writer#/notebooks/47386368/notes/77896029)
目标
本章中,将学习:
- 图像金字塔概念
- 采样API
- 代码演示
图像金字塔概念
- 图像金字塔是图像中对尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
- 图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个中值条件才停止采样。
- 金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。
- 我们将一层一层的图像比喻成金字塔:层级越高,则图像越小,分辨率越低。
金字塔图像.png 0
一般情况下有两种类型的图像金字塔常常出现在文献和实际运用中。他们分别是: - 高斯金字塔(Gaussianpyramid):从底向上,逐层降采样得到,降采样之后图像大小是原图像的MxN的M/2 x N/2,就是对原图像删除偶数行与列,即得到降采样之后上一层的图片;
-
拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。
两者的简要区别:高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。
要从金字塔第i层生成第i+1层(我们表示第i+1层为G_i+1),我们先要用高斯核对G_1进行卷积,然后删除所有偶数行和偶数列。当然的是,新得到图像面积会变为源图像的四分之一。按上述过程对输入图像G_0执行操作就可产生出整个金字塔。
当图像向金字塔的上层移动时,尺寸和分辨率就降低。OpenCV中,从金字塔中上一级图像生成下一级图像的可以用PryDown。而通过PryUp将现有的图像在每个维度都放大两遍。 -
高斯不同(Difference of Gaussion-DOG):就是把同一张图像在不同的参数下做高斯模糊之后的结果相减,得到的输出图像。高斯不同是图像的内在特征,在灰度图像增强,角点检测中经常用到。
图像层级.png
相关API
-
上采样: void pyrUp( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );
函数作用:先对图像进行升采样(将图像尺寸行和列方向增大一倍),然后再进行高斯平滑;
函数说明:倒数第二个参数,在默认的情况下,这个尺寸大小是按照 Size(src.cols2, (src.rows2) 来计算的。如果你自己要指定大小,那么一定要满足下面的条件:|dstsize.width - src.cols * 2| ≤ (dstsize.width mod 2); //如果width是偶数,那么必须dstsize.width是src.cols的2倍;|dstsize.height - src.rows * 2| ≤ (dstsize.height mod 2);然后这个函数运行的过程就是先将图像的尺寸行和列方向都放大一倍,然后进行高斯平滑,不过此时高斯平滑的kernel是上面pyrDown()中的kernel乘上4,而不是完全相同。( 其实也很容易理解,行和列方向各放大一倍的结果就是图像的面积放大四倍,所以这里给之前的kernel乘以4)。 -
上采样: void pyrUp( InputArray src, OutputArray dst,const Size& dstsize = Size(), int borderType = BORDER_DEFAULT );
函数作用:先对图像进行高斯平滑,然后再进行降采样(将图像尺寸行和列方向缩减一半);
函数说明:倒数第二个参数,这个参数指的是降采样之后的目标图像的大小,我们可以看出它是有默认值的,如果我们调用函数的时候不指定第三个参数,那么这个值是按照 Size((src.cols+1)/2, (src.rows+1)/2) 计算的。而且不管你自己如何指定这个参数,一定必须保证满足以下关系式:
|dstsize.width * 2 - src.cols| ≤ 2;
|dstsize.height * 2 - src.rows| ≤ 2;
也就是说降采样的意思其实是把图像的尺寸缩减一半,行和列同时缩减一半。所以你指定的大小,无非就是多一行少一列的区别而已。在大多数情况下使用默认值就可了,因为这个函数不是缩减图像至任意尺寸,就只是缩减一半,所以没必要搞得那么复杂。
这个缩减的过程是这样的,隔行隔列删去图像中的对应行和列!由此我们也可以看出,这样缩减会带来的影响就是:原图中那些精细的细节边缘等地方,会因此变得锯齿状,产生失真,因此为了缩小之后图像看起来自然,必须进行平滑,这也就是这个算法为什么在降采样之前先对图像进行了高斯模糊的原因。
代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
// 1、加载图像,可以是BGR或者灰度图像
Mat src = imread("D:/浏览器下载/谷歌下载/lena512color.tiff");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char input_win[] = "input image";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
Mat dst;
char output_win[] = "pyrUp image";
namedWindow(output_win, WINDOW_AUTOSIZE);
// 上采样
pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
imshow(output_win, dst);
// 降采样
Mat downImg;
pyrDown(src, downImg, Size(src.cols / 2, src.rows / 2));
imshow("pyrDown image", downImg);
// DOG
Mat gray_src, g1, g2,dogimage;
cvtColor(src, gray_src, COLOR_BGR2GRAY); // 转换图像色彩空间
GaussianBlur(gray_src, g1, Size(5, 5), 0, 0); // 高斯模糊
GaussianBlur(g1, g2, Size(5, 5), 0, 0);
subtract(g1, g2, dogimage); // 图像相减值非常低,图像轮廓如果不做处理,不清晰
normalize(dogimage, dogimage, 255, 0, NORM_MINMAX); // 归一化显示,图像映射到0-255范围
imshow("DOG Image", dogimage);
waitKey(0);
return 0;
}
···
![采样效果.png](https://img.haomeiwen.com/i16412133/5893aab32d284185.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![高斯不同效果.png](https://img.haomeiwen.com/i16412133/f225f565bc58f4dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
网友评论