Haar Cascade經常使用來作人臉檢測,其實它能夠檢測任何對象。OpenCV項目源碼中有不少訓練好的Haar分類器。html
OpenCV自帶的haarcascade文件本帖開始先了解怎麼使用這些現成的分類器,最後再訓練本身的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分類器這是個人鼠標,我就使用這一張圖片製做」積極」圖像,沒錯,最後訓練出來的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內容以下:
我下載了2000+圖片製做」積極」圖像
我使用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()
|