图像金字塔及其在 OpenCV 中的应用范例(下)

前言

  本文将主要讲解如何使用 OpenCV 实现图像分割,这也是图像金字塔在 OpenCV 中的一个重要应用。

关于图像分割

  在计算机视觉领域,图像分割(Segmentation)指的是将数字图像细分为多个图像子区域(像素的集合)(也被称作超像素)的过程。图像分割的目的是简化或改变图像的表示形式,使得图像更容易理解和分析。[1]图像分割通常用于定位图像中的物体和边界(线,曲线等)。更精确的,图像分割是对图像中的每个像素加标签的一个过程,这一过程使得具有相同标签的像素具有某种共同视觉特性。

  图像分割的结果是图像上子区域的集合(这些子区域的全体覆盖了整个图像),或是从图像中提取的轮廓线的集合(例如边缘检测)。一个子区域中的每个像素在某种特性的度量下或是由计算得出的特性都是相似的,例如颜色、亮度、纹理。邻接区域在某种特性的度量下有很大的不同。 [1]

  ------ 维基百科

  以下是一位网友对图像分割技术的一个看法,也挺值得借鉴:

  从学术角度讲图像分割主要分成3大类,一是基于边缘的,二是基于区域的,三是基于纹理的。由于基于纹理的也可以看成是基于区域的,所以有些专家也把分割方法分成基于边缘和基于区域两大类。选择算法的时候主要参考你要分割的图像样本的特点。

  如果图像的边界特别分明,比如绿叶和红花,在边界处红绿明显不同,可以精确提取到边界,这时候用基于边缘的方法就可行。但如果是像医学图像一样,轮廓不是特别明显,比如心脏图像,左心房和左心室颜色比较接近,它们之间的隔膜仅仅是颜色比它们深一些,但是色彩上来说很接近,这时候用基于边缘的方法就不合适了,用基于区域的方法更好。再比如带纹理的图像,例如条纹衫,如果用基于边缘的方法很可能就把每一条纹都分割成一个物体,但实际上衣服是一个整体,这时候用基于纹理的方法就能把纹理相同或相似的区域分成一个整体。

  不过总体来说,基于区域的方法近些年更热一些,如Meanshift分割方法、测地线活动轮廓模型、JSEG等。

  ------ 某位网友

金字塔图像分割函数 - cvPyrSegmentation()

  实现原理步骤:

    1. 建立一个图像金字塔

    2. 在金字塔 Gi 层和 Gi+1层之间建立父子关系

    3. 由分辨率低的层次向分辨率高的层次逐层分割,优化。

  函数原型:

1 void cvPyrSegmentation(
2     IplImage* src,           // 输入图像
3     IplImage* dst,          // 输出图像
4     CvMemStorage* storage,     // 这个参数和下个参数用来管理关于分割结果的一些细致信息
5     CvSeq** comp,
6     int level,              // 金字塔等级
7     double threshold1,       // 建立连接的错误阈值 
8     double threshold2        // 分割簇的错误阈值
9 );

  参数特别说明:

    1. 输入图像的长和宽必须能够被 2 整除,并且能够被 2 整除的次数不少于金字塔总的层数。

    2. 关于参数 storage 和 comp,将在以后的文章中结合具体开发例子来介绍。

  参考示例代码:

 1 // 此头文件包含图像IO函数的声明
 2 #include "highgui.h"
 3 // 此头文件包含基本的图像处理函数和高级计算机视觉算法
 4 #include "cv.h"
 5 // 使用 cvPyrSegmentation 分割函数需要包含此头文件
 6 #include <opencv2/legacy/legacy.hpp>
 7 
 8 #include <iostream>
 9 using namespace std;
10 
11 // 分割图像
12 bool doPyrSegmentation( IplImage * src ,IplImage * dst)
13 {
14     // 检查处理图像大小是否符合规格 (规格的解释见下)
15     if (!(src->width%2 == 0 && src->height%2 == 0))
16         return false;
17 
18     // 定义分割参数
19     int level = 1;
20     double threshold1 = 150 ;
21     double threshold2 = 30 ;
22     CvMemStorage * stoage = cvCreateMemStorage(0) ;
23     CvSeq* comp=NULL;
24 
25     // 分割
26     cvPyrSegmentation(src,dst, stoage,&comp,level, threshold1,threshold2);
27 
28     return true;
29 };
30  
31 int main(int argc,char ** argv)
32 {
33     IplImage * src = cvLoadImage("d:\1.jpg");
34     
35     IplImage * dst= cvCreateImage(cvGetSize(src), src->depth,src->nChannels);
36 
37     if (!doPyrSegmentation(src,dst)) {
38         return EXIT_FAILURE;
39     }
40 
41     cvNamedWindow("分割前") ;
42     cvNamedWindow("分割后") ;
43     cvShowImage("分割前",src);
44     cvShowImage("分割后",dst);
45 
46     cvWaitKey(0) ;
47 
48     // 清理内存
49     cvDestroyAllWindows();
50 
51     return 0;
52 }

  运行结果:

    

小结

  本文具体讲述了用 OpenCV 进行图像分割的一个例子。至于如何获取分割的具体结果进行后续开发,则是以后讨论的内容。

原文地址:https://www.cnblogs.com/scut-fm/p/3949317.html