基于支持向量机的行人检测系统设计

11 题目的主要研究内容

(1)工作的主要描述

利用支持向量机算法,检测自然场景下的行人,并用方框圈出。具体工作步骤可分为:

  • 建立包含行人的一个图像数据集,作为正数据样本;
  • 建立不包含行人的一个图像数据集,作为负数据样本;
  • 在数据集上训练一个SVM;
  • 将SVM应用于每个可能的测试图像块,以确定整个图像是否包含一个行人,如果有行人,将行人用方框圈出。

(2)系统流程图

图1 系统流程图

12 题目研究的工作基础或实验条件

(1)硬件环境

一台笔记本

(2)软件环境

Anaconda+python3.9(opencv2matplotlibnumpy)

13 数据集描述

(1)正样本数据集

        正样本数据集,即包含行人的图像数据集,我们使用MIT People数据集,该数据集可以免费用于非商业用途。该数据集一共提供了924张包含行人的彩色图像,每张图像都缩放为64×128像素并对齐,这样人的身体就处在图像的中心位置了。这些图像是在波士顿和剑桥处在不同季节时以及各种光照情况下拍摄的,图片在颜色、纹理、视角(正面或者背面)以及背景等各不相同。

图2 正样本100-104幅图像

(2)负样本数据集

        负样本数据集,即不包含行人的图像数据集,我们使用麻省理工学院的计算视觉认知实验室的城市和自然场景数据集。该数据集收集了大量来自于开阔的乡村、内陆城市、山区,以及森林等类别的图像,所有的图像都是彩色的jpeg格式,大小为256×256像素。为了把他们用作与我们之前的行人图像相匹配的一个负样本,我们需要确保所有图像都有相同的像素,所以我们应该把该数据集中的所有图像剪切为大小64×128的感兴趣区域。

14 特征提取过程描述

        方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种图像特征描述符,HOG已经成功地应用于各种计算机视觉任务,对人进行分类特别合适。HOG特征的基本思想是,边缘方向的分布可以描述图像中物体的局部形状和外观。把图像拆分成小的连通区域,在这些区域内编译梯度方向(或者边缘方向)直方图。然后,描述符是通过连接不同的直方图组合而成的。为了提升性能,局部直方图还可以进行对比度归一化处理,从而对光照和阴影的变化具有更好的不变形。

        构建HOG模型的第一步就是计算图像的梯度。把图像分割成小的单元格(例如8像素×8像素),并针对每个单元格计算方向梯度直方图。方向的值会被分割成多个箱子。通常只考虑梯度的方向,不考虑正负(称作无符号梯度)。这里的方向值范围是0度~180度。采用9个箱子的直方图,方向值的分割间距为20度。每个单元格的梯度向量产生一个箱子,该箱子的权重对应梯度的幅值。然后把这些单元格组合成多个区块,每个区块包含固定数量的单元格。图像上的区块可以互相重叠(即可以共用一些单元格)。例如由2×2的单元格组成的一个区块,每个单元格都可以定义一个区块;也就是说,区块的步长为一个单元格,每个单元格属于两个区块。如果区块的步长是两个单元格,那么区块之间就不会重叠。每个区块包含特定数量的单元格直方图。这些直方图串联起来就构成了一个很长的向量。为了使模型具有可比性,要对向量做归一化处理。最后将所有区块的向量串联起来,组成一个非常大的向量(假设图像为64×64,每个单元格为8×8,每个区块为16×16,步长为1个单元格,共得到7个区块;最终得到向量的维度是49×36=1764),这个大向量就是图像的HOG模型。由此可见,图像HOG模型的向量的维度非常高。这个向量就代表了图像的特征,可用于各种物体图像的分类。

图3 特征提取流程图

15 分类过程描述

        在机器学习中,支持向量机(SVM)是与相关的学习算法有关的监督学习模型,主要用于分类和回归分析。例如在一个p维的空间中有两个由一系列的数据形成的数据集合,每个数据仅属于其中一个集合,为了确定新的数据点事属于哪一个集合,支持向量机会将将每一个数据都看成一个p维向量,然后通过计算分类,找出能够将两个数据集合分开的p-1维的超平面。所以支持向量机也叫做线性分类器。还有许多超平面,可能对数据进行分类。如果存在一个超平面使所有的数据不出错地分类,同时每类数据与超平面的距离最近的向量距离最大,那么这个超平面称之为最优超平面。

        通常SVM 算法关注的是在正样本和负样本数量相隔不大条件下的问题,但是当正样本和负样本数量相差很大时,直接使用SVM 算法,会导致降分类器的分类精度降低很多。针对这一问题,本文做的处理是,首先通过HOG特征提取足够的正负样本,通过大量HOG提取的样本并使用SVM进行分类,这样可以解决分类器处理精度,进而提高行人检测的精度。通过HOG特征提取的训练样本可以很好适应各种情况下检测和识别。

        其次,通过HOG特征提取的样本投入SVM分类器进行样本训练。通过将大量的正负样本进行训练,可以得到model,然后由此得到的model生成检测因子,接下来使用生成的检测因子去检测负样本,得到hardexample,最后提取hardexample中的hog特征,并与hog特征的负样本一起投入训练生成最终的检测因子。

