opencv —— resize、pyrUp 和 pyrDown 图像金字塔(高斯金字塔、拉普拉斯金字塔)与尺寸缩放(向上采样、向下采样)
我们经常会将某种尺寸的图像转化为其他尺寸的图像,如果需要放大或者缩小图像的尺寸,在 OpenCV 中可以使用如下两种方法:
- resize 函数,最直接的方法。
- pyrUp 和 pyrDown 函数,即图像金字塔相关的两个函数,对图像进行向上采样和向下采样的操作。
pyrUp 和 pyrDown 其实和专门用于放大缩小图像尺寸的 resize 在功能上差不多,批着图像金字塔的皮,说白了还是对图像进行放大和缩小操作。
图像金字塔
- 一幅图像的金字塔是一系列以金字塔形状排列,分辨率逐渐降低且源于同一张原始图的图像集合。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。层级越高,图像越小,分辨率越低。
- 图像金字塔是图像中多尺度表达的一种,最初用于机器视觉和图像压缩,最主要功能用于图像分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
向上、向下采样
图像金字塔中的向上和向下采样分别通过 pyrUp 和 pyrDown 实现。这里的向上向下采样,是针对图像的尺寸而言的(和金字塔的方向相反),向上就是图像尺寸加倍,向下就是图像尺寸减半。但需要注意的是,pyrUp 和 pyrDown 不是互逆的。
- 对于 pyrUp,图像首先在每个维度上扩大为原来的两倍,新增的行和列(偶数行和列)以 0 填充。然后用指定的滤波器进行卷积(实际上是一个在每个维度上都扩大为原来两倍的过滤器)去估计”丢失“像素的近似值。
- 对于 pyrDown,我们先要用高斯核对图像进行卷积,然后删除所有偶数行和偶数列,新的到的图像面积就会变成源图像的四分之一。
高斯金字塔
高斯金字塔是通过高斯平滑和亚采样获得的一系列采样图像。
- 向下采样方法:① 对图像进行高斯内核卷积;② 将所有偶数行和列去除。
- 向上采样方法:① 将图像在每个方向上扩大为原来的两倍,新增的行和列以 0 填充;② 使用原先同样的内核(乘以 4)与放大后的图像卷积,获得”新增像素“的近似值。在缩放过程中已经丢失了一些信息,如果想在缩放过程中减少信息的丢失,就需要用到拉普拉斯金字塔。
拉普拉斯金字塔
拉普拉斯金字塔是通过源图像减去先缩小再放大的图像的一系列图像构成。
数学定义:Li = Gi — pryUp( Gi+1 ) g5×5
尺寸调整:resize 函数
此函数将源图像精确地转换为指定尺寸地目标图像。如果源图像中设置了 ROI(感兴趣区域),那么 resize() 函数就会对源图像地 ROI 区域进行调整尺寸操作,来输出到目标图像中。若目标图像中已经设置了 ROI 区域,不难理解 resize() 函数将会对源图像进行尺寸调整并填充到目标图像的 ROI 区域中去。
void resize(InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);
- src,输入图像,Mat 类对象即可。
- dst,输出图像,若其非零时,有着 dsize 的尺寸,或者由 src.size() 计算出来。
- dsize,输出图像的尺寸。如果它等于零,由如下公式进行计算:
dsize = Size ( round ( fx * src.cols ), round( fy * src.rows ) );
- fx,延水平轴的缩放系数,有默认值 0,且为 0 时,由下式进行计算:
fx = (double) dsize.width / src.cols
- fy,延垂直轴的缩放系数,有默认值 0,为 0 时,由下式进行计算:
fy = (double) dsize.height / src.rows
- interpolation,指定插值方式,默认为 INTER_LINEAR (线性插值)。插值就是根据已知数据点(条件),来预测未知数据点值得方法。在尺寸调整过程中,图像的大小可能发生改变。此时像素与像素之间的关系就不是一一对应关系,因此在尺寸调整过程中,可能会涉及到像素值的插值计算。可选插值方式如下:
- INTER_NEAREST(最近邻差值)
- INTER_LINEAR(线性插值,默认)
- INTER_AREA(区域插值,利用像素区域关系的重采样插值)
- INTER_CUBIC(三次样条插值,超过 4×4 像素邻域内的双三次插值)
- INTER_LANCZOS4(Lanczos 插值,超过 8×8 像素邻域的 Lanczos 插值)
若要缩小图像,一般情况下最好用 INTER_AREA 来插值;若要放大图像,一般情况下用 INTER_LINEAR。
代码示例:
#include <opencv.hpp>
using namespace cv;
int main() {
Mat src = imread("C:/Users/齐明洋/Desktop/证件照/7.jpg");
imshow("src", src);
//方法一
Mat dst1 = Mat(200, 300, CV_8UC3);
resize(src, dst1, dst1.size());
imshow("dst1", dst1);
//方法二
Mat dst2;
resize(src, dst2, Size(), 0.5, 0.5);
imshow("dst2", dst2);
waitKey(0);
}
效果演示:
向上采样:pyrUp 函数
pyrUp 函数的作用是向上采样并模糊一张图像,说白了就是放大一张图片。
void pyrUp(InputArray src, OutputArray dst, const Size& dstsize = Size(), int borderType = BORDER_DEFAULT);
- src,输入图像,即源图像,Mat 类的对象即可。
- dst,输出图像。
- dstsize,输出图像的大小,有默认值 Size(),默认情况下,由 Size(src.cols * 2, src.rows * 2) 来进行计算
- borderType,边界扩展的方式,一般不考虑,选择默认值。
向下采样:pyrDown 函数
pyrDown 函数的作用是向下采样并模糊一张图像,说白了就是缩小一张图片。
void pyrDown(InputArray src, OutputArray dst, const Size& dstsize = Size(), int borderType = BORDER_DEFAULT);
- src,输入图像,即源图像,Mat 类的对象即可。
- dst,输出图像。
- dstsize,输出图像的大小,有默认值 Size(),默认情况下,由 Size( (src.cols + 1) / 2, (src.rows + 1) / 2 ) 来进行计算
- borderType,边界扩展的方式,一般不考虑,选择默认值。
代码示例:
#include <opencv.hpp>
using namespace cv;
int main() {
Mat src = imread("C:/Users/齐明洋/Desktop/证件照/7.jpg");
imshow("src", src);
Mat up_img, down_img;
pyrUp(src, up_img);
pyrDown(src, down_img);
imshow("up_img", up_img);
imshow("down_img", down_img);
waitKey(0);
}
效果演示: