人脸检测(一)

客官°小女子只卖身不卖艺 2022-06-16 05:17 355阅读 0赞

有天导师突然找我,让我搞一些关于人脸的应用,比如换个脸什么的……没办法那就先把人脸自动检测出来吧。人脸检测,即检测出图像中存在的人脸,并把它的位置准确地框出来。是人脸特征点检测、人脸识别的基础。可以谷歌Face Detection Benchmark寻找数据集和优秀论文,上thinkface论坛,搜集人脸检测数据集和方法。常用的人脸检测数据集,包括FDDB、AFLW、WIDER FACE等。随着近年来随着深度学习的快速发展,涌现出来很多优秀的人脸检测算法。
例如,FDDB数据库就提交了很多出色的人脸检测算法,例如采用级联CNN网络的人脸检测方法:A Convolutioanal Neural Network Cascade,改进的faster rcnn做人脸检测:Face Detection using Deep Learning:An Improved Faster RCNN Approach,还有对小脸检测非常成功的Finding tiny faces等等,建议找个三篇左右认真研读就行了,也不需要去一一实现,没有太大意义。
另外,像opencv、dlib、libfacedetect等也提供了人脸检测的接口。因为人脸检测是很基本的任务,所以很多公司都做了人脸检测的工作,而且做得很牛,例如face++。
这里写图片描述

下面仅介绍本人尝试并实现了的几种常见的人脸检测方法:

1.单个CNN人脸检测方法
2.级联CNN人脸检测方法
3.OpenCV人脸检测方法
4.Dlib人脸检测方法
5.libfacedetect人脸检测方法
6.Seetaface人脸检测方法


1.单个CNN人脸检测方法

该人脸检测方法的有点在于,思路简单,实现简单;缺点是速度较慢(在一块普通的gpu上对一副1000x600的图像进行多尺度检测也可能花上一两秒),检测效果还可以,但得到的人脸框不够准确。
首先训练一个判断人脸非人脸的二分类器。例如采用卷积神经网络caffenet进行二分类,可以在imagenet数据集训练过的模型,利用自己的人脸数据集,进行微调。也可以自定义卷积网络进行训练,为了能检测到更小的人脸目标,我们一般采用小一点的卷积神经网络作为二分类模型,减小图像输入尺寸,加快预测速度。
然后将训练好的人脸判断分类网络的全连接层改为卷积层,这样网络变成了全卷积网络,可以接受任意输入图像大小,图像经过全卷积网络将得到特征图,特征图上每一个“点”对应该位置映射到原图上的感受野区域属于人脸的概率,将属于人脸概率大于设定阈值的视为人脸候选框。
图像上人脸的大小是变化的,为了适应这种变化,最暴力的办法就是使用图像金字塔的方式,将待检测的图像缩放到不同大小,以进行多尺度人脸检测。对多个尺度下检测出来的所有人脸候选框,做非极大值抑制NMS,得到最后人脸检测的结果。

这里写图片描述

这里提供用caffe实现该方法的数据集、模型文件和代码打包的 下载链接