16 主要程序代码(要求必须有注释)

1、获取正样本数据集

#数据存放在相对路径:../data/chapter6/pedestrians128x64.tar.gz`:

datadir = "../data/chapter6"

dataset = "pedestrians128x64"

datafile = "%s/%s.tar.gz" % (datadir, dataset)

#解压文件存放的相对目录:../data/pedestrians128x64/`:

extractdir = "%s/%s" % (datadir, dataset)

#将压缩文件解压

def extract_tar(datafile, extractdir):

    try:

        import tarfile

    except ImportError:

        raise ImportError("You do not have tarfile installed. "

                          "Try unzipping the file outside of Python.")

    tar = tarfile.open(datafile)

    tar.extractall(path=extractdir)

    tar.close()

    print("%s successfully extracted to %s" % (datafile, extractdir))

#调用函数

extract_tar(datafile, datadir)

import cv2

import matplotlib.pyplot as plt

%matplotlib inline

#显示第100-104张图片

plt.figure(figsize=(10, 6))

for i in range(5):

    filename = "%s/per0010%d.ppm" % (extractdir, i)

    img = cv2.imread(filename)

    plt.subplot(1, 5, i + 1)

    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

plt.axis('off')

2 HOG特征提取

#在opencv中,可以通过cv2.HOGDescriptor来访问HOG描述符,它接受一些输入参数,比如:

#检测窗口大小(待检测物体的最小尺寸48*96)、块的大小(每个框的大小,16*16)、单元格大小(8*8)以及单元格步长

win_size = (48, 96)

block_size = (16, 16)

block_stride = (8, 8)

cell_size = (8, 8)

num_bins = 9

hog = cv2.HOGDescriptor(win_size, block_size, block_stride, cell_size, num_bins)

##从900多个可用图片中随机选择400个图片,并对其应用HOG描述符

import numpy as np

import random

random.seed(42)

X_pos = []

for i in random.sample(range(1,900), 400):

    filename = "%s/per%05d.ppm" % (extractdir, i)

    img = cv2.imread(filename)

    if img is None:

        print('Could not find image %s' % filename)

        continue

X_pos.append(hog.compute(img, (64, 64)))

#OpenCV希望特征矩阵包含32位浮点数,目标标签是32位整数。

#转换为32位浮点类型,我们总共挑选了399个训练样本,每个样本都有1980个特征值(即HOG特征值)。

X_pos = np.array(X_pos, dtype=np.float32)

y_pos = np.ones(X_pos.shape[0], dtype=np.int32)

X_pos.shape, y_pos.shape

3、生成负样本数据集

negset = "pedestrians_neg"

negfile = "%s/%s.tar.gz" % (datadir, negset)

negdir = "%s/%s" % (datadir, negset)

extract_tar(negfile, datadir)

‘’’所有图像都是彩色的jpeg格式,大小为256 x 256像素。但是,为了把它们用作与我们之前的行人图像一起使用的负类的样本,我们需要确保所有图像具有相同的像素大小。而且,图像中所描绘物体的比例应该大致相同。因此,我们希望遍历目录中的所有图像(通过“os.listdir”),并剪切出大小为64 x 128的感兴趣区域。’’’

import os

hroi = 128

wroi = 64

X_neg = []

for negfile in os.listdir(negdir):

    filename = '%s/%s' % (negdir, negfile)

    img = cv2.imread(filename)

    img = cv2.resize(img, (512, 512))

    for j in range(5):

        rand_y = random.randint(0, img.shape[0] - hroi)

        rand_x = random.randint(0, img.shape[1] - wroi)

        roi = img[rand_y:rand_y + hroi, rand_x:rand_x + wroi, :]

        X_neg.append(hog.compute(roi, (64, 64)))

#所有的特征值转换32位浮点数

X_neg = np.array(X_neg, dtype=np.float32)

y_neg = -np.ones(X_neg.shape[0], dtype=np.int32)

X_neg.shape, y_neg.shape

#将所有的正样本和负样本连接到一个数据集中

X = np.concatenate((X_pos, X_neg))

y = np.concatenate((y_pos, y_neg))

#划分训练集和测试集

from sklearn import model_selection as ms

X_train, X_test, y_train, y_test = ms.train_test_split(

    X, y, test_size=0.2, random_state=42

)

4、实现SVM

#用opencv建立一个SVM,然后进行训练

