阅读这篇文章,任何人只需要30分钟 1就能让你的摄像头识别出来一个比较固定形状的物品。试试吧。

一、介绍

参考学习项目 : hand_gesture

这个项目进行图片分类识别,使用的是对图片提取fhog特征,进行训练进一步进行分类的。(并不是cnn,所以没有用到卷积神经网络)

这个过程可以如下图 2

image.png

If you want to create object detectors then try the scan_fhog_pyramid tool first. It is quite easy to use and train and will, in many cases, give excellent results. If that doesn't give good results then try the more powerful convolutional neural network based detector. 3

Also note that dlib contains more powerful CNN based object detection tooling, which will usually run slower but produce much more general and accurate detectors. 4

dlib的官网也说明了,使用fhog特征进行分类就能得到不错的结果,如果对结果不满意,可以使用cnn模型进行训练,但是耗时也会更长。

二、相关名词

2.1 图像金字塔

同一个问题物体的尺寸会因为距离摄像头远近有不同的大小,机器同样能识别就是对原始图片进行不断的下采样,直至缩放小于扫描窗口的大小停止。

图像金字塔可以认为是下采样的一种策略,即给定一个采样因子N,每次都会对图片进行缩放N-1/N 比例的大小。这样的话,一张图片在下采样的过程中会生成很多有一定比例尺寸规律的图片,构成的金字塔状,如下图所示 5

image.png

N越大,每次缩放的尺寸越小,同样下采样到同一个扫描窗口大小,必然花费的时间更多,金字塔中产生图片也就越多,但是获得信息也就越多。

2.2 检测窗口

可以简单理解为这个扫描窗口就是一个固定大小的矩阵在图像上不停的滑动,然后根据模型判断此窗口的特征是否符合指定动作的特征(如点赞的手势特征)。而提取的特征使用fhog特征来表示的。6

2.3 fhog 特征

是对图片特征的一种数学化表示

方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功。7

如果想知道计算过程,可以参考这两篇文章

fhog 则是 Felzenszwalb 这位改良后的一个hog特征。

三、检测过程

3.1 模型导入

//1. 图片特征扫描器
typedef dlib::scan_fhog_pyramid<dlib::pyramid_down<N>> image_scanner_type;

//2. 图片位置检测器
dlib::object_detector<image_scanner_type> thumb,thumb_mobile;

//3. 图片位置检测器列表,为什么要一个列表,下面会说到
std::vector<dlib::object_detector<image_scanner_type> > my_detectors;

//4. 导入模型
dlib::deserialize(thumb_svm) >> thumb;
my_detectors.push_back(thumb);

第一行的第一个类 scan_fhog_pyramid 8 ,作用如名,提取图片fhog特征的扫描器。定义如下:

template <typename Pyramid_type, typename Feature_extractor_type =default_fhog_feature_extractor>
class scan_fhog_pyramid : noncopyable{...}

类模板本身要接收两个参数:

  • 第一个参数是 pyramid_down,下采样因子,这个前面已经说过了
  • 第二个参数是 Feature_extractor_type特征提取器,默认有一个赋值,就是指使用fhog特征,提取图像的特征。9

第二行的第二类object_detector 10,基于图像特征扫描器,用来检测图像中要检测物体(如点赞的大拇指)的位置。


第四行,deserialize 我们将我们训练好的模型解析出来。

3.2 检测

好了,开始检测吧。

dlib::cv_image<dlib::bgr_pixel> cimg(cvMat);//cv::Mat 转成dlib所需的图片格式
std::vector<dlib::rect_detection> &dets;//检测结果的列表,每个结果包含检测物体在图像中的位置
double detect_shreshold = -2;//检测的门限,越小越容易检测出
evaluate_detectors(my_detectors, cimg, dets, detect_shreshold);//

我们可以从OpenCV中获取cv::Mat,然后转成dlib需要图片格式 cv_image _image[imagemage]。

rect_detection 是用来盛放检测结果的容器,定义如下:

    struct rect_detection
    {
        double detection_confidence; //检测结果的置信度
        unsigned long weight_index; //如果有多个模型的话,当前结果是哪个模型序号
        rectangle rect;//检测结果的位置信息

        bool operator<(const rect_detection& item) const { return detection_confidence < item.detection_confidence; }
    };

看起来很简单,接着调用 evaluate_detectors 11 函数进行预测即可。

这个函数是可以运行多个检测器,而且这样做比单独使用多次这个函数要更快,因为他只会提取一次图像的fHog特征,然后每个检测器都会重用这个fhog特征

如果传入的 my_detectors有多个检测器的话,那检测结果就有可能是多个,即返回的dets有多个元素。这个时候,我们就可以通过判断多个结果的置信度来决定最终的结果是什么。 在这个过程中,我们可以人为的根据某些原因(比如检测结果的尺寸)来更相信其中的一个结果。

四、训练过程

训练过程也并不难。

4.1 采集数据

无论是从摄像头还是视频中采集都是可以,使用OpenCV可以很快的将一帧图片保存到本地。这里可以参考 Collection.cpp

4.2 标注数据

dlib本身提供了 selectROI函数,作用就是可以接管我们的鼠标事件,然后能够返回圈出来的图片的位置信息,最后就能根据圈出来的位置信息使用OpenCV的图片处理裁剪图片并保存到本地了。这里可以参考boundingBox

对这个图片的位置最终要生成一个xml文件,这个xml文件中记录了所有图片的名称,以及圈出来用机器识别的部分的位置信息(top,left,width,height),才能用于训练。这里可以看一下这里txt_to_xml.cpp

4.3 训练数据

可以看一下这篇文章dlib人脸识别代码解读。写的非常详细。

最后有一个使用训练好的检测器来测试测试集的函数是:

 test_object_detection_function(detector, images_test, face_boxes_test) 

这个函数返回三个值分别代表的意思是 precision, recall, and then average precision.12 即 精确率、召回率和平均精确率。

  • 召回率 = 把有点赞的识别成点赞数目 / (把有点赞的识别成点赞数目 + 把有点赞的识别成没有点赞的)
  • 精确率 = 把有点赞的识别成点赞数目 / (把有点赞的识别成点赞数目 + 把没有点赞的识别成点赞的数目)
  • 正确率 = (把有点赞的识别成点赞数目 + 把没有点赞的识别成没有点赞数目) / (检测样本总数)

13

因为我们测试集都是有点赞的数据,所以
这里的精确率为1
召回率和正确率的计算是一样的。当然是值越大,说明模型训练的越可以了。


最后,推荐我在查询资料过程中,包括写这篇文章过程中找到的一些比较好的文章,可以进一步阅读:


参考链接:

最后修改:2020 年 08 月 07 日
喜欢我的文章吗?
别忘了点赞或赞赏,让我知道创作的路上有你陪伴。