手把手教你搭建目标检测器-附代码

翻译:刘威威

编辑:祝鑫泉

前 言

本文译自:[http://www.hackevolve.com/create-your-own-object-detector/](http://www.hackevolve.com/create-your-own-object-detector/ ) 手动搭建属于自己的目标检测器现在已经不是一个很难的事情,比较常见的方法有Haarcascades 和HOG+SVM,后者在精度上优于前者,此篇文章中,将详细介绍如何使用HOG+SVM搭建自己的检测器,实现效果如下:

理论上说本文的方法适合检测各种经过训练的目标,此篇文章将以检测钟表为例子,检测图像中标记的目标。

1

任务说明

为了端对端的训练一个目标检测器,检测需要检测的目标,在此是钟表,首先需要标注出图像中的钟表,其次是训练,所有需要做的是:

  1. 收集数据
  2. 标注图像中目标的位置
  3. 训练检测器
  4. 保存并测试模型

我们所建立的工程结构如下:

Object Detector
├── detector.py
├── gather_annotations.py
├── selectors/
├── train.py
└── test.py
  • selectors 包含 BoxSelector 函数类,用来标注(选择)目标区域
  • gather_annotations.py 允许我们使用选择器标注图像的脚本。
  • detector.py 此文件中包含ObjectDetector类,用来训练和检测目标。
  • train.py 用来训练目标检测器
  • test.py 测试检测器

2

收集图像

本文以检测钟表为例子,介绍如何检测各种物品,因此,本实验收集的都是钟表图像,部分训练图像如下:

3

标注数据

已经拥有了训练数据,接下来需要对数据做标注,所使用的是上文介绍的BoxSelector类,写在gather_annotations.py文件中,此文件中的函数负责标注并保存在硬盘上。

首先需要import几个必须的依赖,和设置几个必须的超参数。

import numpy as np
import cv2
import argparse
from imutils.paths import list_images
from selectors import BoxSelector
#parse arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d","--dataset",required=True,help="path to images dataset...")
ap.add_argument("-a","--annotations",required=True,help="path to save annotations...")
ap.add_argument("-i","--images",required=True,help="path to save images")
args = vars(ap.parse_args())
  • dataset 表示训练数据集的路径
  • annotations 表示保存标注到本地的路径
  • images 保存图像数据到本地的路径
#annotations and image paths
annotations = []
imPaths = []
#loop through each image and collect annotations
for imagePath in list_images(args["dataset"]):
    #load image and create a BoxSelector instance
    image = cv2.imread(imagePath)
    bs = BoxSelector(image,"Image")
    cv2.imshow("Image",image)
    cv2.waitKey(0)
    #order the points suitable for the Object detector
    pt1,pt2 = bs.roiPts
    (x,y,xb,yb) = [pt1[0],pt1[1],pt2[0],pt2[1]]
    annotations.append([int(x),int(y),int(xb),int(yb)])
    imPaths.append(imagePath)

首先,建立两个空的列表,用来存放annotation 和图像的路径,我们需要保存图像的路径,这样就可以按序号索引图像的标注,确保不会索引错。然后遍历整张图像,建立一个BoxSelector实例帮助我们使用鼠标选择区域,然后通过鼠标选择收集annotation 通过分类将annotation和 image path append到 annotations and imPaths 中 最终,收集到了annotations 和 imPaths 到numpy的数组中,并保存到本地。

4

创建目标检测器

关于HOG(http://www.learnopencv.com/histogram-of-oriented-gradients/)和SVM(https://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html),此部分不做介绍,鉴于直接使用HOG和SVM很麻烦,因此可以使用dlib 包,里面封装的有目标检测的API,实际的HOG+SVM可以拆解为下述步骤。 训练:

  • 创建一个HOG descriptor,其包含pixels per cell, cells per block 和orientations
  • 使用descriptor从标注好的区域提取特征
  • 以提取的HOG特征创建一个线性的SVM多分类器 测试:
  • 估计平均的widows size
  • 缩小或者放大图像到固定大小,然后建立image pyramid
  • 从每一个定位中提取HOG特征
  • 使用当前的HOG特征估计训练的SVM分类概率,如果超过设置的阈值,则区域中包含目标,否则不包含。 接下来,打开detector.py文件,开始撸代码:
import dlib
import cv2
class ObjectDetector(object):
    def __init__(self,options=None,loadPath=None):
        #create detector options
        self.options = options
        if self.options is None:
            self.options = dlib.simple_object_detector_training_options()
        #load the trained detector (for testing)
        if loadPath is not None:
            self._detector = dlib.simple_object_detector(loadPath)

此部分创建了一个ObjectDetector类,需要两个关键的参数:

  • option 目标检测器的options 用来控制HOG和SVM超参数
  • loadpath 用来从本地加载训练好的检测器

首先对于简单的样本检测器,使用默认的options ,通过使用dlib.simple_object_detector_training_options(), 里面已经包含了一些超参数,比如:window_size,num_threads等等, 可以帮助我们训练和拟合检测器,在测试过程中,可以直接加载训练好的检测器。

def _prepare_annotations(self,annotations):
        annots = []
        for (x,y,xb,yb) in annotations:
            annots.append([dlib.rectangle(left=long(x),top=long(y),right=long(xb),bottom=long(yb))])
        return annots
    def _prepare_images(self,imagePaths):
        images = []
        for imPath in imagePaths:
            image = cv2.imread(imPath)
            image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
            images.append(image)
        return images

然后,我们定义了两个_prepare_annotations 和 _prepare_images 用来处理数据到一个检测器适合处理的形式,和从imagePaths中加载图像并转化为RGB,因为使用CV2读到的数据是BGR形式的,需要转化为RGB形式。

然后就是创建一个fit 函数了,具有以下参数:

  • imagePaths 一个类型为unicode的numpy 的array,包含的是图像的路径
  • annotations 包含对应图像的annotations
  • visualize 标志位,是否可视化HOG提取的特征,默认是false
  • savepath 保存训练好模型的路径,默认是None
def fit(self, imagePaths, annotations, visualize=False, savePath=None):
        annotations = self._prepare_annotations(annotations)
        images = self._prepare_images(imagePaths)
        self._detector = dlib.train_simple_object_detector(images, annotations, self.options)
        #visualize HOG
        if visualize:
            win = dlib.image_window()
            win.set_image(self._detector)
            dlib.hit_enter_to_continue()
        #save detector to disk
        if savePath is not None:
            self._detector.save(savePath)

手下使用定义好的_prepare_annotations 和 _prepare_images准备annotations和images,然后使用images创建一个dlib.train_simple_object_detector的实例,然后处理HOG的可视化特征并保存在本地。

def predict(self,image):
        boxes = self._detector(image)
        preds = []
        for box in boxes:
            (x,y,xb,yb) = [box.left(),box.top(),box.right(),box.bottom()]
            preds.append((x,y,xb,yb))
        return preds
    def detect(self,image,annotate=None):
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
        preds = self.predict(image)
        for (x,y,xb,yb) in preds:
            image = cv2.cvtColor(image,cv2.COLOR_RGB2BGR)
            #draw and annotate on image
            cv2.rectangle(image,(x,y),(xb,yb),(0,0,255),2)
            if annotate is not None and type(annotate)==str:
                cv2.putText(image,annotate,(x+5,y-5),cv2.FONT_HERSHEY_SIMPLEX,1.0,(128,255,0),2)
        cv2.imshow("Detected",image)
        cv2.waitKey(0)

到目前为止,已经建立好了fit ,predict (以图像为输入,输出检测目标在图像中的位置)并且定义了detect (将图像转化为RGB并预测bounding box),接下来就是训练检测器了,首先创建train.py,填入如下代码:

from detector import ObjectDetector
import numpy as np
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("-a","--annotations",required=True,help="path to saved annotations...")
ap.add_argument("-i","--images",required=True,help="path to saved image paths...")
ap.add_argument("-d","--detector",default=None,help="path to save the trained detector...")
args = vars(ap.parse_args())
print "[INFO] loading annotations and images"
annots = np.load(args["annotations"])
imagePaths = np.load(args["images"])
detector = ObjectDetector()
print "[INFO] creating & saving object detector"
detector.fit(imagePaths,annots,visualize=True,savePath=args["detector"])

最后还有一个test.py脚本,用来测试我们的模型。

from detector import ObjectDetector
import numpy as np
import cv2
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("-d","--detector",required=True,help="path to trained detector to load...")
ap.add_argument("-i","--image",required=True,help="path to an image for object detection...")
ap.add_argument("-a","--annotate",default=None,help="text to annotate...")
args = vars(ap.parse_args())
detector = ObjectDetector(loadPath=args["detector"])
imagePath = args["image"]
image = cv2.imread(imagePath)
detector.detect(image,annotate=args["annotate"])

运行结果

开始跑代码了,首先,运行gather_annotations.py,选择图像中目标的区域 。

获得annotations和image后,开始运行train.py训练检测器

运行完之后,检测器就训练好了,我们可以可视化训练好的HOG特征,然后给定测试图像,运行test.py检测图像中的目标

现在,已经完成了工程的所有部分,完整代码请移步GitHub(https://github.com/saideeptalari/Object-Detector)

原文发布于微信公众号 - 目标检测和深度学习(The_leader_of_DL_CV)

原文发表时间:2018-04-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

Tensorflow:基于LSTM轻松生成各种古诗

RNN不像传统的神经网络-它们的输出输出是固定的,而RNN允许我们输入输出向量序列。RNN是为了对序列数据进行建模而产生的。 样本序列性:样本间存在顺序关系,...

4876
来自专栏梦里茶室

Google机器学习笔记(七)TF.Learn 手写文字识别

mnist问题 计算机视觉领域的Hello world 给定55000个图片,处理成28*28的二维矩阵,矩阵中每个值表示一个像素点的灰度,作为feature...

2999
来自专栏用户2442861的专栏

python pyplot accuracy cost曲线绘制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haluoluo211/article/d...

1103
来自专栏和蔼的张星的图像处理专栏

4. 经典卷积网络之AlexNet

原文:《ImageNet Classification with Deep Convolutional Neural Networks》 我没有读原文,这个已...

1562
来自专栏应兆康的专栏

“西瓜书”——第三章_线性模型(笔记)

线性模型形式简单、易于建模,许多功能更为强大的非线性模型可在线性模型的基础上通过引入层级结构或高维映射而得。 ? ? ? ? ?

41215
来自专栏数据结构与算法

概率论中几个入门公式

临时整理一下,以后会慢慢补 独立 独立:对于事件$A$和$B$,如果$P(AB)$=$P(A)P(B)$,那么称$A$和$B$是独立的。 所谓独立,即两事件的结...

2876
来自专栏YoungGy

MMD_6b_DecisionTree

overview ? construct 构建决策树的时候需要考虑以下问题: 什么时候停止 如果不停止,那么以什么变量的什么特征构建二叉树 如果停止,那么预测的...

2037
来自专栏云时之间

深度学习与神经网络:mnist数据集实现手写数字识别

对于mnist数据集,具体的一些介绍我这里就不搬运过来了,这里我直接说我们如何在TensorFlow上使用mnist数据集.

37311
来自专栏CreateAMind

DeepMind时间序列生成模型

使用vae推理;lstm 时间相关建模;external memory加强记忆;和神经图灵机 可微分计算机等进行比较。

1242
来自专栏量化投资与机器学习

深度学习Matlab工具箱代码注释之MnistTest.m

%%========================================================================= %...

2227

扫码关注云+社区