Haar Cascade经常使用来作人脸检测,其实它能够检测任何对象。OpenCV项目源码中有不少训练好的Haar分类器。html

本帖开始先了解怎么使用这些现成的分类器,最后再训练本身的Haar分类器。若是你要检测什么物体,先Google,也许已经有训练好的Haar分类器了(像汽车、猫,狗之类的)。python
若是你没有安装OpenCV,参考:Ubuntu编译安装OpenCV 3.1(Python)sublime-text
使用OpenCV自带的Haar分类器检测脸和眼睛,代码:api
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import cv2
import sys
img = cv2.imread(sys.argv[1])
# 加载分类器
face_haar = cv2.CascadeClassifier("data/haarcascades/haarcascade_frontalface_default.xml")
eye_haar = cv2.CascadeClassifier("data/haarcascades/haarcascade_eye.xml")
# 把图像转为黑白图像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测图像中的全部脸
faces = face_haar.detectMultiScale(gray_img, 1.3, 5)
for face_x,face_y,face_w,face_h in faces:
cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)
# 眼长在脸上
roi_gray_img = gray_img[face_y:face_y+face_h, face_x:face_x+face_w]
roi_img = img[face_y:face_y+face_h, face_x:face_x+face_w]
eyes = eye_haar.detectMultiScale(roi_gray_img, 1.3, 5)
for eye_x,eye_y,eye_w,eye_h in eyes:
cv2.rectangle(roi_img, (eye_x,eye_y), (eye_x+eye_w, eye_y+eye_h), (255,0,0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
1
|
$ python face_detect.py lena.jpg
|
使用摄像头作为输入,实时检测:多线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import cv2
face_haar = cv2.CascadeClassifier("data/haarcascades/haarcascade_frontalface_default.xml")
eye_haar = cv2.CascadeClassifier("data/haarcascades/haarcascade_eye.xml")
cam = cv2.VideoCapture(0)
while True:
_, img = cam.read()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_haar.detectMultiScale(gray_img, 1.3, 5)
for face_x,face_y,face_w,face_h in faces:
cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)
roi_gray_img = gray_img[face_y:face_y+face_h, face_x:face_x+face_w]
roi_img = img[face_y:face_y+face_h, face_x:face_x+face_w]
eyes = eye_haar.detectMultiScale(roi_gray_img, 1.3, 5)
for eye_x,eye_y,eye_w,eye_h in eyes:
cv2.rectangle(roi_img, (eye_x,eye_y), (eye_x+eye_w, eye_y+eye_h), (255,0,0), 2)
cv2.imshow('img', img)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
cam.release()
cv2.destroyAllWindows()
|
上面咱们使用的是训练好的分类器文件,若是你要检测的物体没有现成的Haar分类器,咱们只能本身训练了,其中最费事的部分就是制做训练样本。ide
训练Haar分类器的主要步骤:工具
- 搜集制做成千上万张”消极”图像,什么图片都行,可是确保要检测的对象不在图像中
- 搜集制做成千上万张”积极”图像,确保这些图像中包含要检测的对象
- http://image-net.org是不错的图像资源站
- 建立”积极”向量文件
- 使用OpenCV训练Haar分类器
为了简单,我使用一张图片制做”积极”图像:测试

这是个人鼠标,我就使用这一张图片制做”积极”图像,没错,最后训练出来的Haar分类器只能识别这个特定鼠标。若是你想要识别各类各样的鼠标,你须要搜集整理包含各类鼠标的图片(标记出图片中鼠标所在位置-ROI),即便有工具的帮助,这个工做也是至关痛苦的。url
下载”消极”图像spa
找点和鼠标不想干的图片:image-net
Downloads中包含图像地址:
写一个简单的Python脚本下载图片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# Python3
import urllib.request
import cv2
import os
# 建立图片保存目录
if not os.path.exists('neg'):
os.makedirs('neg')
neg_img_url = ['http://image-net.org/api/text/imagenet.synset.geturls?wnid=n00523513', 'http://image-net.org/api/text/imagenet.synset.geturls?wnid=n07942152']
urls = ''
for img_url in neg_img_url:
urls += urllib.request.urlopen(img_url).read().decode()
img_index = 1
for url in urls.split('\n'):
try:
print(url)
urllib.request.urlretrieve(url, 'neg/'+str(img_index)+'.jpg')
# 把图片转为灰度图片
gray_img = cv2.imread('neg/'+str(img_index)+'.jpg', cv2.IMREAD_GRAYSCALE)
# 更改图像大小
image = cv2.resize(gray_img, (150, 150))
# 保存图片
cv2.imwrite('neg/'+str(img_index)+'.jpg', image)
img_index += 1
except Exception as e:
print(e)
# 判断两张图片是否彻底同样
def is_same_image(img_file1, img_file2):
img1 = cv2.imread(img_file1)
img2 = cv2.imread(img_file2)
if img1.shape == img2.shape and not (np.bitwise_xor(img1, img2).any()):
return True
else:
return False
# 去除重复图片
"""
file_list = os.listdir('neg')
try:
for img1 in file_list:
for img2 in file_list:
if img1 != img2:
if is_same_image('neg/'+img1, 'neg/'+img2) is True:
print(img1, img2)
os.remove('neg/'+img1)
file_list.remove(img1)
except Exception as e:
print(e)
"""
|
- 不少url被墙,你可能须要使用代理。(参考:使用Tor的匿名Python爬虫)
- 下载的文件不少,为了提速,你能够把上面代码改成多线程。
建立消极图片列表:
1
2
3
4
5
6
7
|
import os
import numpy as np
with open('neg.txt', 'w') as f:
for img in os.listdir('neg'):
line = 'neg/'+img+'\n'
f.write(line)
|
建立的neg.txt内容以下:

制做”积极”图像
我使用OpenCV提供的opencv_createsamples命令建立pos.txt文件。它会把要识别的图片嵌入到消极图像中,容许咱们快速建立”积极”图像:
1
|
$ opencv_createsamples -img mouse.jpg -bg neg.txt -info pos.txt -maxxangle 0.5 -maxyangle -0.5 -maxzangle 0.5 -num 2000
|
生成的pos.txt文件:

你能够看看生成的“积极”图像,这些图像中嵌入了要识别的鼠标。
上面的”积极图像”是自动生成的,这要是手工制做,那工做量可想而知。
建立向量文件
无论你用什么方法制做”积极”图像,都须要把它转换为向量格式:
1
|
$ opencv_createsamples -info pos.txt -num 2000 -w 20 -h 30 -vec pos.vec
|
开始训练
1
2
|
$ mkdir data
$ opencv_traincascade -data data -vec pos.vec -bg neg.txt -numPos 1800 -numNeg 900 -numStages 15 -w 20 -h 30 # pos通常是neg的1倍
|
大概须要几个小时,我电脑不给力,上面参数设置的都比较小。
训练完成以后生成的haar分类器(cascade.xml)保存在data目录。
测试生成的haar分类器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import cv2
mouse_haar = cv2.CascadeClassifier("data/cascade.xml")
cam = cv2.VideoCapture(0)
while True:
_, img = cam.read()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#http://docs.opencv.org/2.4/modules/objdetect/doc/cascade_classification.html
mouse = mouse_haar.detectMultiScale(gray_img, 1.2, 3) # 调整参数
for mouse_x,mouse_y,mouse_w,mouse_h in mouse:
cv2.rectangle(img, (mouse_x, mouse_y), (mouse_x+mouse_w, mouse_y+mouse_h), (0,255,0), 2)
cv2.imshow('img', img)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
cam.release()
cv2.destroyAllWindows()
|