训练样本分为正样本和负样本。正样本是指待检目标样本,例如车辆,行人,人脸等,负样本是指其它任意图片。所有的样本图片都被归一化为同样的尺寸大小,例如20×20,24×24或33×33。负样本可以来自于任意的图片,但这些图片不能包含目标特征。
进入路径为tools\temp\positive\rawdata的文件夹中,然后在里面放入含有正样本的图片。正样本数目要足够大,一般要是1000以上。
注:图片要用BMP格式,如果图片不是BMP格式的话,可以在文件夹中创建一个空的文本文件,在文本文件中输入ren *.jpg *.bmp,并将该文本文件改成.bat后缀的批处理文件,双击该批处理文件即可将文件夹中.JPG格式的图片批量转换成.BMP格式。
双击tools\temp\positive下的objectmarker.exe可执行文件,开始手动截取目标区域。
使用方法可见readme文件,每次截好一次都要按一次空格键保存区域,多目标的图片可以继续截图并按空格键保存,若这张图片截取完成则按下回车键可以跳到下一张图片。
这个截图的过程不能中断,不然就无法产生相应的文件了,所以在样本太多的情况下,可以先分组,大约100张图片放进rawdata文件夹中,这样子如果有什么意外的话,损失也就100张图的时间而已,最后只需要把几个文件的内容合成一个大文件,并且把所有相关的图片放进rawdata文件夹中,最终的效果是一样的。截图完成后会在路径tools\temp\positive下生成info.txt文件。
info.txt文件内容说明:
rawdata/1000986.BMP 1 0 1 127 93
① rawdata/1000986.BMP表示文件的相对路径;
② 第2位的1表示图片中截取的区域数量,此处仅包含一个目标;
③ 第3和第4位的0 1表示截取的矩形框的起点坐标;
④ 第5和第6位的127 93表示截取的矩形框的宽和高;
注:第2位的数字若为2,即截取的目标数量为2个,则后面相应的矩形框起点坐标和矩形框尺寸也应该有2个,否则会在之后生成正样本的描述文件时报如下错误:
info.txt(1) : parse errorDone. Created 0 samples
打开tools文件夹下的samples_creation.bat文件,可见到如下指令:
cd temp
createsamples.exe -info positive/info.txt -vec data/vector.vec -num 4346 -w 24 -h 24
rem positive/positive_bmp_list.txt - file containing list of positive bmp files along with the rectagle coordinates from objectmarker.exe
rem -vec data/vector.vec - file created by the createsamples tool
rem all the other paramteres are described in the literature (links in the how_to.txt)
pause
其中我们需要根据实际情况修改的参数是num、w和h。
运行samples_creation.bat文件后,会在tools\temp\data下面生成vector.vec文件,这个就是向量描述文件了。
进入路径为tools\temp\negative的文件夹中,然后在里面放入负样本图片。一般来说,负样本要比正样本数目多很多。为什么呢?因为负样本表示的是随机情况,只要有大量随机样本的情况下,才可以充分表示与正样本相反的情况,大约2-5倍。但也不能太多,不然的话花费的时间太长,分类效果可能反而不好,因为比例偏移太严重。
注:负样本图片也需要采用.BMP格式。
运行tools\temp\negative下的create_list.bat文件,可以自动生成描述文件。如果没有找到这个create_list.bat批处理文件,可以自行在该目录下创建一个.bat文件,添加内容dir /b *.BMP >infofile.txt,然后保存。
打开tools文件夹下的haarTraining.bat文件,首先对训练器进行配置。
训练过程会在tools\temp\data\cascade中产生相应级数的文件,训练花费的时间跟电脑配置和训练数据的大小有关。如果训练过程中断也没关系,再次启动训练可以继续训练下去的。
训练完成后,将temp\data\cascade下的N(这里N=18)个弱分类器文件夹拷贝到cascade2xml\data下,运行tools\cascade2xml下的convert.bat文件就可以生成.xml分类器文件了,默认在同级目录下生成output.xml。
如下是launch文件的内容:
haar_scaleFactor: 1.2
haar_minNeighbors: 2
haar_minSize: 20
haar_maxSize: 55
参数说明:
如下是vehicle_detector.py文件内容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import cv2
import numpy as np
from sensor_msgs.msg import Image, RegionOfInterest
from cv_bridge import CvBridge, CvBridgeError
class vehicleDetector:
def __init__(self):
# 创建cv_bridge
self.bridge = CvBridge()
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
video = rospy.get_param("~video_vehicle", "")
cascade_vehicle = rospy.get_param("~cascade_vehicle", "")
# 使用级联表初始化haar特征检测器
self.cascade_vehicle = cv2.CascadeClassifier(cascade_vehicle)
# 设置级联表的参数,优化目标识别,可以在launch文件中重新配置
self.haar_scaleFactor = rospy.get_param("~haar_scaleFactor", 1.2)
self.haar_minNeighbors = rospy.get_param("~haar_minNeighbors", 2)
self.haar_minSize = rospy.get_param("~haar_minSize", 40)
self.haar_maxSize = rospy.get_param("~haar_maxSize", 60)
self.color = (50, 255, 50)
cap = cv2.VideoCapture(video)
# 获取视频图像
while(cap.isOpened()):
ret, cv_image = cap.read()
cv_image_compressed = cv2.resize(cv_image, (1280,720))
frame = cv_image_compressed
if ret==True:
# 创建灰度图像
grey_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 创建平衡直方图,减少光线影响
grey_image = cv2.equalizeHist(grey_image)
vehicle_result = self.detect_vehicle(grey_image)
# 将识别到的车辆框出来
if len(vehicle_result)>0:
for vehicle in vehicle_result:
x, y, w, h = vehicle
cv2.rectangle(cv_image_compressed, (x, y), (x+w, y+h), self.color, 2)
cv2.imshow('frame',cv_image_compressed)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
else:
break
def detect_vehicle(self, input_image):
# 匹配车辆模型
if self.cascade_vehicle:
vehicles = self.cascade_vehicle.detectMultiScale(input_image,
self.haar_scaleFactor,
self.haar_minNeighbors,
cv2.CASCADE_SCALE_IMAGE,
(self.haar_minSize, self.haar_maxSize))
return vehicles
def cleanup(self):
print "Shutting down vision node."
cv2.destroyAllWindows()
if __name__ == '__main__':
try:
# 初始化ros节点
rospy.init_node("vehicle_detector")
vehicleDetector()
rospy.spin()
except KeyboardInterrupt:
print "Shutting down face detector node."
cv2.destroyAllWindows()
CV|Haar特征分类与车屁股识别