在进行数字图像处理时,我们可能会需要将某种尺寸的图像转换为其他尺寸的图像,这样会存在放大图像核缩小图像两种可能。opencv提供了一个真正意义上的图像所方函数resize(),但在本篇中主要学习以下使用图像金字塔进行图像的所方,图像金字塔是视觉运用较为广泛的一项技术。
一个图像金字塔是一系列图像的集合,所有图像来源于同一张原始图像,通过梯次向下采样获得,直到达到某个终止条件才停止采样。通常有两种类型的图像金字塔
. 高斯金字塔(Gaussian pyramid): 用来向下采样
. 拉普拉斯金字塔(Laplacian pyramid): 用来从金字塔底层图像重建上层未采样图像,可以对图像进行最大程度的还原.
之所以称图像金字塔是因为激昂一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低,有如下两种形式:
1.高斯金字塔
高斯金字塔是图像处理、计算机视觉、信号处理上所使用的一项技术,高斯金字塔本质上为信号的多尺度表示法,亦即将同一信号或图片进行多次高斯模糊并且向下取样以产生不同尺度下的多组信号或图片进行后续的处理。如下图所示:
. 每一层都按从下到上的次序编号,层级(i+1)尺寸G(i+1)小于层级i的图像尺寸G(i)
. 高斯金字塔是用来向下采样,为了由第i层图像向下采样得到i+1层的图像,我们采用如下方法
(1)对图像进行高斯内核卷积,高斯内核为:
(2)将所有偶数行和列去除。
得到的图像即为第i+1层的图像,相较于第i层图像,其尺寸是第i层图像的1/2.通过对原图像不断的迭代就会得到整个金字塔,同时由第二步我们也可以看出向下采样会逐渐丢失图像的信息,达到缩小图像的目的。opencv提供了pyrDown函数来实现图像的向下采样,其原型为:
void cv::pyrDown (
InputArray src,
OutputArray dst,
const Size & dstsize = Size(),
int borderType = BORDER_DEFAULT
)
参数说明:
. InputArray src: 输入图像,可以是Mat类型
. OutputArray dst: 输出图像,尺寸由第三个参数指定,类型与输入图像一致
. const Size & dstsize=Size(): 输出图像的尺寸,有默认值Size(),在默认情况下将会由Size((src.cols+1)/2, (src.rows+1)/2)计算得到并且还要满足以下条件
|dstsize.width*2-src.cols|<=2
|dstsize.height*2-src.rows|<=2
. int borderType=BORDER_DEFAULT: 用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT
2.拉普拉斯金字塔
拉普拉斯金字塔是向上采样,重建上层未采样图像,在图像处理中预测残差。得到的图像比原来图像的尺寸大。向上采样如下:
(1)将图像在每个方向上扩大为原来的两倍,新增的行和列以0填充
(2)使用先前同样的内核(乘以4)与放大后的图像卷积,或得”新增像素”的近似值
得到的图像即为放大后的图像,但所与原来的图像相比会比较模糊,因为在向下采样过程中丢失了一些信息。opencv中提供了pyrUp()实现图像的向上采样,函数原型如下:
void cv::pyrUp ( InputArray src,
OutputArray dst,
const Size & dstsize = Size(),
int borderType = BORDER_DEFAULT
)
参数解释:
. InputArray src: 输入图像
. OutputArray dst: 输出图像
. const Size & dstsize=Size(): 输出图像尺寸,有默认值Size(),在使用默认值的情况下,输出图像的尺寸由Size((src.cols*2),(src.rows*2))计算得到,但是必须满足以下条件
|dstsize.width - src.cols*2|<=(dstsize.width mod 2)
|dstsize.height - src.rows*2|<=(dstsize.height mod 2)
其中mod时求余函数,即dstsize.width mod 2是dstsize.width除以2的余数。
. int borderType=BORDER_DEFAULT: 用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT,具体可以查看函数BorderTypes获取详细信息(需要注意的是与膨胀腐蚀不同,这里不支持BORDER_CONSTANT模式)
该函数与高斯金字塔有相同的步长,可以用来构建拉普拉斯金字塔。其核如下:
示例程序如下:
/*
*程序首先对加载的图像执行向下采样操作形成高斯金字塔
*之后再利用向下采样得到的图像进行向上采样形成拉普拉斯金字塔
*/
#include
#include
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat srcImage = imread("pyramid.jpg");
//判断图像是否加载成功
if(srcImage.empty())
{
cout << "图像加载失败!" << endl;
return -1;
}
else
cout << "图像加载成功!" << endl << endl;
namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", srcImage);
//两次向下采样操作分别输出
Mat pyrDownImage_1, pyrDownImage_2;
pyrDown(srcImage, pyrDownImage_1);
namedWindow("向下采样-1", WINDOW_AUTOSIZE);
imshow("向下采样-1", pyrDownImage_1);
pyrDown(pyrDownImage_1, pyrDownImage_2);
namedWindow("向下采样-2", WINDOW_AUTOSIZE);
imshow("向下采样-2", pyrDownImage_2);
//利用向下采样的结果进行向上采样操作
Mat pyrUpImage_1, pyrUpImage_2;
pyrUp(pyrDownImage_2, pyrUpImage_1);
namedWindow("向上采样-1", WINDOW_AUTOSIZE);
imshow("向上采样-1", pyrUpImage_1);
pyrUp(pyrUpImage_1, pyrUpImage_2);
namedWindow("向上采样-2", WINDOW_AUTOSIZE);
imshow("向上采样-2", pyrUpImage_2);
waitKey(0);
return 0;
}