下面介绍用caffe实现该方法的具体过程。因为需要训练判断是否为人脸的CNN分类器,准备好正负训练样本,然后得到caffe训练所需的的数据集文件(由于采用的是48x48的网络,原始数据集归一化到了48x48)。
这里写图片描述
这里CNN采用的是DeepID卷积神经网络,网络结构如下,它的输入只有48x48大小,而采用AlexNet或CaffeNet网络会增加时间开销。
这里写图片描述
准备好网络模型文件train_val.prototxt和超参数配置文件solver.prototxt之后(下载链接中都有),开始训练,迭代10w次得到caffemodel。对测试集face_test文件夹中的图像进行测试,准备好测试用的deploy.prototxt。
测试单张图像的python脚本face_test.py如下:

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Mar 10 23:02:06 2017
  4. @author: Administrator
  5. """
  6. import numpy as np
  7. import caffe
  8. size = 48
  9. image_file = 'C:/Users/Administrator/Desktop/caffe/data/face/face_test/0/253_faceimage07068.jpg'#测试图片路径
  10. model_def = 'C:/Users/Administrator/Desktop/caffe/models/face/deploy.prototxt'
  11. model_weights = 'C:/Users/Administrator/Desktop/caffe/models/face/_iter_10000.caffemodel'
  12. net = caffe.Net(model_def, model_weights, caffe.TEST)
  13. # 加载均值文件 也可指定数值做相应的操作
  14. #mu = np.load('C:/Users/Administrator/Desktop/caffe/python/caffe/imagenet/ilsvrc_2012_mean.npy') ###caffe 自带的文件
  15. #mu = mu.mean(1).mean(1) # average over pixels to obtain the mean (BGR) pixel values
  16. transformer = caffe.io.Transformer({
  17. 'data': net.blobs['data'].data.shape}) ##设定图片的shape格式(1,3,48,48),大小由deploy 文件指定
  18. #transformer.set_mean('data', mu) # 每个通道减去均值
  19. # python读取的图片文件格式为H×W×K,需转化为K×H×W
  20. transformer.set_transpose('data', (2,0,1)) #改变维度的顺序,由原始图片(48,48,3)变为(3,48,48)
  21. # python中将图片存储为[0, 1],而caffe中将图片存储为[0, 255],所以需要一个转换
  22. transformer.set_raw_scale('data', 255) # 缩放到【0,255】之间
  23. transformer.set_channel_swap('data', (2,1,0)) #交换通道,将图片由RGB变为BGR
  24. #net.blobs['data'].reshape(1,3,size, size) # 将输入图片格式转化为合适格式(与deploy文件相同)
  25. #上面这句,第一参数:图片数量 第二个参数 :通道数 第三个参数:图片高度 第四个参数:图片宽度
  26. image = caffe.io.load_image(image_file) #加载图片,始终是得到一副(h,w,3),rgb,0~1,float32的图像
  27. net.blobs['data'].data[...] = transformer.preprocess('data', image) #用上面的transformer.preprocess来处理刚刚加载图片
  28. caffe.set_device(0)
  29. caffe.set_mode_gpu()
  30. output = net.forward()
  31. output_prob = output['prob'][0].argmax() # 给出概率最高的是第几类,需要自己对应到我们约定的类别去
  32. print output_prob
  33. print output['prob'][0][0] #或print output['prob'][0,1]

批量测试计算准确度的matlab脚本face_test.m如下:

  1. %注意:caffe中维度顺序为(N,C,H,W),而matcaffeBlob维度顺序为(W,H,C,N),即完全相反
  2. %matlab加载图像为(h,w,c),得到的是rgb,而caffe使用的是bgr
  3. function test_face()
  4. clear;
  5. addpath('..');%添加上级目录搜索路径
  6. addpath('.');%添加当前目录搜索路径
  7. caffe.set_mode_gpu(); %设置gpu模式
  8. caffe.set_device(0); %gpuid0
  9. %caffe.set_mode_cpu();
  10. net_model = 'C:\Users\Administrator\Desktop\caffe\models\face\deploy.prototxt'; %网络模型deploy.prototxt
  11. net_weights = 'C:\Users\Administrator\Desktop\caffe\models\face\_iter_10000.caffemodel'; %训练好的模型文件
  12. %net_model = 'C:\Users\Administrator\Desktop\caffe\models\face2\deploy.prototxt'; %网络模型deploy.prototxt
  13. %net_weights = 'C:\Users\Administrator\Desktop\caffe\models\face2\_iter_100000.caffemodel'; %训练好的模型文件
  14. phase = 'test'; %不做训练,而是测试
  15. net = caffe.Net(net_model, net_weights, phase); %获取网络
  16. tic;
  17. error = 0;
  18. total = 0;
  19. %批量读取图像进行测试
  20. datadir = 'C:\Users\Administrator\Desktop\caffe\data\face\face_test\0';
  21. imagefiles = dir(datadir);
  22. for i = 3:length(imagefiles)
  23. im = imread(fullfile(datadir,imagefiles(i).name));
  24. [input_data,flag] = prepare_image(im); %图像数据预处理
  25. if flag ~= 1
  26. continue;
  27. end
  28. input_data ={input_data};
  29. net.forward(input_data); %做前向传播
  30. scores = net.blobs('prob').get_data();
  31. [best_score,best] = max(scores);
  32. % fprintf('*****%.3f %d %d\n',best_score,best - 1,classid(i-2));
  33. best = best - 1; %matlab中从1开始,减1变成从0开始
  34. if best ~= 0
  35. error = error + 1;
  36. fprintf('-----error: %d\n',error);
  37. errorfile = ['error\' imagefiles(i).name];
  38. %imwrite(im,errorfile);
  39. end
  40. total = total + 1;
  41. end
  42. datadir_1 = 'C:\Users\Administrator\Desktop\caffe\data\face\face_test\1';
  43. imagefiles_1 = dir(datadir_1);
  44. for i = 3:length(imagefiles_1)
  45. im_1 = imread(fullfile(datadir_1,imagefiles_1(i).name));
  46. [input_data_1,flag] = prepare_image(im_1); %图像数据预处理
  47. if flag ~= 1
  48. continue;
  49. end
  50. input_data_1 = {input_data_1};
  51. net.forward(input_data_1); %做前向传播
  52. scores_1 = net.blobs('prob').get_data();
  53. [best_score_1,best_1] = max(scores_1);
  54. % fprintf('*****%.3f %d %d\n',best_score,best - 1,classid(i-2));
  55. best_1 = best_1 - 1; %matlab中从1开始,减1变成从0开始
  56. if best_1 ~= 1
  57. error = error + 1;
  58. fprintf('error: %d-----\n',error);
  59. errorfile = ['face_error\' imagefiles_1(i).name];
  60. %imwrite(im,errorfile);
  61. end
  62. total = total + 1;
  63. end
  64. total_time = toc;
  65. %打印到屏幕上
  66. fprintf('total_time: %.3f s\n',total_time);
  67. fprintf('aver_time: %.3f s\n',total_time/total);
  68. fprintf('error/total: %d/%d\n',error,total);
  69. fprintf('accurary: %.4f\n',1.0 - (error*1.0)/total);
  70. %disp(['error/total: ',num2str(error),'/',num2str(length(imagefiles)-2)]);
  71. end
  72. function [im_data,flag] = prepare_image(im)
  73. %d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat');
  74. %mean_data = d.mean_data;
  75. %resize to 227 x 227
  76. im_data = [];
  77. im = imresize(im,[227 227],'bilinear');
  78. %im = imresize(im,[48 48],'bilinear');
  79. [h,w,c] = size(im);
  80. if c ~= 3
  81. flag = 0;
  82. return;
  83. end
  84. flag = 1;
  85. %caffeblob顺序是[w h c num]
  86. %matlab:[h w c] rgb -> caffe:[w h c] bgr
  87. im_data = im(:,:,[3,2,1]); %rgb -> bgr
  88. im_data = permute(im_data,[2,1,3]); %[h w c] -> [w h c]
  89. [w,h,~] = size(im_data);
  90. %ImageNet数据集的均值具有统计规律,这里可以直接拿来使用
  91. mean_data(:,:,1) = ones(w,h) .* 104; %b
  92. mean_data(:,:,2) = ones(w,h) .* 117; %g
  93. mean_data(:,:,3) = ones(w,h) .* 123; %r
  94. im_data = single(im_data);
  95. %im_data = im_data - single(mean_data); %因为训练集和测试集都没有做去均值,所以这里也不做(如果只是这里做了去均值效果会变差)
  96. end

在测试集上进行批量测试,准确率达到了98%。
这里写图片描述
为了利用CNN分类器来检测人脸,需要将CNN网络中的全连接层替换为卷积层得到全卷积网络,修改好的全卷积网络deploy_full_conv.prototxt内容如下:

  1. name: "face_full_conv_net"
  2. layer {
  3. name: "data"
  4. type: "Input"
  5. top: "data"
  6. input_param { shape: { dim: 1 dim: 3 dim: 48 dim: 48 } }
  7. }
  8. layer {
  9. name: "conv1"
  10. type: "Convolution"
  11. bottom: "data"
  12. top: "conv1"
  13. convolution_param {
  14. num_output: 20
  15. kernel_size: 3
  16. stride: 1
  17. pad: 1
  18. }
  19. }
  20. layer {
  21. name: "relu1"
  22. type: "ReLU"
  23. bottom: "conv1"
  24. top: "conv1"
  25. }
  26. layer {
  27. name: "norm1"
  28. type: "LRN"
  29. bottom: "conv1"
  30. top: "conv1"
  31. lrn_param {
  32. local_size: 5
  33. alpha: 0.0001
  34. beta: 0.75
  35. }
  36. }
  37. layer {
  38. name: "pool1"
  39. type: "Pooling"
  40. bottom: "conv1"
  41. top: "pool1"
  42. pooling_param {
  43. pool: MAX
  44. kernel_size: 2
  45. stride: 2
  46. }
  47. }
  48. layer {
  49. name: "conv2"
  50. type: "Convolution"
  51. bottom: "pool1"
  52. top: "conv2"
  53. convolution_param {
  54. num_output: 40
  55. kernel_size: 3
  56. pad: 1
  57. }
  58. }
  59. layer {
  60. name: "relu2"
  61. type: "ReLU"
  62. bottom: "conv2"
  63. top: "conv2"
  64. }
  65. layer {
  66. name: "norm2"
  67. type: "LRN"
  68. bottom: "conv2"
  69. top: "conv2"
  70. lrn_param {
  71. local_size: 5
  72. alpha: 0.0001
  73. beta: 0.75
  74. }
  75. }
  76. layer {
  77. name: "pool2"
  78. type: "Pooling"
  79. bottom: "conv2"
  80. top: "pool2"
  81. pooling_param {
  82. pool: MAX
  83. kernel_size: 2
  84. stride: 2
  85. }
  86. }
  87. layer {
  88. name: "conv3"
  89. type: "Convolution"
  90. bottom: "pool2"
  91. top: "conv3"
  92. convolution_param {
  93. num_output: 60
  94. kernel_size: 3
  95. pad: 1
  96. }
  97. }
  98. layer {
  99. name: "relu3"
  100. type: "ReLU"
  101. bottom: "conv3"
  102. top: "conv3"
  103. }
  104. layer {
  105. name: "norm3"
  106. type: "LRN"
  107. bottom: "conv3"
  108. top: "conv3"
  109. lrn_param {
  110. local_size: 5
  111. alpha: 0.0001
  112. beta: 0.75
  113. }
  114. }
  115. layer {
  116. name: "pool3"
  117. type: "Pooling"
  118. bottom: "conv3"
  119. top: "pool3"
  120. pooling_param {
  121. pool: MAX
  122. kernel_size: 2
  123. stride: 2
  124. }
  125. }
  126. layer {
  127. name: "conv4"
  128. type: "Convolution"
  129. bottom: "pool3"
  130. top: "conv4"
  131. convolution_param {
  132. num_output: 80
  133. kernel_size: 3
  134. pad: 1
  135. }
  136. }
  137. layer {
  138. name: "relu4"
  139. type: "ReLU"
  140. bottom: "conv4"
  141. top: "conv4"
  142. }
  143. layer {
  144. name: "norm4"
  145. type: "LRN"
  146. bottom: "conv4"
  147. top: "conv4"
  148. lrn_param {
  149. local_size: 5
  150. alpha: 0.0001
  151. beta: 0.75
  152. }
  153. }
  154. layer {
  155. name: "pool4"
  156. type: "Pooling"
  157. bottom: "conv4"
  158. top: "pool4"
  159. pooling_param {
  160. pool: MAX
  161. kernel_size: 2
  162. stride: 2
  163. }
  164. }
  165. #修改为卷积层
  166. layer {
  167. name: "fc5-conv" ### fc5
  168. type: "Convolution" ### InnerProduct
  169. bottom: "pool4"
  170. top: "fc5-conv" ### fc5
  171. #inner_product_param {
  172. # num_output: 160
  173. #}
  174. convolution_param {
  175. num_output: 160
  176. kernel_size: 3
  177. }
  178. }
  179. layer {
  180. name: "relu5"
  181. type: "ReLU"
  182. bottom: "fc5-conv"
  183. top: "fc5-conv"
  184. }
  185. layer {
  186. name: "drop5"
  187. type: "Dropout"
  188. bottom: "fc5-conv"
  189. top: "fc5-conv"
  190. dropout_param {
  191. dropout_ratio: 0.5
  192. }
  193. }
  194. #修改为卷积层
  195. layer {
  196. name: "fc6-conv" ### fc6
  197. type: "Convolution" ### InnerProduct
  198. bottom: "fc5-conv"
  199. top: "fc6-conv"
  200. #inner_product_param {
  201. # num_output: 2
  202. #}
  203. convolution_param {
  204. num_output: 2
  205. kernel_size: 1
  206. }
  207. }
  208. layer {
  209. name: "prob"
  210. type: "Softmax"
  211. bottom: "fc6-conv"
  212. top: "prob"
  213. }

还需要将训练好的_iter_100000.caffemodel模型文件也转化为全卷积的,得到的_iter_100000_full_conv.caffemodel,转换脚本convert_full_conv.py如下:

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Mar 10 21:14:09 2017
  4. @author: Administrator
  5. """
  6. ###首先需要手动将deploy.prototxt修改成全卷积的deploy_full_conv.prorotxt,特别要注意全连接层修改成卷积层的细节
  7. ###将训练好的分类模型caffemodel转换成可以接受任意输入大小,最后输出特征图的全卷积模型caffemodel
  8. import numpy as np
  9. import caffe
  10. model_def = 'C:/Users/Administrator/Desktop/caffe/models/face/deploy.prototxt'
  11. model_weights = 'C:/Users/Administrator/Desktop/caffe/models/face/_iter_100000.caffemodel'
  12. net = caffe.Net(model_def,
  13. model_weights,
  14. caffe.TEST)
  15. params = ['fc5', 'fc6']
  16. # fc_params = {name: (weights, biases)}
  17. fc_params = {pr: (net.params[pr][0].data, net.params[pr][1].data) for pr in params}
  18. for fc in params:
  19. print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params[fc][0].shape, fc_params[fc][1].shape)
  20. # Load the fully convolutional network to transplant the parameters.
  21. net_full_conv = caffe.Net('./deploy_full_conv.prototxt',
  22. './_iter_100000.caffemodel',
  23. caffe.TEST)
  24. params_full_conv = ['fc5-conv', 'fc6-conv']
  25. # conv_params = {name: (weights, biases)}
  26. conv_params = {pr: (net_full_conv.params[pr][0].data, net_full_conv.params[pr][1].data) for pr in params_full_conv}
  27. for conv in params_full_conv:
  28. print '{} weights are {} dimensional and biases are {} dimensional'.format(conv, conv_params[conv][0].shape, conv_params[conv][1].shape)
  29. for pr, pr_conv in zip(params, params_full_conv):
  30. conv_params[pr_conv][0].flat = fc_params[pr][0].flat # flat unrolls the arrays
  31. conv_params[pr_conv][1][...] = fc_params[pr][1]
  32. net_full_conv.save('./_iter_100000_full_conv.caffemodel')
  33. print 'success'