def train_svm(X_train, y_train):

    svm = cv2.ml.SVM_create()

    svm.train(X_train, cv2.ml.ROW_SAMPLE, y_train)

return svm

#对函数进行评分,这里我们需要传递一个特征矩阵以及一个标签向量y。

def score_svm(svm, X, y):

    from sklearn import metrics

    _, y_pred = svm.predict(X)

return metrics.accuracy_score(y, y_pred)

svm = train_svm(X_train, y_train)

score_svm(svm, X_train, y_train)

score_svm(svm, X_test, y_test)

 5、Bootstrapping 模型

提升模型性能的一种有趣的方法是bootstrapping。在最早的一篇论文中,实际上是将这个思想应用于使用SVM和HOG特征相结合进行行人检测。在训练上进行SVM训练后,对模型评分,找到模型产生的一些假阳性。假阳性表示模型预测的一个样本为正(+),但实际上该样本却是一个负样本(-),这表示SVM错误地认为一张图像包含了一个行人。如果这刚好是数据集中的一个特定图像,那么这个例子显然很麻烦。因此,我们应该将其添加到训练集中,用增添的假阳性重新训练SVM,这样算法才可以学习正确地进行分类。重复这个过程,直到SVM给出满意的性能。

#对模型进行训练和评分

score_train = []

score_test = []

for j in range(3):

    svm = train_svm(X_train, y_train)

    score_train.append(score_svm(svm, X_train, y_train))

    score_test.append(score_svm(svm, X_test, y_test))

    #找出测试集中的假阳性。如果没有假阳性,那么我们的工作就完成了

    _, y_pred = svm.predict(X_test)

    false_pos = np.logical_and((y_test.ravel() == -1), (y_pred.ravel() == 1))

    if not np.any(false_pos):

        print('done')

        break

    #把假阳性添加到训练集中,然后重复这个过程

    X_train = np.concatenate((X_train, X_test[false_pos, :]), axis=0)

y_train = np.concatenate((y_train, y_test[false_pos]), axis=0)

score_train

#第一轮实现了66.15的准确率,第二轮便能实现100%的准确率

score_test

6、检测更大图像中的行人

剩下要做的就是把SVM分类过程和检测过程连接起来。实现这个过程的方法是对图像中每个可能的块进行重复分类。这与可视化决策边界时的做法类似,我们创建一个精细的网格,并分类网格上的每个点。同样的思路在这里也适用,我们把图像分成块,再把每个块分类为包含行人和不包含行人的。

img_test = cv2.imread('../data/chapter6/pedestrian_test.jpg')

#循环遍历一张图像中的所有可能的块,每次通过少量stride像素移动感兴趣区域

stride = 16

found = []

for ystart in np.arange(0, img_test.shape[0], stride):

    for xstart in np.arange(0, img_test.shape[1], stride):

        #确保不会超出图像的边界

        if ystart + hroi > img_test.shape[0]:

            continue

        if xstart + wroi > img_test.shape[1]:

            continue

        #裁剪出感兴趣区域,进行预处理,并进行分类

        roi = img_test[ystart:ystart + hroi, xstart:xstart + wroi, :]

        feat = np.array([hog.compute(roi, (64, 64))])

        _, ypred = svm.predict(feat)

        #如果特定的图像块刚好被分类为一个行人,那么我们就把这个图像块添加到成功的列表中。

        if np.allclose(ypred, 1):

            found.append((ystart, xstart, hroi, wroi))

#因为行人不但出现在不同的位置,而且大小也是不同的,我们必须重新调整图像大小并重#复整个过程,getDecisionFunction函数可以执行这个多尺度检测任务。我们把SVM的所#有参数都传递给hog对象。

hog = cv2.HOGDescriptor(win_size, block_size, block_stride, cell_size, num_bins)

rho, _, _ = svm.getDecisionFunction(0)

sv = svm.getSupportVectors()

#调用检测函数,该函数将返回一个边框列表,该边框中包含了检测到的行人。

hog.setSVMDetector(np.append(sv[0, :].ravel(), rho))

#预扫描SVM分类器

hogdef = cv2.HOGDescriptor()

hogdef.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

found, _ = hogdef.detectMultiScale(img_test)

#使用matplotlib绘制出测试图像

fig = plt.figure(figsize=(10, 6))

ax = fig.add_subplot(111)

ax.imshow(cv2.cvtColor(img_test, cv2.COLOR_BGR2RGB))

from matplotlib import patches

#通过遍历found中的边框可以标记检测到的图像中的行人

for f in found:

    ax.add_patch(patches.Rectangle((f[0], f[1]), f[2], f[3], color='y', linewidth=3, fill=False))

plt.savefig('detected.png')

17 运行结果及分析

运行结果:被测图片中行人被检测出,并框出。

图4 检测结果

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小蜗牛,大大梦想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值