转载自:
【Caffe实践】基于Caffe的人脸检测实现 - 1983的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/chenriwei2/article/details/50321085
深度学习可以说是在人脸分析相关领域遍地开花,近年来在人脸识别,深度学习在人脸检测,人脸关键点检测中有很广泛的应用,这篇文章中,初步实现了基于深度学习CNN的人脸检测。
深度学习一般没有进行直接的检测,现有的检测大多都是基于分类的检测,主要的方法有两种:
最典型的方法就是OverFeat那一套,其主要的方法是:对于每一个尺度、每一个可能的滑动窗口,进行分类。其主要的缺点是:对于稍微大一点的图像,滑动窗口往往有好几百万个之多,所以直接利用这个方法往往速度比较的慢。
如果只是对每一个滑动窗口进行分类的话,那速度的确会变得非常的慢,但是,卷积有一个显著的优点就是权值共享,它可以很好的进行计算结果的重复利用。所以最后基于CNN的全卷积网络速度也不会特别的慢。
最典型的方法是R-CNN那一套,其主要的方法是:先快速的检测可能的目标区域块,然后用训练好的深度网络模型进行特征提取,之后再进行分类。它主要解决的问题就是基于滑动窗口的目标检测方法窗口过多的问题。
然而这种方法可能不适合于人脸检测,因为人脸是属于局部目标,而显著目标检测通常用来检测通用的完整目标区域。
在这里,我实现的是基于滑动窗口的检测方法,利用caffe的机制,直接将训练好了的网络模型转换为全卷积网络,从而实现直接输入任意图像的大小。
首先是样本的采样,需要的是两类数据,人脸图像和非人脸图像。可以用自己喜欢的方法进行人脸框和非人脸框的选取,并把截取的人脸图像块分别放在face-images 和no-face-images 文件夹中。
在这里需要注意的一点是:如果随机采样,很有可能正负数据及其的不平衡,从而导致网络无法训练,需要特别注意。
紧接着是将数据转换为LMDB,这一点其实挺重要的,直接的文件列表虽然方便,但是训练速度会比LMDB格式的低5倍左右,而且LMDB或者LevelDB支持更多的数据预处理方法。
利用如下脚本:{convert_data_lmdb.sh},可以将数据转化为LMDB。
<code class="hljs bash has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-shebang" style="color: rgb(0, 102, 102); box-sizing: border-box;">#!/usr/bin/env sh</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># Create the image to lmdb inputs</span> TOOLS=/home/crw/caffe-master/.build_release/tools <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#图像文件的存放位置</span> TRAIN_DATA_ROOT=/media/crw/MyBook/Dataset/faceImages/ VAL_DATA_ROOT=/media/crw/MyBook/Dataset/faceImages/ IMAGE_LIST_ROOT=./ <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#LMDB文件的存放位置</span> ROOT_LMDB=/media/crw/MyBook/TrainData/LMDB/FaceDetection/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50000</span>_32X32 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># Set RESIZE=true to resize the images to 256x256. Leave as false if images have</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># already been resized using another tool.</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#是否剪切为相同的大小</span> RESIZE=<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$RESIZE</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> RESIZE_HEIGHT=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> RESIZE_WIDTH=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> RESIZE_HEIGHT=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> RESIZE_WIDTH=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">fi</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> [ ! <span class="hljs-operator" style="box-sizing: border-box;">-d</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TRAIN_DATA_ROOT</span>"</span> ]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error: TRAIN_DATA_ROOT is not a path to a directory: <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TRAIN_DATA_ROOT</span>"</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path"</span> \ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"where the ImageNet training data is stored."</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">exit</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">fi</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> [ ! <span class="hljs-operator" style="box-sizing: border-box;">-d</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$VAL_DATA_ROOT</span>"</span> ]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error: VAL_DATA_ROOT is not a path to a directory: <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$VAL_DATA_ROOT</span>"</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path"</span> \ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"where the ImageNet validation data is stored."</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">exit</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">fi</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Creating train lmdb..."</span> GLOG_logtostderr=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TOOLS</span>/convert_imageset \ --resize_height=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$RESIZE_HEIGHT</span> \ --resize_width=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$RESIZE_WIDTH</span> \ --shuffle \ --gray \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TRAIN_DATA_ROOT</span> \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$IMAGE_LIST_ROOT</span>/train_2.list \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ROOT_LMDB</span>/train <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Creating val lmdb..."</span> GLOG_logtostderr=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TOOLS</span>/convert_imageset \ --resize_height=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$RESIZE_HEIGHT</span> \ --resize_width=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$RESIZE_WIDTH</span> \ --shuffle \ --gray \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$VAL_DATA_ROOT</span> \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$IMAGE_LIST_ROOT</span>/val_2.list \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ROOT_LMDB</span>/val <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$TOOLS</span>/compute_image_mean <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ROOT_LMDB</span>/train \ <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ROOT_LMDB</span>/mean.binaryproto <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">echo</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Done."</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li></ul>
由于我们是用来做人脸二分类,所以没有必要训练一个非常大的网络,小一点的就可以,我这边是改进DeepID的网络,采用人脸图像大小是48*48 彩色图像。当然你也可以直接那别人训练好了的网络进行微调处理。
完整的训练参数及其文件在最后面的链接文件给出。。
训练网络也跟普通的所有的分类网络训练一样。
配置好相对应的路径和超参数,在当前路径下,运行
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">./train<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sh</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
由于是二分类,网络收敛的很快,差不多几万个迭代就可以达到99%以上的二分类精度。
训练好了的人脸二分类器,不能直接应用于人脸检测,需要进行转换为全卷积网络的格式,具体的方法在Caffe官网上有详细的说明,这里不再赘述。
关键代码如下:
<code class="hljs python has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">convert_full_conv</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(model_define,model_weight,model_define_fc,model_weight_fc)</span>:</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''' @breif : 将原始网络转换为全卷积模型 @param: model_define,二分类网络定义文件 @param: model_weight,二分类网络训练好的参数 @param: model_define_fc,生成的全卷积网络定义文件 @param: model_weight_fc,转化好的全卷积网络的参数 '''</span> net = caffe.Net(model_define, model_weight, caffe.TEST) fc_params = {pr: (net.params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].data, net.params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].data) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> pr <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> params} net_fc = caffe.Net(model_define_fc, model_weight, caffe.TEST) conv_params = {pr: (net_fc.params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].data, net_fc.params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].data) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> pr <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> params_fc} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> pr, pr_conv <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> zip(params, params_fc): conv_params[pr_conv][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].flat = fc_params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].flat <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># flat unrolls the arrays</span> conv_params[pr_conv][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>][...] = fc_params[pr][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] net_fc.save(model_weight_fc) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'convert done!'</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> net_fc</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
直接使用了这个代码,已经实现了非极大值阈值。
主要代码如下:
<code class="hljs python has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">face_detection_image</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(net,net_vf,image_name)</span>:</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''' @检测单张人脸图像 '''</span> scales = [] imgs = skimage.io.imread(image_name) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> imgs.ndim==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>: rows,cols,ch = imgs.shape <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>: rows,cols = imgs.shape <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#计算需要的检测的尺度因子</span> min = rows <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> rows<=cols <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> cols max = rows <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> rows>=cols <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> cols <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 放大的尺度 </span> delim = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2500</span>/max <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (delim >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>): scales.append(delim) delim=delim-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#缩小的尺度</span> min = min * factor factor_count = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(min >= face_w): scale = pow(factor, factor_count) scales.append(scale) min = min * factor factor_count += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#=========================</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#scales.append(1)</span> total_boxes = [] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">###显示热图用</span> num_scale = len(scales) s1=int(np.sqrt(num_scale))+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> tt=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> plt.subplot(s1, s1+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, tt) plt.axis(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'off'</span>) plt.title(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Input Image"</span>) im=caffe.io.load_image(image_name) plt.imshow(im) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#============</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> scale <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> scales: w,h = int(rows* scale),int(cols* scale) scale_img= tf.resize(imgs,(w,h)) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#更改网络输入data图像的大小</span> net.blobs[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>].reshape(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,channel,w,h) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#转换结构</span> transformer = caffe.io.Transformer({<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>: net.blobs[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>].data.shape}) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#transformer.set_mean('data', np.load(caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy').mean(1).mean(1))</span> transformer.set_transpose(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>, (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)) transformer.set_channel_swap(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>, (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)) transformer.set_raw_scale(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>, raw_scale) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#前馈一次</span> out = net.forward_all(data=np.asarray([transformer.preprocess(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>, scale_img)])) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">###显示热图用</span> tt=tt+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> plt.subplot(s1, s1+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, tt) plt.axis(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'off'</span>) plt.title(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"sacle: "</span>+ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%.2f"</span> %scale) plt.imshow(out[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'prob'</span>][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,map_idx]) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#===========</span> boxes = generateBoundingBox(out[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'prob'</span>][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,map_idx], scale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(boxes): total_boxes.extend(boxes) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#非极大值抑制</span> boxes_nms = np.array(total_boxes) true_boxes1 = nms_max(boxes_nms, overlapThresh=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.3</span>) true_boxes = nms_average(np.array(true_boxes1), overlapThresh=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.07</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#===================</span> plt.savefig(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'heatmap/'</span>+image_name.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/'</span>)[-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#在图像中画出检测到的人脸框</span> fig, ax = plt.subplots(ncols=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, nrows=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, figsize=(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>)) ax.imshow(imgs) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> box <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> true_boxes: im_crop = im[box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]:box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>],box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]:box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>],:] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> im_crop.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">or</span> im_crop.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> re_verify(net_vf, im_crop) == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>: rect = mpatches.Rectangle((box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]), box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]-box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>]-box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], fill=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">False</span>, edgecolor=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'red'</span>, linewidth=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) ax.text(box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"{0:.3f}"</span>.format(box[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>]),color=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'white'</span>, fontsize=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>) ax.add_patch(rect) plt.savefig(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'result/'</span>+image_name.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/'</span>)[-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]) plt.close() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> out[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'prob'</span>][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,map_idx]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li></ul>
其中,颜色越红的地方出现就是检测器判断人脸出现的地方。
这里面已经设置了比较高的阈值,不然误检率会很高。
1,阈值的设定,是在准确率和召回率之前的权衡。
2,基于以上方法,定位还不够准确。
地址:Github代码
PS: 如果对你有帮助,还请点个star吧
至此,完成了基于Caffe的人脸检测、人脸点检测、人脸识别的基本工作,后面还需要努力搞创新,come on ~