31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列


本文作者:小嗷

微信公众号:aoxiaoji

吹比QQ群:736854977

微信链接:https://mp.weixin.qq.com/s?__biz=MzU1MTgxNjQyMg==&mid=2247483888&idx=1&sn=37e594296d95152ccc560d0670b21197&chksm=fb8adc79ccfd556f80688f90a56c56b85734d8a7b50de691ab57f004570df25a9b1f46c97445#rd


image
31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第1张图片
image
image

说白了,图像金字塔就是用来进行图像缩放的,干的事情跟resize函数没两样,那我们还需要学它吗?我觉得有必要的额,因为在学习卷积神经网络中会遇到这个名词,所以都学一学吧,搞图形都绕不过他!

说说什么是图像金字塔。

在本篇中,您将学习:

使用OpenCV函数pyrUp()pyrDown()对给定的图像进行下样或上样。

  • 通常我们需要将一个图像转换成与它原来的大小不同的图像。为此,有两种可能的选择:
  1. 扩大图像

  2. 缩小图像

  • 虽然OpenCV中有一个几何变换函数——字面上——调整图像大小(resize , 我们将在以后的篇章中展示),在这一节中,我们首先分析了图像金字塔的使用,它在大量的视觉应用中得到了广泛的应用。

本文你会找到以下问题的答案:

  1. pyrUp()

  2. pyrDown()


2.1 图像金字塔

图像金字塔是一个图像的集合,所有的图像都来自于一个原始的图像,它们被连续地向下采样,直到到达某个想要的停止点。

一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第2张图片
image

其实非常好理解,如上图所示,我们将一层层的图像比喻为金字塔,层级越高,则图像尺寸越小,分辨率越低。

有两种常见的图像金字塔:

  • 高斯金字塔:用于下采样图像

  • Laplacian金字塔:用金字塔较低的图像重建上采样的图像(分辨率较低)

在本篇中,我们将使用高斯金字塔。

2.2 高斯金字塔

忘了高斯函数请点击蓝色字体

  • 把金字塔想象成一层一层,层次越高,尺寸越小。
image.gif
  • 每个层都从下到上编号,因此层(i+1)(表示为Gi+1)比层i (Gi)小。

  • 为了在高斯金字塔中生成层(i+1),我们做以下工作:

    image.gif
  • 删除所有偶数行和列

  • 与高斯核的卷积(下图为高斯核):

您可以很容易地注意到,生成的图像的面积将恰好是其前身的四分之一。在输入图像G0(原始图像)上迭代此过程将生成整个金字塔。

如何理解生成的图像的面积将恰好是其前身的四分之一?(删除所有偶数行和列)

即:20/2=10,10/2=5

上面的过程对于降低图像的采样很有用。如果我们想让它变大呢?:填充0(0)的列

  • 首先,在每个维度上将图像放大到原来的两倍,并使用新的偶数行。

  • 与上面所示的相同内核执行卷积(乘以4)以近似“丢失像素”的值

这两个过程(如上所述的向下采样和向上采样)是由OpenCV函数pyrUp()和pyrDown()实现的,我们将在下面第4点的代码示例中看到:

注意:当我们缩小图像的尺寸时,我们实际上是在丢失图像的信息。

其实就是:N次循环【图像高斯完,删除所有偶数行和列,循环】

image

3.1 pyrUp()

把一个图像放大,然后模糊它。

1void cv::pyrUp  (   InputArray      src,2        OutputArray     dst,3        const Size &    dstsize = Size(),4        int     borderType = BORDER_DEFAULT 5    ) 

默认情况下,输出图像的大小被计算为size(src.cols2,src.rows2),但在任何情况下,应满足以下条件:

image

函数执行高斯金字塔结构的向上采样步骤,虽然它实际上可以用来构建拉普拉斯金字塔。

  • 首先,它通过注入零行和列对源映像进行向上采样,

  • 然后将结果与pyrDown中相同的内核相乘4进行卷积

参数:

  • src:输入图片.

  • dst:输出图片. 它具有指定的大小和与src相同的类型.

  • dstsize:输出图像的大小.

  • borderType:int类型的borderType边界模式

borderType的API网址:

https://docs.opencv.org/master/d2/de8/groupcorearray.html#ga209f2f4869e304c82d07739337eae7c5

上采样步骤:

将图像在每个方向放大为原来的两倍,新增的行和列用0填充; 使用先前同样的内核(乘以4)与放大后的图像卷积,获得新增像素的近似值。

3.2 pyrDown()

模糊图像并向下采样。

1void cv::pyrDown  ( InputArray  src,  2  OutputArray  dst,  3  const Size &  dstsize = Size(),  4  int  borderType = BORDER_DEFAULT  5 )  

默认情况下,输出图像的大小被计算为大小((src.cols+1)/2,(src.row+1)/2),但无论如何,应该满足以下条件:

image

如果width是偶数,那么必须dstsize.width是src.cols的2倍;

该函数执行高斯金字塔结构的下采样步骤。首先,它将源图像与内核进行卷积:

31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第3张图片
image

将所有偶数行和列去除.

下采样将步骤:

  1. 对图像进行高斯内核卷积

  2. 将所有偶数行和列去除

上、下采样都存在一个严重的问题,那就是图像变模糊了,因为缩放的过程中发生了信息丢失的问题。要解决这个问题,就得看拉普拉斯金字塔了(下篇在讲)。

image

本篇文章的代码如下所示。

