本文总结了与行人检测相关的HOG+SVM。当然,还有车辆检测等等……这里以行人检测为例进行介绍:
HOG:梯度直方图,与Window size、Block size、Block滑动步长、Cell size和Bin size有关(一般是9,360度等于9个部分),目的是得到Window中所有滑动的直方图块的单元格的梯度,构成特征向量。Dimension: N = ((W–wb )/stride + 1)*((H-hb)/stride+1)*bins*n
,其中W是Window的宽度,H是Window的高度,wb和hb是block的宽度和高度,stride是block的滑动步长,bins是投影的block,n是块中包含的单元格的数量。
本文主要是基于OpenCV做一个HOG和SVM结合的过程,适合小白(知道HOG和SVM原理)学习,具体项目具体分析,中间还会提到一些项目的东西。
INRIA Person Dataset:这个数据库是目前使用最多的静态行人检测数据库,提供原始图片和对应的标注文件。训练集有614个正样本(包括2416个行人)和1218个负样本;测试集有288个正样本(包括1126个行人)和453个负样本。图中人体大部分为站立姿势,高度大于100像素,部分可能标注错误。图片主要来自GRAZ-01、个人照片和google,所以图片清晰度很高。一些训练或测试的图片在XP操作系统下看不清楚,但是用OpenCV可以正常读取和显示。
下载地址: ftp://ftp.inrialpes.fr/pub/lear/douze/data/INRIAPerson.tar
在项目中,如果想要得到更高的准确率,需要根据具体项目场景、行人的姿态、帧图像的大小、检测的目的等,构建自己的数据集。 ,或者您可以将自己的数据集添加到一些公共数据集合中进行训练。
1、提取数据集的HOG特征:样本很重要。需要根据项目的实际环境获取图像数据集。不要以为只拍几张照片就足够训练了。
2.训练正负样本得到模型
3.使用训练好的模型生成检测器
4. 使用检测器识别测试负样本集,找到识别错误的hard example:hard example是指在负样本(绝对没有人体)的原始图像上检测到行人时的所有检测,使用第一个训练好的分类器这些矩形框显然是误报。将这些误报矩形框保存为图片,并将它们添加到初始负样本集中。重新训练 SVM 可以显着减少误报。这种方法称为引导。bootstrap 方法首先使用一组初始负样本来训练一个模型,然后收集被这个初始模型错误分类的负样本,形成一组困难的负样本。用这组负样本训练一个新模型,这个过程可以重复很多次。
5. 从hard example中提取HOG特征,与第一步得到的特征一起训练模型。
6、鉴别:有两种鉴别方法。如果只使用线性核,则只需要 Hog 类自带的 setSVMDetector 和 detect(detectMultiScale)。如果使用 RBF,则需要使用 SVM 类预测。但是 predict 是判断“是与否”。如果要获取面积,请使用 Hog 类的 setSVMDetector 和检测(detectMultiScale)。
7.非极大值抑制优化重叠检测区域
import cv2
import numpy as np
import random
#Loading samples
def loadImageList(dirName, fileListPath):
imageList = [];
file = open(dirName + r'/' + fileListPath)
imageName = file.readline()
while imageName !='':
imageName = dirName + r'/' + imageName.split('/', 1)[1].strip('\n')
#print imageName
imageList.append(cv2.imread(imageName))
imageName = file.readline()
return imageList
#Get a positive sample, intercept the area of size (128,64) from (16, 16)
def getPosSample(imageList):
posList = []
for i in range(len(imageList)):
roi = imageList[i][16:16+128, 16:16+64]
posList.append(roi);
return posList
#Get a negative sample, randomly crop out 10 areas of size (128, 64) from pictures without pedestrians
def getNegSample(imageList):
negList = []
random.seed(1)
for i in range(len(imageList)):
for j in range(10):
y = int(random.random() * (len(imageList[i])-128))
x = int(random.random() * (len(imageList[i][0])-64))
negList.append(imageList[i][y:y + 128, x:x + 64])
return negList
#Calculate HOG features
def getHOGList(imageList):
HOGList = []
hog = cv2.HOGDescriptor()
for i in range(len(imageList)):
gray = cv2.cvtColor(imageList[i], cv2.COLOR_BGR2GRAY)
HOGList.append(hog.compute(gray))
return HOGList
#Get detector
def getHOGDetector(svm):
sv = svm.getSupportVectors()
rho, _, _ = svm.getDecisionFunction(0)
sv = np.transpose(sv)
return np.append(sv, [[-rho]], 0)
#Get Hard example
def getHardExamples(negImageList, svm):
hardNegList = []
hog = cv2.HOGDescriptor()
hog.setSVMDetector(getHOGDetector(svm))
for i in range(len(negImageList)):
rects, wei = hog.detectMultiScale(negImageList[i], winStride=(4, 4),padding=(8, 8), scale=1.05)
for (x,y,w,h) in rects:
hardExample = negImageList[i][y:y+h, x:x+w]
hardNegList.append(cv2.resize(hardExample,(64,128)))
return hardNegList
#Non-maximum suppression
def fastNonMaxSuppression(boxes, sc, overlapThresh):
# if there are no boxes, return an empty list
if len(boxes) == 0:
return []
# if the bounding boxes integers, convert them to floats --
# this is important since we'll be doing a bunch of divisions
if boxes.dtype.kind == "i":
boxes = boxes.astype("float")
# initialize the list of picked indexes
pick = []
# grab the coordinates of the bounding boxes
x1 = boxes[:, 0]
y1 = boxes[:, 1]
x2 = boxes[:, 2]
y2 = boxes[:, 3]
scores = sc
# compute the area of the bounding boxes and sort the bounding
# boxes by the score of the bounding box
area = (x2 - x1 + 1) * (y2 - y1 + 1)
idxs = np.argsort(scores)
# keep looping while some indexes still remain in the indexes
# list
while len(idxs) > 0:
# grab the last index in the indexes list and add the
# index value to the list of picked indexes
last = len(idxs) - 1
i = idxs[last]
pick.append(i)
# find the largest (x, y) coordinates for the start of
# the bounding box and the smallest (x, y) coordinates
# for the end of the bounding box
xx1 = np.maximum(x1[i], x1[idxs[:last]])
yy1 = np.maximum(y1[i], y1[idxs[:last]])
xx2 = np.minimum(x2[i], x2[idxs[:last]])
yy2 = np.minimum(y2[i], y2[idxs[:last]])
# compute the width and height of the bounding box
w = np.maximum(0, xx2 - xx1 + 1)
h = np.maximum(0, yy2 - yy1 + 1)
# compute the ratio of overlap
overlap = (w * h) / area[idxs[:last]]
idxs = np.delete(idxs, np.concatenate(([last],
np.where(overlap > overlapThresh)[0])))
# return only the bounding boxes that were picked using the
# integer data type
return boxes[pick]
#Main program
labels = []
posImageList = []
posList = []
posImageList = []
posList = []
hosList = []
tem = []
hardNegList = []
#Load pictures with pedestrians
posImageList = loadImageList(r"/home/ningshaohui/tfboy/INRIAPerson/train_64x128_H96", "pos.lst")
print ("posImageList:", len(posImageList))
#Crop the picture, get the positive sample
posList = getPosSample(posImageList)
print ("posList", len(posList))
#Get the HOG of the positive sample
hosList = getHOGList(posList)
print ("hosList", len(hosList))
#Add the label corresponding to all positive samples
[labels.append(+1) for _ in range(len(posList))]
#Load pictures without pedestrians
negImageList = loadImageList(r"/home/ningshaohui/tfboy/INRIAPerson/train_64x128_H96", "neg.lst")
print ("negImageList:", len(negImageList))
#Random crop to obtain negative samples
negList = getNegSample(negImageList)
print ("negList", len(negList))
#Get the negative sample HOG and add it to the overall HOG feature list
hosList.extend(getHOGList(negList))
print ("hosList", len(hosList))
#Add the label corresponding to all negative samples
[labels.append(-1) for _ in range(len(negList))]
print ("labels", len(labels))
####################So far, all the features and labels of SVM are obtained (excluding hard example)######################
#Create svm classifier, parameter settings
#################################################################
#-d degree:Degree setting in the kernel function (for polynomial kernel function) (default 3)
#-g r(gama):The gamma function setting in the kernel function (for polynomial/rbf/sigmoid kernel function) (default 1/k)
#-r coef0:Coef0 setting in the kernel function (for polynomial/sigmoid kernel function) ((default 0)
#-c cost:Set the parameters (loss function) of C-SVC, e-SVR and v-SVR (default 1)
#-n nu:Set the parameters of v-SVC, a type of SVM and v-SVR (default 0.5)
#-p p:Set the value of loss function p in e -SVR (default 0.1)
#-m cachesize:Set the cache memory size in MB (default 40)
#-e eps:Set the allowable termination criterion (default 0.001)
#-h shrinking:Whether to use heuristic, 0 or 1 (default 1)
#-wi weight:Set the type of parameter C to weight*C (C in C-SVC) (default 1)
#-v n: n-fold interactive test mode, n is the number of folds, which must be greater than or equal to 2
##################################################################################
svm = cv2.ml.SVM_create()
svm.setCoef0(0.0)
svm.setDegree(3)
criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 1000, 1e-3)#Termination condition
svm.setTermCriteria(criteria)
svm.setGamma(0)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setNu(0.5)
svm.setP(0.1) # for EPSILON_SVR, epsilon in loss function?
svm.setC(0.01) # From paper, soft classifier
svm.setType(cv2.ml.SVM_EPS_SVR) # C_SVC # EPSILON_SVR # may be also NU_SVR # do regression task
svm.train(np.array(hosList), cv2.ml.ROW_SAMPLE, np.array(labels))
#Acquire hard example based on initial training results
hardNegList = getHardExamples(negImageList, svm)
hosList.extend(getHOGList(hardNegList))
print ("hosList=====", len(hosList))
[labels.append(-1) for _ in range(len(hardNegList))]
####################So far, all the features and labels of SVM are obtained (including hard example)######################
####################Adding a hard example to the actual measurement can greatly improve the accuracy of the detection#########################
#Add hard example, retrain
svm.train(np.array(hosList), cv2.ml.ROW_SAMPLE, np.array(labels))
#Save model
hog = cv2.HOGDescriptor()
hog.setSVMDetector(getHOGDetector(svm))
hog.save('myHogDector.bin')
#Pedestrian detection
#hog.load('myHogDector.bin') #Because in the same file, there is no need to load the model
hog = cv2.HOGDescriptor()
hog.load('myHogDector.bin')
image = cv2.imread("1.jpg")
cv2.imshow("image", image)
cv2.waitKey(0)
rects, scores = hog.detectMultiScale(image, winStride=(4, 4),padding=(8, 8), scale=1.05)
#fastNonMaxSuppression-The first parameter
for i in range(len(rects)):
r = rects[i]
rects[i][2] = r[0] + r[2]
rects[i][3] = r[1] + r[3]
#fastNonMaxSuppression-Second parameter
sc = [score[0] for score in scores]
sc = np.array(sc)
pick = []
print('rects_len',len(rects))
pick = fastNonMaxSuppression(rects, sc, overlapThresh = 0.3)
print('pick_len = ',len(pick))
for (x, y, xx, yy) in pick:
print (x, y, xx, yy)
cv2.rectangle(image, (int(x), int(y)), (int(xx), int(yy)), (0, 0, 255), 2)
cv2.imshow('a', image)
cv2.waitKey(0)
官网: http://pascal.inrialpes.fr/data/human/
下载地址: ftp://ftp.inrialpes.fr/pub/lear/douze/data/INRIAPerson.tar
INRIA 数据集是一组有标记的站立或行走的人的图像,是 Navneet Dalal 在图像和视频中检测直立的行人的研究工作中收集的。该研究详见 Dalal 的博士毕业论文以及 Dalal 2005 20052005 年在 CVPR 上发表的一篇论文——“Histograms of Oriented Gradients for Human Detection”,也是在这篇论文中 Dalal 和 Triggs 提出了 HOG+SVM 行人检测算法。
INRIA 数据集中训练集有正样本 614 614614 张(包含 1237 12371237 个行人),负样本 1218 12181218 张;测试集有正样本 288 288288 张(包含 589 589589 个行人),负样本 453 453453 张。图片中人体大部分为站立姿势且高度大于 100 100100 个象素,部分标注可能不正确。图片主要来源于 GRAZ-01、个人照片及 google,因此图片的清晰度较高。
对于下载的文件(INRIAPerson.tar),由于用到了软连接,在 Windows 上直接解压会有问题,使用 WSL(Windows Subsystem for Linux) 可以解决,解压命令:
tar xvf INRIAPerson.tar
1
具体地,下载下来的 INRIA 数据集内有6个文件夹:
‘./Train’ 和 ‘./Test’ 文件夹分别对应于原始训练图像和测试图像。这两个文件夹的每个文件夹内都有三个子文件夹: /pos(正样本图像)、/neg(负样本图像)、/annotations(Pascal Challenge格式的正样本的注释文件)。
文件夹 ‘./train_64x128_H96’ 和 ‘./test_64x128_H96’ 对应于标准化(标准化的意思是图像有相同的分辨率)的数据集。两个文件夹中都有子文件夹:/pos、/neg。‘/pos’ 文件夹中的图像实际为根目录下 ‘/96X160H96’ 和 ‘/70X134H96’ 文件夹下的图片,是以人为中心左右镜像的标准化正训练或测试图像,使用的是软连接,‘/neg’ 文件夹也是如此,实际上是原始图像 ‘./Train/neg’ 和 ‘./Test/neg’ 中的图像。所以根目录下虽然有六个文件夹,但是实际上只有四个文件夹有图像。
数据集文件夹 Tree 目录及每个目录图像数目如下所示:
./INRIAPerson
/Train – 1832
/Test – 741
/train_64x128_H96
/pos – 2416
/neg – 1218
/test_64x128_H96
/pos – 1126
/neg – 453
————————————————
版权声明:本文为CSDN博主「Krone_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Krone_/article/details/103909470
免责声明: | |
1、 | 资源售价只是赞助,不代表代码或者素材本身价格。收取费用仅维持本站的日常运营所需。 |
2、 | 本站资源来自用户上传,仅供用户学习使用,不得用于商业或者非法用途,违反国家法律一切后果用户自负。用于商业用途,请购买正版授权合法使用。 |
3、 | 本站资源不保证其完整性和安全性,下载后自行检测安全,在使用过程中出现的任何问题均与本站无关,本站不承担任何技术及版权问题,不对任何资源负法律责任。 |
4、 | 如有损害你的权益,请联系275551777@qq.com及时删除。 |