opencv+CNN实现人脸识别
2017-03-30 16:50
615 查看
在知乎上看到一个有趣的专栏,讲的是国外(日本?)一个牛人用OpenCV+CNN实现了一个人脸识别工具,觉得挺好玩的,所以fork下来自己也研究了一下,在这里做一个总结:
总的来说,要实现最终的人脸识别功能,就要分别实现以下几个小目标:
通过笔记本自带的摄像头实现实时的人脸检测,这里用到了python下的openCV;
为了得到用于识别模型的输入,还需要从已有照片中提取出目标(比如说自己)的人脸,以及其他人的人脸。别忘了给这两类数据分别贴上标签;
实现对来自照片或摄像头帧的人脸的统一处理(大小、去色等),这样才能使得输入到模型中的输入标准化;
构造一个CNN 模型,以目标和其他人的人脸为输入,经过训练得到模型参数并保存,这里用到了python下的keras框架;
回到1,当通过笔记本摄像头实现了人脸检测后,将这个人脸输入到训练好的模型中,如果模型输出0,说明该人脸是属于目标的,即完成了人脸识别;
该项目是在Python下实现的,用到了openCV和keras。这里实在想吐槽一下,不晓得是不是ubuntu16.04的版本太高,导致和openCV不兼容,总之在ubuntu下面费了九牛二虎之力也不能正常使用openCV,摄像头打不开。至于keras和它所依托的theano倒是装得很顺利,
1
的安装方式还是很方便的。
至于windows下的话,则是keras始终跑不了。。。前前后后也花了几个星期。。。
最后是在ubuntu下训练和识别,摄像头帧在windows环境下先采好,算是勉强完成了目标。感慨就是环境的搭建总归是很蛋疼的。
好在整个小项目还是弄懂了的,一共用到了5个模块,下面分别进行描述:
人脸识别的前提是人脸检测,这里其实通过openCV调用笔记本摄像头,并且用其自带的人脸检测工具实现,尽管识别的成功率不是特别高,头转得超过某个角度就识别不出来了,不过比较正的人脸还是能成功识别的。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
这一步其实和上面的差不多,只不过上面是实时地从摄像头的每一帧图像上提取人脸,这里是从事先准备好的照片上提取出人脸来。
遍历路径
2
3
4
5
6
7
1
2
3
4
5
6
7
一样用到了
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
无论是用来训练模型的照片人脸,还是用来最终识别的摄像头人脸,被提取出来后都要进行统一的处理:
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
注意到最后的
这一步是用keras构建CNN模型,并且训练它,得到用于后续人脸识别的模型参数。keras是一个python下很流行的深度学习框架,它封装得很好,所以只是使用一下的话,就会感到很方便。
CNN 即是针对图像输入的一种卷积神经网络,它的实现原理可以看一下这里,还是挺神奇的,虽然和其他绝大多数机器/深度学习的方法一样,很难通过数学方法证明其有效性。不过我们这里只是用一下。。。
最终,得到并保存模型参数为
其实这一步又是在最初人脸检测的基础上实现的,将人脸检测的结果:人脸进行标准化处理,输入到模型中,输出一个预测的标签。如果标签为0,那么就是成功识别了,反之就没有识别到目标物体。
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
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
复现这个人脸识别器的原因很简单,就是觉得挺好玩的。而且之前总是觉得人脸识别很神秘,现在基本弄懂了这个实现方法之后(虽然keras内部实现完全没懂),就对深度学习和它在生活中的应用有了更深的理解了,总之还是很不错的。
最后,虽然基本没有改动,但是我把我做了注释的版本放在了GitHub上。
项目描述
总的来说,要实现最终的人脸识别功能,就要分别实现以下几个小目标:通过笔记本自带的摄像头实现实时的人脸检测,这里用到了python下的openCV;
为了得到用于识别模型的输入,还需要从已有照片中提取出目标(比如说自己)的人脸,以及其他人的人脸。别忘了给这两类数据分别贴上标签;
实现对来自照片或摄像头帧的人脸的统一处理(大小、去色等),这样才能使得输入到模型中的输入标准化;
构造一个CNN 模型,以目标和其他人的人脸为输入,经过训练得到模型参数并保存,这里用到了python下的keras框架;
回到1,当通过笔记本摄像头实现了人脸检测后,将这个人脸输入到训练好的模型中,如果模型输出0,说明该人脸是属于目标的,即完成了人脸识别;
该项目是在Python下实现的,用到了openCV和keras。这里实在想吐槽一下,不晓得是不是ubuntu16.04的版本太高,导致和openCV不兼容,总之在ubuntu下面费了九牛二虎之力也不能正常使用openCV,摄像头打不开。至于keras和它所依托的theano倒是装得很顺利,
conda install xx1
1
的安装方式还是很方便的。
至于windows下的话,则是keras始终跑不了。。。前前后后也花了几个星期。。。
最后是在ubuntu下训练和识别,摄像头帧在windows环境下先采好,算是勉强完成了目标。感慨就是环境的搭建总归是很蛋疼的。
好在整个小项目还是弄懂了的,一共用到了5个模块,下面分别进行描述:
摄像头的人脸检测
人脸识别的前提是人脸检测,这里其实通过openCV调用笔记本摄像头,并且用其自带的人脸检测工具实现,尽管识别的成功率不是特别高,头转得超过某个角度就识别不出来了,不过比较正的人脸还是能成功识别的。def camera_detector(): global frame_num cap = cv.VideoCapture(0) #打开笔记本内置的摄像头 while cap.isOpened(): #time.sleep(1) #延迟x秒 ret, frame = cap.read() #读取一帧,前一个返回值是是否成功,后一个返回值是图像本身 # out.write(frame) #把每帧图片一帧帧地写入video中 show_image = face_detector(frame, face_cascade) #show_image是返回的已标记出人脸的图片 cv.imshow("monitor", show_image) #在窗口显示一帧 key = cv.waitKey(40) if key == 27 or key == ord('q'): #如果按 14433 ESC或q键,退出 break if key == ord('s'): #如果按s键,保存图片 cv.imwrite("frame_%s.png" % frame_num,frame) frame_num = frame_num+1 # out.release() cap.release() cv.destroyAllWindows()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 检测出图片中的人脸,并用方框标记出来 def face_detector(image, cascade): global face_num #引用全局变量 grayImage = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #灰度化图片 equalImage = cv.equalizeHist(grayImage) #直方图均衡化 faces = cascade.detectMultiScale(equalImage, scaleFactor=1.3, minNeighbors=3) for (x,y,w,h) in faces: #裁剪出人脸,单独保存成图片,注意这里的横坐标与纵坐标不知为啥颠倒了 #cv.imwrite("face_%s.png" %(face_num), image[y:y+h,x:x+w]) cv.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2) face_num = face_num + 1 return image1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
从照片中提取人脸作为模型输入
这一步其实和上面的差不多,只不过上面是实时地从摄像头的每一帧图像上提取人脸,这里是从事先准备好的照片上提取出人脸来。 遍历路径
path中的所有图片:
def get_my_face(path): for root, dirs, files in os.walk(path): for name in files: if name.endswith("jpg"): img = cv.imread(os.path.join(root, name)) #打开该照片 print('now is %s' % name) face_detector(img, face_cascade)1
2
3
4
5
6
7
1
2
3
4
5
6
7
一样用到了
face_detector(image, cascade)函数来检测人脸,不过这里略有不同,是直接把提取的人脸另存为图片。
def face_detector(image, cascade): global face_num global root_path grayImage = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #灰度化图片 equalImage = cv.equalizeHist(grayImage) #直方图均衡化 faces = cascade.detectMultiScale(equalImage, scaleFactor=1.3, minNeighbors=3) os.chdir(os.path.join(root_path,'training')) for (x,y,w,h) in faces: #裁剪出人脸,单独保存成图片,注意这里的横坐标与纵坐标不知为啥颠倒了 cv.imwrite("face_%s.png"%(face_num), image[y:y+h,x:x+w]) face_num = face_num + 11
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
标准化输入
无论是用来训练模型的照片人脸,还是用来最终识别的摄像头人脸,被提取出来后都要进行统一的处理:import os import numpy as np import cv2 IMAGE_SIZE = 64 images = [] labels = [] #============================================================================== #将image统一补全并缩放成相同的大小 def resize_with_pad(image, height=IMAGE_SIZE, width=IMAGE_SIZE): #计算后续填充图片时的上、下、左、右的像素点 def get_padding_size(image): h, w, _ = image.shape longest_edge = max(h, w) top, bottom, left, right = (0, 0, 0, 0) if h < longest_edge: dh = longest_edge - h top = dh // 2 bottom = dh - top elif w < longest_edge: dw = longest_edge - w left = dw // 2 right = dw - left else: pass return top, bottom, left, right top, bottom, left, right = get_padding_size(image) BLACK = [0, 0, 0] #填充图片 constant = cv2.copyMakeBorder(image, top , bottom, left, right, cv2.BORDER_CONSTANT, value=BLACK) #缩放图片以统一输入 resized_image = cv2.resize(constant, (height, width)) return resized_image #============================================================================== #============================================================================== #读取图片,并返回大小统一的图片 def read_image(file_path): image = cv2.imread(file_path) grayImage = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #灰度化图片 image = cv.equalizeHist(grayImage) #直方图均衡化 image = resize_with_pad(image, IMAGE_SIZE, IMAGE_SIZE) return image #============================================================================== #============================================================================== #遍历path,返回它下面的所有PNG图片及其所在路径 def traverse_dir(path): for file_or_dir in os.listdir(path): abs_path = os.path.abspath(os.path.join(path, file_or_dir)) #print(abs_path) if os.path.isdir(abs_path): # 遍历子目录 traverse_dir(abs_path) else: # file if file_or_dir.endswith('.png'): image = read_image(abs_path) images.append(image) labels.append(path) return images, labels #============================================================================== #============================================================================== #给获得的图片贴上标签 def extract_data(path): images, labels = traverse_dir(path) images = np.array(images) labels = np.array([0 if label.endswith('me') else 1 for label in labels]) return images, labels1
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
注意到最后的
extract_data(path)函数通过训练数据所在的路径给输入贴上不同的标签。目标的所有人脸放在文件夹1里,其他人的人脸放在文件夹2里。目标人脸赋予标签0,其他人的人脸赋予标签1。
训练模型得到参数
这一步是用keras构建CNN模型,并且训练它,得到用于后续人脸识别的模型参数。keras是一个python下很流行的深度学习框架,它封装得很好,所以只是使用一下的话,就会感到很方便。 CNN 即是针对图像输入的一种卷积神经网络,它的实现原理可以看一下这里,还是挺神奇的,虽然和其他绝大多数机器/深度学习的方法一样,很难通过数学方法证明其有效性。不过我们这里只是用一下。。。
最终,得到并保存模型参数为
model.h5。
最终实现人脸识别
其实这一步又是在最初人脸检测的基础上实现的,将人脸检测的结果:人脸进行标准化处理,输入到模型中,输出一个预测的标签。如果标签为0,那么就是成功识别了,反之就没有识别到目标物体。import cv2 as cv from CNN_train import Model #from image_show import show_image face_cascade = cv.CascadeClassifier('./data/haarcascade_frontalface_alt.xml') if __name__ == '__main__': cap = cv.VideoCapture(0) model = Model() model.load() while cap.isOpened(): _, image = cap.read() grayImage = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #灰度化图片 equalImage = cv.equalizeHist(grayImage) #直方图均衡化 faces = face_cascade.detectMultiScale(equalImage, scaleFactor=1.3, minNeighbors=3) if len(faces) > 0: print('face detected') color = (255, 255, 255) # 白 for (x,y,w,h) in faces: #裁剪出人脸,单独保存成图片 head = image[y-10:y+h,x:x+w] result = model.predict(head) if result == 0: # boss print('Successfully!') #show_image() else: print('......') key = cv.waitKey(40) if key == 27 or key == ord('q'): #如果按ESC或q键,退出 break cap.release() cv.destroyAllWindows()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
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
总结
复现这个人脸识别器的原因很简单,就是觉得挺好玩的。而且之前总是觉得人脸识别很神秘,现在基本弄懂了这个实现方法之后(虽然keras内部实现完全没懂),就对深度学习和它在生活中的应用有了更深的理解了,总之还是很不错的。 最后,虽然基本没有改动,但是我把我做了注释的版本放在了GitHub上。
相关文章推荐
- openCV+ASM+LBP+Gabor实现人脸识别(GT人脸库)
- 基于OpenCV的EigenFace FisherFace LBPHFace人脸识别的实现
- Android使用OpenCV实现「人脸检测」和「人脸识别」
- OpenCV + MFC 实现简单人脸识别
- QT+Opencv实现人脸检测与性别识别(2)
- OpenCV中人脸识别代码实现
- java+opencv+intellij idea实现人脸识别
- 25 行 Python 代码实现人脸识别——OpenCV
- OpenCV实现人脸识别
- Java使用OpenCV实现人脸识别/人眼检测/图片截取/合成/添加水印
- python下实现人脸识别(opencv2)
- 调用OpenCV实现人脸识别功能
- 人脸识别特征提取(LBP)及其opencv实现
- OpenCV实现人脸识别——EigenFace特征脸法
- OpenCV实现人脸识别——EigenFace特征脸法
- 使用 HTML5, javascript, webrtc, websockets, Jetty 和 OpenCV 实现基于 Web 的人脸识别
- OpenCV+JavaCV实现人脸识别
- 【Android】Android使用OpenCV实现人脸识别(OpenCV+JavaCV)
- python使用opencv实现人脸识别系统
- QT+Opencv实现人脸检测与性别识别(1)