1#include "iostream" 2#include "opencv2/imgproc.hpp" 3#include "opencv2/imgcodecs.hpp" 4#include "opencv2/highgui.hpp" 5 6using namespace std; 7using namespace cv; 8 9const char* window_name = "Pyramids Demo";1011int main(int argc, char** argv)12{13    cout << "\n Zoom In-Out demo \n "14        "------------------  \n"15        " * [i] -> Zoom in   \n"16        " * [o] -> Zoom out  \n"17        " * [ESC] -> Close program \n" << endl;1819    const char* filename = argc >= 2 ? argv[1] : "D://6.30pian.jpg";2021    // Loads an image22    Mat src = imread(filename);2324    // Check if image is loaded fine25    if (src.empty()) {26        printf(" Error opening image\n");27        printf(" Program Arguments: [image_name -- default ..D://6.30pian.jpg] \n");28        return -1;29    }3031    for (;;)32    {33        imshow(window_name, src);34        char c = (char)waitKey(0);3536        if (c == 27)37        {38            break;39        }40        else if (c == 'i')41        {42            pyrUp(src, src, Size(src.cols * 2, src.rows * 2));43            printf("** Zoom In: Image x 2 \n");44        }45        else if (c == 'o')46        {47            pyrDown(src, src, Size(src.cols / 2, src.rows / 2));48            printf("** Zoom Out: Image / 2 \n");49        }50    }5152    return 0;53}

源图:

31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第4张图片
image

效果图:(按i放大,o就缩小)

  • 放大
31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第5张图片
image
  • 缩小
31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第6张图片
image

解释一下:

让我们来看看这个项目的总体结构:

加载一个图像

1const char* filename = argc >=2 ? argv[1] : "D://6.30pian.jpg";2// Loads an image3Mat src = imread( filename );4// Check if image is loaded fine5if(src.empty()){6    printf(" Error opening image\n");7    printf(" Program Arguments: [image_name -- default D://6.30pian.jpg] \n");8    return -1;9}

创建窗体

imshow( window_name, src );

循环

 1for(;;) 2{ 3    imshow( window_name, src ); 4    char c = (char)waitKey(0); 5    if( c == 27 ) 6    { break; } 7    else if( c == 'i' ) 8    { pyrUp( src, src, Size( src.cols*2, src.rows*2 ) ); 9        printf( "** Zoom In: Image x 2 \n" );10    }11    else if( c == 'o' )12    { pyrDown( src, src, Size( src.cols/2, src.rows/2 ) );13        printf( "** Zoom Out: Image / 2 \n" );14    }15}

执行一个等待用户输入的无限循环。如果用户按ESC,程序将退出。此外,它还有两个选择:

  • 执行向上采样-放大(按i后)

  • 我们使用了函数pyrUp()的三个参数:

  • src:当前图像和目标图像(显示在屏幕上,应该是输入图像的两倍)

  • Size(tmp.cols2, tmp.rows2 ):目标大小。由于我们正在进行向上采样,所以pyrUp()期望大小比输入图像(在本例中是src)大一倍。

1        else if( c == 'i' )2        { pyrUp( src, src, Size( src.cols*2, src.rows*2 ) );3            printf( "** Zoom In: Image x 2 \n" );4        }
  • 执行向下采样-缩小(按'o')

  • 我们使用了函数pyrDown()的三个参数:

  • src:当前图像和目标图像(显示在屏幕上,大概是输入图像的一半)

  • Size(tmp.cols2, tmp.rows2 ):目标大小。由于我们正在进行向上采样,所以pyrUp()期望大小是输入图像的一半大小(在本例中为src)。

1        else if( c == 'o' )2        { pyrDown( src, src, Size( src.cols/2, src.rows/2 ) );3            printf( "** Zoom Out: Image / 2 \n" );4        }

小嗷提醒一下注意:

输入图像必须要可以除以二。否则,会报错。

(10/2,但是5/2。就会报错。当然,大家可以写一个判断是否是奇数)

image
  1. 本人是抱着玩一玩的心态,学习opencv(其实深度学习没有外界说的这么高深,小嗷是白板,而且有工作在身并且于代码无关)

  2. 大家可以把我的数学水平想象成初中水平,毕竟小嗷既不是代码靠吃饭又不是靠数学吃饭,毕业N年

  3. 写文章主要是为了后人少走点弯路,多交点朋友,一起学习

  4. 如果有好的图像识别群拉我进去QQ:631821577

  5. 就我一个白板,最后还是成的,你们别怕,慢慢来吧

31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列_第7张图片
image

分享可以无数次,转载成自己文章QQ邮箱通知一下,未经授权请勿转载。

邮箱:[email protected]

QQ群:736854977

有什么疑问公众号提问,下班或者周六日回答,ths

感言

嗷嗷嗷~~~,喜欢就推荐一下好友,下篇就拉普拉斯吧。

推荐文章:

18.图像处理之线性滤波(空间域/高低频/方框/均值/高斯) --- OpenCV从零开始到图像(人脸 + 物体)识别系列

20.方差/标准差/数学期望/正态分布/高斯函数(数学篇)--- OpenCV从零开始到图像(人脸 + 物体)识别系列

代码链接:

https://pan.baidu.com/s/1hwPOGQ_xCoYCDwGNOTwdOQ

密码: w6h9

你可能感兴趣的:(31.图像金字塔(pyrUp/pyrDown/高斯金字塔)--- OpenCV从零开始到图像(人脸 + 物体)识别系列)