前言
- 需要下载安装OpenCV工具包的朋友,请前往 此处 ;
- 系统要求:Windows系统,LabVIEW>=2018,兼容32位和64位。
features2d 基本应用
OpenCV 的 features2d 模块的主要作用是提供特征检测和描述功能,广泛应用于计算机视觉领域中的图像特征提取、匹配,进而实现图像拼接、物体识别等任务。选板如下图。
1. 特征点提取
提取2D图像的特征点,可以使用 FAST 和 AGAST 这样单独的函数,分别代表 FastFeatureDetector 和 AgastFeatureDetector 的检测算法。但更多时候,我们会采用集成度更高的 Feature2D 类来实现。
Feature2D 是一个基类,根据不同的实现算法,衍生出一系列子类。
选板如下,子目录下的函数,是子类私有方法,外部的是共有方法。
下面 以 ORB (Oriented FAST and Rotated BRIEF)算法为例,实现一张图片的特征提取。
- 插入一个 Feature2D 的 create 方法,切换模式到 “ORB”,并对必要的参数进行初始化设置;
- 插入一个或多个 ORB 子类的私有方法 ORB_set,通过切换模式,设置不同的参数;
- 本次我们只提取特征点,不计算特征描述,所以插入一个 detect 方法;
- 读取图片,连接到 detect 作为被检测图像(ORB支持彩色图片输入,但有些子类只支持灰度图);
- 在 core 模块下,找到 KeyPoint >> vector_KeyPoint 选板,插入一个 new 并连接到上述 detect 的输入端;
(这相当于C++的 vector< KeyPoint > ,是长度不确定的 KeyPoint 序列,作为 detect 结果的容器) - 使用 features2d 模块下的 drawKeypoints 函数将结果可视化;
- 使用 core >> KeyPoint 选板下的 convert 方法,将 vector_KeyPoint 对象转化成 LabVIEW 数组,以便观察;
- 最后,调用各自的 delete 或 release 方法,释放所有对象。完整流程如下图:
- 如果需要同时获取特征点的 “描述”,就将 detect 替换成 detectAndCompute 方法;
- detectAndCompute 除了能返回关键点外,还能返回每一个关键点的描述子,组成 descriptors 矩阵;
- descriptors 的行数等于关键点的数量,每一行的数据作为一个关键点的描述子;
(ORB基于BRIEF-256,所以每一个描述子占32字节,即 descriptors 的列数是32) - descriptors 将作为特征点匹配的依据。
2. 特征点匹配
特征点匹配的任务,是找出两张图片中特征相似的关键点,并建立对应关系。
在OpenCV中,有3个类可以实现特征点匹配功能:DescriptorMatcher 和它的两个子类 BFMatcher、FlannBasedMatcher。此三类合并在工具包的同一个子目录下(因为函数都相同),如图:
下面 以 FlannBasedMatcher 为例,实现两张图片的特征点匹配。
- 插入一个 DescriptorMatcher 选板的 create 方法,切换模式到 “FlannBasedMatcher”;
- 按照上文的方法,使用 ORB 分别提取两张图片的 keypoints 和 descriptors;
- 插入一个 DescriptorMatcher 选板的 match 方法;
- 按照 match 的要求,将上述两组 descriptors 转换成 32F 类型,再连接到 match 的输入端;
- 在 core 模块下,找到 DMatch >> vector_DMatch 选板,插入一个 new 并连接到上述 match 的输入端;
(这相当于C++的 vector< DMatch > ,是长度不确定的 DMatch 序列,作为 match 结果的容器) - 使用 features2d 模块下的 drawMatches 函数将结果可视化;
- 最后,调用各自的 delete 或 release 方法,释放所有对象。完整流程如下图:
这两张图片,一张是上例的 “小猫和小狗” 合照,另一张是截取其中的小狗,并旋转90度。匹配效果如下图:
可以看出,大部分关键点匹配较好,但也存在一些误差。
为了消除一些误差,你可以遍历 vector_DMatch 中的每一个 DMatch,筛选其中匹配较好的(distance较小的)DMatch,组成一个新的 vector_DMatch,效果如下图。除此之外,还有很多优化方法,不一一列举了。
3. BOW 应用
BOW(Bag of Words),也就是常说的 “词袋”,是一种用于图像分类和对象识别的技术。
BOW 模型的基本思想是将图像中的局部特征描述符聚类成视觉单词,然后计算每个图像中这些视觉单词的出现频率,从而形成一个“词袋”来表示该图像。
OpenCV 的 features2d 模块下,有两个BOW类:BOWImgDescriptorExtractor 和 BOWKmeansTrainer。后者用于将多个图片特征聚类成 “词汇”;前者用于根据设定的 “词汇”,提取一张图片的 “词袋”。选板如图。
下面我们用 BOW 模型的思想,结合 Feature2D 和 ml(机器学习)模块,训练一个 “猫,狗” 二分类模型。
- 第1步:提取特征,聚成词汇
- 搜集猫和狗的图片(每张只能有一只猫或一只狗),越多越好;
- 插入一个 BOWKmeansTrainer 类的 new 方法,并设置必要的参数;
- 插入一个 Feature2D 类的 create 方法,并切换模式到 “SIFT”;
- 遍历每一张图片,使用 Feature2D 类的 detectAndCompute 方法,提取 descriptors;
- 每获取一张图片的 descriptors,都用 BOWKmeansTrainer 类的 add 方法将其添加到BOW模型中;
- 遍历添加完成后,调用一次 BOWKmeansTrainer 类的 cluster 方法,获取聚类成的词汇 vocabulary;
(vocabulary 中的每一行是一个 SIFT 特征子,由128个float数据组成,每行称为一个“单词”) - 将 vocabulary 保存到文件中以备用;
- 最后,调用各自的 delete 或 release 方法,释放所有对象。完整流程如下图:
参考范例:examples/Molitec/OpenCV/features2d/features2d_3(BOW_vocabulary).vi
- 第2步:根据词汇,计算词袋
- 插入一个 Feature2D 的 create 并切换到“SIFT”,插入一个 DescriptorMatcher 的 create 并切换到“BFMatcher”;
- 插入一个 BOWImgDescriptorExtractor 的 new,并将上述的 SIFT 和 BFMatcher 对象连到输入端;
- 插入一个 BOWImgDescriptorExtractor 的 setVocabulary,从文件中载入 vocabulary 到 Mat 并连入;
- 再次遍历图片,使用 Feature2D 的 detect 配合 BOWImgDescriptorExtractor 的 compute,计算每张图片的词袋;
(词袋是个行向量,每个数据依次代表 vocabulary 中每个“单词”在此图片中出现的频率) - 根据 “猫,狗” 类别,将每个词袋 push_back 到两个不同的 Mat 对象中,最后分别保存到两个文件中;
- 最后,调用各自的 delete 或 release 方法,释放所有对象。完整流程如下图:
参考范例:examples/Molitec/OpenCV/features2d/features2d_4(BOW_imgDescriptor).vi
- 第3步:用词袋训练分类模型
- 从文件中载入猫、狗的词袋数据到 Mat 对象;
- 采用 SVM 模型进行训练,词袋作为 Samples,猫、狗类别 Responses 分别用 1 和 -1 代表;
(SVM 是机器学习模块的内容,这里不再赘述,请参考 教程(12)) - 调用 save 保存 SVM 的训练模型到 xml 文件,以备后用;
- 完整流程如下。参考范例:examples/Molitec/OpenCV/features2d/features2d_5(BOW_SVM_train).vi
- 第4步:测试分类模型
- 调用 SVM 的 load 方法,载入之前训练好的模型;
- 准备几张新的猫、狗图片,用和当初相同的 vocabulary 来计算词袋;
- 将新图片的词袋作为 Samples,传入 SVM 的 predict 方法,运行得到 Responses;
- 完整流程如下。参考范例:examples/Molitec/OpenCV/features2d/features2d_6(BOW_SVM_predict).vi
总结
- 本系列博文作为LabVIEW工具包—OpenCV的教程,将以专栏的形式陆续发布和更新。
- 对工具包感兴趣的朋友,欢迎下载试用:秣厉科技 - LabVIEW工具包 - OpenCV
- 各位看官有什么想法、建议、吐槽、批评,或新奇的需求,也欢迎留言讨论。