OpenCV——图像金字塔和边缘检测

图像金字塔

尺度调整

      顾名思义,即对源图像的尺寸进行放大或者缩小变换。在opencv里面可以用resize函数,将源图像精准地转化为指定尺寸的目标图像。要缩小图像,一般推荐使用CV_INETR_AREA(区域插值)来插值;若要放大图像,推荐使用CV_INTER_LINEAR(线性插值)。这个函数可以用来做简单的图像尺度变换。而下面要说的图像金字塔的用处很大,在特征检测中都是基础理论和技术;

Opencv里面的API介绍:

void resize(src,dst,size,int interpolation)
//src:源图像;dst:目标图像,
//size目标图像大小,可以是指定的尺寸或者放大缩小的比例
//指定插值方式,一般有四种插值方式可供选择,默认为线性插值法

图像金字塔(Image Pyramid)

       图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

常见两类图像金字塔

       高斯金字塔 ( Gaussian pyramid): 用来向下/降采样,主要的图像金字塔
       拉普拉斯金字塔(Laplacian pyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。                                                                                        


       两者的简要区别:高斯金字塔用来向下降采样图像,注意降采样其实是由金字塔底部向上采样,分辨率降低,它和我们理解的金字塔概念相反(注意);而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。

       要从金字塔第i层生成第i+1层(我们表示第i+1层为G_i+1),我们先要用高斯核对G_1进行卷积,然后删除所有偶数行和偶数列。新得到图像面积会变为源图像的四分之一。按上述过程对输入图像G_0执行操作就可产生出整个金字塔。

       当图像向金字塔的上层移动时,尺寸和分辨率就降低。OpenCV中,从金字塔中上一级图像生成下一级图像的可以用PryDown。而通过PryUp将现有的图像在每个维度都放大两遍。

图像金字塔中的向上和向下采样分别通过OpenCV函数 pyrUp 和 pyrDown 实现。概括起来就是:

对图像向上采样:pyrUp函数
对图像向下采样:pyrDown函数

       这里的向下与向上采样,是对图像的尺寸而言的(和金字塔的方向相反),向上就是图像尺寸加倍,向下就是图像尺寸减半。而如果我们按上图中演示的金字塔方向来理解,金字塔向上图像其实在缩小,这样刚好是反过来了。

       但需要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降采样的逆操作。这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行)以0填充。然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器)去估计“丢失”像素的近似值。PryDown( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。


高斯金字塔

      高斯金字塔是通过高斯平滑和亚采样获得一系列下采样图像,也就是说第K层高斯金字塔通过平滑、亚采样就可以获得K+1层高斯图像,高斯金字塔包含了一系列低通滤波器,其截至频率从上一层到下一层是以因子2逐渐增加,所以高斯金字塔可以跨越很大的频率范围。金字塔的图像如下:

另外,每一层都按从下到上的次序编号, 层级 G_i+1 (表示为 G_i+1尺寸小于第i层G_i)。

对图像的向下取样操作,即缩小图像。
为了获取层级为 G_i+1 的金字塔图像,方法步骤如下:

<1> 对图像G_i进行高斯内核卷积,进行高斯模糊;

<2> 将所有偶数行和列去除。

       得到的图像即为G_i+1的图像,显而易见,结果图像只有原图的四分之一。通过对输入图像G_i(原始图像)不停迭代以上步骤就会得到整个金字塔。同时我们也可以看到,向下取样会逐渐丢失图像的信息。以上就是对图像的向下取样操作,即缩小图像。

对图像的向上取样,即放大图像
方法步骤如下:

<1> 将图像在每个方向扩大为原来的两倍,新增的行和列以0填充

<2> 使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素”的近似值

       得到的图像即为放大后的图像,但是与原来的图像相比会发觉比较模糊,因为在缩放的过程中已经丢失了一些信息,如果想在缩小和放大整个过程中减少信息的丢失,这些数据形成了拉普拉斯金字塔。

拉普拉斯金字塔

拉普拉斯金字塔第i层的数学定义:

 

       式中的表示第i层的图像。而UP()操作是将源图像中位置为(x,y)的像素映射到目标图像的(2x+1,2y+1)位置,即在进行向上取样。符号表示卷积,为5x5的高斯内核。

pryUp,就是在进行上面这个式子的运算。因此,可以直接用OpenCV进行拉普拉斯运算:

 

将降采样之后的图像再进行上采样操作,然后与之前还没降采样的原图进行做差得到残差图!为还原图像做信息的准备!

也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的。保留的是残差!为图像还原做准备!

整个拉普拉斯金字塔运算过程可以通过下图来概括:

 

所以,我们可以将拉普拉斯金字塔理解为高斯金字塔的逆形式。

另外再提一点,关于图像金字塔非常重要的一个应用就是实现图像分割。图像分割的话,先要建立一个图像金字塔,然后在G_i和G_i+1的像素直接依照对应的关系,建立起”父与子“关系。而快速初始分割可以先在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。

注意:上采样和下采样是非线性处理,不可逆,有损的处理!
 

 下面是pyrDowm函数的应用:

#include 
#include
#include"opencv2/highgui/highgui.hpp"
#include
#include
#include
using namespace std;
using namespace cv;


int main(int argc, char** argv)
{
	Mat srcImage = imread("tahiti.jpg");

	Mat tmpImage, dstImage;
	tmpImage = srcImage;

	imshow("【原始图】", srcImage);

	pyrDown(tmpImage, dstImage, Size(tmpImage.cols / 2, tmpImage.rows / 2));


	imshow("【效果图】", dstImage);

	waitKey(0);
	return 0;
}


边缘检测

       边缘检测实际上就是对图像进行系统的梯度计算,包含了图像的噪声处理,非极大值抑制,双阈值检测等一系列图像处理方式,通过这些方式处理图像后得到图像的轮廓。这些方式在之前的博客都已经提到过i了,而Opencv提供了一个非常方便的函数进行边缘检测,它将高斯滤波,梯度大小及方向计算,非极大值抑制,双阈值检测等几个边缘检测常用函数全部集成为一个函数,使用者只需要给出两个阈值的大小即可。
   

Sobel算子

       Sobel算子是离散微分算子,用来计算图像灰度的近似梯度;Sobel算子功能集合高斯平滑和微分求导。

       下面是Sobel算子的演示示例:

#include
using namespace cv;
int main()
{
	Mat dstIamge, grad_x, grad_y, abs_grad_x, abs_grad_y;
	Mat srcIamge = imread("tahiti.jpg");
 
	imshow("原始图", srcIamge);
	cvtColor(srcIamge, srcIamge, COLOR_RGB2GRAY);
	//求 X方向梯度
	Sobel(srcIamge, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);//使用线性变换转换输入数组元素成8位无符号整型
	imshow("X方向Sobel", abs_grad_x);
 
	//求Y方向梯度
	Sobel(srcIamge, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("Y方向Sobel", abs_grad_y);
 
	//合并梯度(近似)
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0,dstIamge);
	imshow("整体方向Sobel", dstIamge);
 
	waitKey(0);
	return 0;
}

Laplance算子

       Laplance算子就是对图像求二阶导

       下面是一个示例:

#include 
#include 
#include 

using namespace cv;
int main(int argc, char** argv) {
    Mat src, dst;
    src = imread("tahiti.jpg");
    if (!src.data) {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "Laplance Result";
    imshow(INPUT_WIN, src);

    Mat gray_src, edge_image;
    GaussianBlur(src, dst, Size(3, 3), 0, 0);  //高斯平滑,高斯滤波
    cvtColor(dst, gray_src, COLOR_BGR2GRAY);
    imshow("gray", gray_src);

    Laplacian(gray_src, edge_image, CV_16S, 3);
    convertScaleAbs(edge_image, edge_image);

    imshow(OUTPUT_WIN, edge_image);



    waitKey(0);
    return 0;
}

应用Laplacian函数后:

 

Canny 算子

Canny 的目标是找到一个最优的边缘检测算法,让我们看一下最优边缘检测的三个主要评价标准:

1.低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。

2.高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。

3.最小响应: 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。

#include 
#include 
#include 

using namespace cv;
int main(int argc, char** argv) {
    Mat src, dst;
    src = imread("tahiti.jpg");
    if (!src.data) {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "Canny Result";
    imshow(INPUT_WIN, src);

    Mat gray_src, edge_image;
    GaussianBlur(src, dst, Size(3, 3), 0, 0);  //高斯平滑,高斯滤波
    cvtColor(dst, gray_src, COLOR_BGR2GRAY);
    imshow("gray", gray_src);

    Canny(gray_src, edge_image, CV_16S, 3);
    convertScaleAbs(edge_image, edge_image);

    imshow(OUTPUT_WIN, edge_image);



    waitKey(0);
    return 0;
}

 

你可能感兴趣的:(计算机视觉,opencv,计算机视觉,图像处理,c++)