当我们开车时会经常关注环境,尤其关注那些潜在障碍物的位置,不管是汽车、行人还是道路上的物体。 同样,当我们开发自动驾驶车辆所需的智能和传感器时,最重要的一点是这些车辆能够检测到障碍物,因为它加强了车辆对环境的理解。 其中一种最重要的障碍物是道路上的其他车辆,因为它们很可能是我们车道或邻近道路上最大的物体,因此构成潜在的危险。
在众多的文献中,研究人员已经开发了许多用于障碍物检测的技术,从传统的计算机视觉技术到深度学习都有。 在本文中,我们使用一种传统的计算机视觉技术 — 方向梯度直方图(HOG
)并结合被称为支持向量机(SVM
)的机器学习算法来构建车辆检测器。
如果想马上学习Python和机器学习方面的知识,推荐你使用汇智网的Python机器学习。
数据集
我们使用的数据集概述如下:
- 车辆图像:〜9K
- 非车辆图像:〜9K
- 图像尺寸:64x64
该数据集来自GTI
车辆影像数据库和KITTI Vision Benchmark Suite
。 下面展示了数据集中的一些样本:
我们可以清楚地看到,数据集中包含了车辆和非车辆的图像。 非车辆图像往往是道路的其他元素,如沥青、道路标志或路面。 车辆和非车辆的区别非常明显。 大多数图像中车辆都位于图的中心,但可能有不同的朝向,这有助于机器学习模型的泛化,很好。 此外,数据集中的汽车类型、颜色和照明条件都是多种多样的。
分类特征的研究
方向梯度直方图(HOG)
自从Navneet Dalal
和Bill Triggs
在其论文《基于HOG的行人检测》中展示出令人印象深刻的结果后,将HOG
用于物体检测就流行开来。 Satya Mallick
在这篇文章中很好的解释了HOG
的原理和算法,对于那些希望深入理解HOG
的人来说值得一看。
我们首先针对HOG算法的以下参数,在RGB
图像上尝试不同的配置:
- 方向数(用
o
表示) - 每个单元的像素数(用
px / c
表示)
每个图像块的单元数最初固定为2
(用c / bk
表示) 。 下面的图片显示了在RGB
格式的车辆图像样本上获得的结果:
仅仅是基于肉眼的观察,如下的配置看起来似乎可以为车辆生成独特的梯度特征:
- 方向数:11
- 单元像素数:14
- 图像块单元数:2
现在让我们尝试下不同的图像块单元数量:
对于人眼来说,不同的单元数量配置所生成的特征,彼此间并没有显著的差异。 理想情况下,我们希望压缩特征空间以便更快地计算。 因此将一个图像块的单元数设定为3
。
颜色空间
现在我们需要找出最合适的颜色空间,因为看起来3
个RGB
通道的HOG
特征太相似了,看起来特征的变化范围还不够大。
我们尝试在多个颜色空间中生成以下输出:
对于某些颜色通道来说,很难解释所生成的HOG
特征。 有趣的是,YUV
、YCrCb
和LAB
这几个颜色空间中的第一个颜色通道似乎就足以捕捉我们正在寻找的梯度特征。 在另外两个颜色空间HSV
和HLS
中,HOG
在Value
和Lightness
通道捕捉到了车辆最重要的特征。
为了证实这个假设,让我们尝试在一个车辆的不同颜色空间的影像上计算HOG
:
在上面这样的光线黯淡的图像,我们可以观察到,携带最多亮度信息的通道HOG
的结果并不好。 因此,我们必须考虑所有的色彩通道以便捕捉尽可能多的特征。 最后,我们得到的参数配置如下:
- 使用
YCrCb
色彩空间的所有通道 HOG
方向数:11
- 每个单元的
HOG
像素数:14
- 每个图像块的
HOG
单元数:2
我们还将添加了颜色信息来强化特征集。 要做到这一点,我们只需要使用32
个bin
来生成所有颜色通道的直方图,如下所示:
def color_histogram(img, nbins=32, bins_range=(0, 256)):
"""
Returns the histograms of the color image across all channels, as a concatenanted feature vector
"""
# Compute the histogram of the color channels separately
channel1_hist = np.histogram(img[:,:,0], bins=nbins, range=bins_range)
channel2_hist = np.histogram(img[:,:,1], bins=nbins, range=bins_range)
channel3_hist = np.histogram(img[:,:,2], bins=nbins, range=bins_range)
# Concatenate the histograms into a single feature vector and return it
return np.concatenate((channel1_hist[0], channel2_hist[0], channel3_hist[0]))
分类器
分类器负责将指定的图像分类为车辆/非车辆。 为此目的,我们按以下步骤进行实现:
- 从数据集加载图像
- 从图像中提取特征
- 特征归一化
- 将数据拆分为训练集和测试集
- 使用适当的参数构建分类器
- 使用训练数据对分类器进行训练
正如上一节所讨论的,我们决定只保留一个特征:YCrCb
图像Y
通道上计算的HOG
特征向量。
我们随机地分割数据集,留下20%用于测试。 然后使用sklearn.preprocessing.StandardScaler
来归一化样本数据。
由于没有足够的时间来测试众多的分类器,我们主观选择了支持向量机 (SVM
),因为在物体检测的相关文献中,SVM
与HOG
是常见的组合。 而且,我们使用了rbf
核函数的SVC
,因为它精度最高,虽然要比LinearSVC
慢一些, 但是在一系列图像上的测试表明,使用rbf
核的SVC
,其物体检测能力要强得多。
我们使用GridSearchCV
函数获得了以下参数的理想值:核类型( linear
或rbf
), C
( 1,100,1000,1000 )和gamma
( auto,0.01,0.1,1 )之间 。 最佳的配置可以实现99%
以上的准确度,参数如下:
- kernel = rbf
- C = 100
- gamma = auto
滑动窗口检测
我们创建多个尺寸的滑动窗口,大小从64x64到256x256像素,然后使用分类器来识别这些窗口,并且只保留正向的预测。 我们在屏幕底部使用较大的滑动窗户,因为这一区域的车辆通常较大,而在屏幕上方则使用较小的滑动窗口。 在y
方向小于350
像素的区域(即图像上部)不进行车辆检测。 下图显示了单元的重叠设置为4
时的滑动窗口检测示例:
热图和阈值化
我们的分类器有时(不可避免地)会将非车辆区域错误地识别为车辆。 为了避免在视频上突出显示这些误报区域,我们可以利用滑动窗口中的冗余信息,计算某一区域被检测为车辆的次数。首先使用scipy.ndimage.measurements
的label函数来标记具有重叠窗口的对象。 然后通过物体最小边界框来提取每个标签的位置。我们只保留识别为车辆的次数超过特定阈值的区域。 根据实验,我们发现阈值4
就可以取得不错的结果。 下面的照片展示了热图和阈值的工作原理:
第一个小热图表示分类器的原始检测结果,而第二个小热图表示阈值区域,红色强度随着重叠窗口数量的增加而增加。 右侧的最后一张小图显示了分类器预测为车辆的所有窗口。 在这个例子中,我们实际上使用的是LinearSVC
,它比rbf
核的SVC
更容易得到错误的预测。
帧聚合
为了进一步强化我们的处理流水线,我们决定每隔n
帧平滑所有的检测窗口。 为此,我们缓存在( n-1)* f + 1
到n* f
之间所有检测到的窗口,其中n
是正标量,表示当前所在的帧分组。下面的类封装了检测到的物体:
class DetectedObject:
"""
The DetectedObject class encapsulates information about an object identified by our detector
"""
def __init__(self, bounding_box, img_patch, frame_nb):
self.bounding_box = bounding_box
self.img_patch = img_patch
self.frame_nb = frame_nb
self.centroid = (int((bounding_box[0][0] + bounding_box[1][0]) / 2), int((bounding_box[0][1] + bounding_box[1][1]) / 2))
self.similar_objects = []
...
每当组中的当前帧或下一帧中检测到一个新目标时,检查过去是否检测到类似的对象,如果是的话,我们追加那个类似的对象,从而增加这个对象在多个帧中的计数。 在帧n * f
处,我们只保留那些检测超过m
次的物体(及其边界框),从而在流水线中实现某种双重滤波。
在下面的gif中可以看到,当我们有一个覆盖两辆汽车的单个边界框和每个汽车都有自己的边界框之间有一秒钟的时间:帧聚合逻辑必须等待,直到两个窗口出现足够多的时间显示他们:
进一步改进
这是一个棘手的项目,特别是对于那些选择更传统的计算机视觉和机器学习方法而不是深度学习的人。 以下步骤非常耗时:
- 确定最合适的特征(
HOG
,图像颜色直方图等) - 探索
HOG
参数+色彩空间的最佳组合 - 使用网格搜索来找到最合适的分类器
下一步,可以采用更快的像R-CNN
或YOLO
架构的深度学习方法,因为这些方法现在是用于目标检测问题的最先进的解决方案,并且可以实时运行。 尽管如此,为了更好地理解传统的机器学习技术并帮助建立特征选择的直觉,这是一个有价值的练习。 而且,我震惊于像HOG
这样简单而有美感的技术,依然可以输出可靠的结果。
如果你喜欢这篇文章,记得关注我的头条号:新缸中之脑!
原文:Teaching Cars To See — Vehicle Detection Using Machine Learning And Computer Vision