最后,就可以用deploy_full_conv.prototxt和_iter_100000_full_conv.caffemodel对任意输入尺寸的图像进行人脸检测了。对单张图像进行人脸检测的python脚本face_detect如下:

  1. # -*- coding: utf-8 -*-
  2. import numpy as np
  3. import cv2 #需要安装opencv,然后将opencv安装目录下build\python\2.7\x64\cv2.pyd拷贝到python的安装目录下Anaconda2\Lib\site-packages文件夹下
  4. from operator import itemgetter
  5. import time
  6. import caffe
  7. caffe.set_device(0)
  8. caffe.set_mode_gpu()
  9. def IoU(rect_1, rect_2):
  10. '''
  11. :param rect_1: list in format [x11, y11, x12, y12, confidence]
  12. :param rect_2: list in format [x21, y21, x22, y22, confidence]
  13. :return: returns IoU ratio (intersection over union) of two rectangles
  14. '''
  15. x11 = rect_1[0] # first rectangle top left x
  16. y11 = rect_1[1] # first rectangle top left y
  17. x12 = rect_1[2] # first rectangle bottom right x
  18. y12 = rect_1[3] # first rectangle bottom right y
  19. x21 = rect_2[0] # second rectangle top left x
  20. y21 = rect_2[1] # second rectangle top left y
  21. x22 = rect_2[2] # second rectangle bottom right x
  22. y22 = rect_2[3] # second rectangle bottom right y
  23. x_overlap = max(0, min(x12,x22) -max(x11,x21))
  24. y_overlap = max(0, min(y12,y22) -max(y11,y21))
  25. intersection = x_overlap * y_overlap
  26. union = (x12-x11) * (y12-y11) + (x22-x21) * (y22-y21) - intersection
  27. return float(intersection) / union
  28. def IoM(rect_1, rect_2):
  29. '''
  30. :param rect_1: list in format [x11, y11, x12, y12, confidence]
  31. :param rect_2: list in format [x21, y21, x22, y22, confidence]
  32. :return: returns IoM ratio (intersection over min-area) of two rectangles
  33. '''
  34. x11 = rect_1[0] # first rectangle top left x
  35. y11 = rect_1[1] # first rectangle top left y
  36. x12 = rect_1[2] # first rectangle bottom right x
  37. y12 = rect_1[3] # first rectangle bottom right y
  38. x21 = rect_2[0] # second rectangle top left x
  39. y21 = rect_2[1] # second rectangle top left y
  40. x22 = rect_2[2] # second rectangle bottom right x
  41. y22 = rect_2[3] # second rectangle bottom right y
  42. x_overlap = max(0, min(x12,x22) -max(x11,x21))
  43. y_overlap = max(0, min(y12,y22) -max(y11,y21))
  44. intersection = x_overlap * y_overlap
  45. rect1_area = (y12 - y11) * (x12 - x11)
  46. rect2_area = (y22 - y21) * (x22 - x21)
  47. min_area = min(rect1_area, rect2_area)
  48. return float(intersection) / min_area
  49. def NMS(rectangles,threshold=0.3):
  50. '''
  51. :param rectangles: list of rectangles, which are lists in format [x11, y11, x12, y12, confidence]
  52. :return: list of rectangles after local NMS
  53. '''
  54. rectangles = sorted(rectangles, key=itemgetter(4), reverse=True) #按照confidence降序排列
  55. result_rectangles = rectangles[:] # list to return
  56. '''
  57. while not result_rectangles == []:
  58. rect = result_rectangles[0]
  59. for index in range(1,len(result_rectangles)):
  60. iou = IoU(rect,result_rectangles[index])
  61. if
  62. '''
  63. number_of_rects = len(result_rectangles)
  64. #threshold = 0.3 # threshold of IoU of two rectangles
  65. cur_rect = 0
  66. while cur_rect < number_of_rects - 1: # start from first element to second last element
  67. rects_to_compare = number_of_rects - cur_rect - 1 # elements after current element to compare
  68. cur_rect_to_compare = cur_rect + 1 # start comparing with element after current
  69. while rects_to_compare > 0: # while there is at least one element after current to compare
  70. if (IoU(result_rectangles[cur_rect], result_rectangles[cur_rect_to_compare]) >= threshold or IoM(result_rectangles[cur_rect], result_rectangles[cur_rect_to_compare]) >= 0.3):
  71. del result_rectangles[cur_rect_to_compare] # delete the rectangle
  72. number_of_rects -= 1
  73. else:
  74. cur_rect_to_compare += 1 # skip to next rectangle
  75. rects_to_compare -= 1
  76. cur_rect += 1 # finished comparing for current rectangle
  77. return result_rectangles
  78. def face_detection(imgFile) :
  79. #model_def = 'C:/Users/Administrator/Desktop/caffe/models/face/deploy_full_conv.prototxt'
  80. #model_weights = 'C:/Users/Administrator/Desktop/caffe/models/face/_iter_10000_full_conv.caffemodel'
  81. model_def = 'C:/Users/Administrator/Desktop/caffe/models/face2/deploy_full_conv.prototxt'
  82. model_weights = 'C:/Users/Administrator/Desktop/caffe/models/face2/_iter_100000_full_conv.caffemodel'
  83. net_full_conv = caffe.Net(model_def,
  84. model_weights,
  85. caffe.TEST)
  86. mu = np.load('C:/Users/Administrator/Desktop/caffe/python/caffe/imagenet/ilsvrc_2012_mean.npy')
  87. mu = mu.mean(1).mean(1) # average over pixels to obtain the mean (BGR) pixel values
  88. #print 'mean-subtracted values:' , zip('BGR', mu)
  89. start_time = time.time()
  90. scales = [] #尺度变换和尺度变换因子
  91. factor = 0.793700526
  92. img = cv2.imread(imgFile) #opencv读取的图像为(h,w,c),bgr,caffe的blob维度为(n,c,h,w),使用的也是rgb
  93. print img.shape
  94. largest = min(2, 4000/max(img.shape[0:2])) #4000是人脸检测的经验值
  95. scale = largest
  96. minD = largest*min(img.shape[0:2])
  97. while minD >= 48: #网络的输入是227x227??? #多尺度变换
  98. scales.append(scale) #添加当前尺度
  99. scale *= factor #乘以尺度变换因子
  100. minD *= factor #得到新的尺度
  101. true_boxes = []
  102. for scale in scales:
  103. scale_img = cv2.resize(img,((int(img.shape[1] * scale), int(img.shape[0] * scale)))) #将图像缩放到各尺度
  104. cv2.imwrite('C:/Users/Administrator/Desktop/caffe/scale_img.jpg',scale_img)
  105. im = caffe.io.load_image('C:/Users/Administrator/Desktop/caffe/scale_img.jpg') #利用caffe的io接口加载图像,始终是得到一副(h,w,3),rgb,0~1,float32的图像
  106. net_full_conv.blobs['data'].reshape(1,3,scale_img.shape[0],scale_img.shape[1]) #重新设置网络data层Blob维度为:1,3,height,width
  107. transformer = caffe.io.Transformer({
  108. 'data': net_full_conv.blobs['data'].data.shape}) #为data层创建transformer
  109. transformer.set_transpose('data', (2,0,1)) #(h,w,3)->(3,h,w)
  110. #transformer.set_mean('data', mu) #设置均值,由于训练集没有去均值,这里也不去均值
  111. transformer.set_raw_scale('data', 255.0) #rescale from [0,1] to [0,255]
  112. transformer.set_channel_swap('data', (2,1,0)) #RGB -> BGR
  113. net_full_conv.blobs['data'].data[...] = transformer.preprocess('data', im)
  114. out = net_full_conv.forward()
  115. print out['prob'][0,0].shape #输出层prob结果,行x列
  116. #print out['prob'][0].argmax(axis=0)
  117. featureMap = out['prob'][0,0] #out['prob'][0][0]属于人脸的概率特征图
  118. stride = 16 #特征图感受野大小
  119. cellSize = 48 #网络输入尺寸
  120. thresh = 0.95
  121. for (y,x),prob in np.ndenumerate(featureMap):
  122. if prob > thresh :
  123. true_boxes.append([float(x*stride)/scale,
  124. float(y*stride)/scale,
  125. float(x*stride + cellSize - 1)/scale,
  126. float(y*stride + cellSize - 1)/scale,
  127. prob])
  128. true_boxes = NMS(true_boxes,0.2) #非极大值抑制
  129. for true_box in true_boxes:
  130. (x1, y1, x2, y2) = true_box[0:4] #取出人脸框的坐标
  131. cv2.rectangle(img, (int(x1),int(y1)), (int(x2),int(y2)), (0,255,0)) #画人脸框
  132. end_time = time.time()
  133. print (end_time-start_time)*1000,'ms'
  134. cv2.imwrite('output.jpg',img)
  135. cv2.namedWindow('test win')
  136. cv2.imshow('test win', img)
  137. cv2.waitKey(0)
  138. cv2.destroyWindow('test win')
  139. if __name__ == "__main__":
  140. imgFile = 'C:/Users/Administrator/Desktop/caffe/matlab/demo/1.jpg'
  141. face_detection(imgFile)

发表评论

表情:
评论列表 (有 0 条评论,355人围观)

还没有评论,来说两句吧...

相关阅读

    相关 人脸检测(三)

    3.OpenCV人脸检测方法 采用的是harr-like特征提取 + adaboost级联分类器构成的人脸检测算法,可以设置要检测的人脸大小范围,召回率高,但有时会出现误检

    相关 人脸检测

    有天导师突然找我,让我搞一些关于人脸的应用,比如换个脸什么的……没办法那就先把人脸自动检测出来吧。人脸检测,即检测出图像中存在的人脸,并把它的位置准确地框出来。是人脸特征点检测

    相关 人脸识别系统_人脸检测

    项目:基于人脸识别的无卡ATM机模拟系统 主要实现内容: 包括实现AMT机模拟人脸识别和密码输入、PC端模拟实现储户数据库服务器系统。 1. ATM模拟端实现采用手