0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MTCNN人脸检测的详细介绍及完整C++代码你能学会吗?

C语言专家集中营 来源:未知 作者:易水寒 2018-07-09 11:02 次阅读

人脸检测识别一直是图像算法领域一个主流话题

前年SeetaFace开源了人脸识别引擎,一度成为热门话题。

虽然后来SeetaFace又放出来 2.0版本,但是,我说但是。。。

没有训练代码,想要自己训练一下模型那可就犯难了。

虽然可以阅读源码,从前向传播的角度,反过来实现训练代码,

但是谁有那个闲功夫和时间,去折腾这个呢?

有的时候还是要站在巨人的肩膀上,你才能看得更远。

而SeetaFace不算巨人,只是当年风口上的猪罢了。

前年,为了做一个人脸项目,也是看遍了网上各种项目。

林林总总,各有优劣。

不多做评价,很多东西还是要具体实操,实战才能见真知。

有一段时间,用SeetaFace的人脸检测来做一些小的演示demo,

也花了一点小时间去优化它的算法。

不过很明显我只是把他当成玩具看待。

毕竟不能自己训练模型,这是很大的诟病。

直到后来深度学习大放异彩,印象最深刻莫过于MTCNN。

Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Neural Networks

大合照下,人脸圈出来很准确,壮观了去,这是第一印象。

上图,大家感受一下。

CNN的有三个网络结构。

Stage1: Proposal Net

MTCNN人脸检测的详细介绍及完整C++代码你能学会吗?

Stage2: Refine Net

MTCNN人脸检测的详细介绍及完整C++代码你能学会吗?

Stage3: Output Net

MTCNN人脸检测的详细介绍及完整C++代码你能学会吗?

具体算法思路就不展开了。

我对MTCNN感兴趣的点在于,

MTCNN的思路可以拓展到各种物体检测和识别方向。

也许唯一缺少的就是打标好的数据,

而标注五个点,足够用于适配大多数物体了。

符合小而美的理念,这个是我比较推崇的。

所以MTCNN是一个很值得品味的算法。

github上也有不少MTCNN的实现和资源。

基于mxnet基于caffe基于ncnn等等。。。

很明显,mxnet和 caffe不符合小而美的理念。

果断抛弃了。

ncnn有点肥大,不合我心。

所以,我动了杀气。。

移除NCNN与mtcnn无关的层,

梳理ncnn的一些逻辑代码。

简单做了一些适配和优化。

砍掉一些边边角角。

不依赖opencv等第三方库。

编写示例代码完成后,还有不少工作要做,

不过第一步感觉已经符合我的小小预期。

完整示例代码:

#include "mtcnn.h"#include "browse.h"#define USE_SHELL_OPEN#ifndef nullptr#define nullptr 0#endif#if defined(_MSC_VER)#define _CRT_SECURE_NO_WARNINGS#include #else#include#endif#define STB_IMAGE_STATIC#define STB_IMAGE_IMPLEMENTATION#include"stb_image.h"//ref:https://github.com/nothings/stb/blob/master/stb_image.h#define TJE_IMPLEMENTATION#include "tiny_jpeg.h"//ref:https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h#include #include "timing.h"char saveFile[1024];unsignedchar *loadImage(const char *filename, int *Width, int *Height, int *Channels) { return stbi_load(filename, Width, Height, Channels, 0); }void saveImage(const char *filename, int Width, int Height, int Channels, unsigned char *Output) { memcpy(saveFile + strlen(saveFile), filename, strlen(filename)); *(saveFile + strlen(saveFile) + 1) = 0; //保存为jpg if (!tje_encode_to_file(saveFile, Width, Height, Channels, true, Output)) { fprintf(stderr, "save JPEG fail. "); return; }#ifdef USE_SHELL_OPEN browse(saveFile);#endif}void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) { const char *end; const char *p; const char *s; if (path[0] && path[1] == ':') { if (drv) { *drv++ = *path++; *drv++ = *path++; *drv = ''; } } else if (drv) *drv = ''; for (end = path; *end && *end != ':';) end++; for (p = end; p > path && *--p != '' && *p != '/';) if (*p == '.') { end = p; break; } if (ext) for (s = end; (*ext = *s++);) ext++; for (p = end; p > path;) if (*--p == '' || *p == '/') { p++; break; } if (name) { for (s = p; s < end;)             *name++ = *s++;        *name = '';   }  if (dir) {          for (s = path; s < p;)             *dir++ = *s++;        *dir = '';  } }void getCurrentFilePath(const char *filePath, char *saveFile) {    char drive[_MAX_DRIVE];    char dir[_MAX_DIR];    char fname[_MAX_FNAME];    char ext[_MAX_EXT];    splitpath(filePath, drive, dir, fname, ext);    size_t n = strlen(filePath);    memcpy(saveFile, filePath, n);    char *cur_saveFile = saveFile + (n - strlen(ext));    cur_saveFile[0] = '_';    cur_saveFile[1] = 0; }void drawPoint(unsigned char *bits, int width, int depth, int x, int y, const uint8_t *color) {    for (int i = 0; i < min(depth, 3); ++i) {        bits[(y * width + x) * depth + i] = color[i];    } } void drawLine(unsigned char *bits, int width, int depth, int startX, int startY,         int endX, int endY, const uint8_t *col) {          if (endX == startX) {        if (startY > endY) { int a = startY; startY = endY; endY = a; } for (int y = startY; y <= endY; y++) {            drawPoint(bits, width, depth, startX, y, col);        }    }else{        float m = 1.0f * (endY - startY) / (endX - startX);        int y = 0;        if (startX > endX) { int a = startX; startX = endX; endX = a; } for (int x = startX; x <= endX; x++) {            y = (int)(m * (x - startX) + startY);            drawPoint(bits, width, depth, x, y, col);        }    } } void drawRectangle(unsigned char *bits, int width, int depth, int x1, int y1, int x2, int y2, const uint8_t *col) {    drawLine(bits, width, depth, x1, y1, x2, y1, col);    drawLine(bits, width, depth, x2, y1, x2, y2, col);    drawLine(bits, width, depth, x2, y2, x1, y2, col);    drawLine(bits, width, depth, x1, y2, x1, y1, col); }int main(int argc, char **argv) {    printf("mtcnn face detection ");    printf("blog:http://cpuimage.cnblogs.com/ ");    if (argc < 2) {        printf("usage: %s  model_path image_file ", argv[0]);        printf("eg: %s  ../models ../sample.jpg ", argv[0]);        printf("press any key to exit. ");        getchar();        return 0;    }   const char *model_path = argv[1];   char *s***ile = argv[2];    getCurrentFilePath(s***ile, saveFile);   int Width = 0;   int Height = 0;   int Channels = 0;    unsigned char *inputImage = loadImage(s***ile, &Width, &Height, &Channels);    if (inputImage == nullptr || Channels != 3) return -1;    ncnn::Mat ncnn_img = ncnn::Mat::from_pixels(inputImage, ncnn::Mat::PIXEL_RGB, Width, Height);    std::vector finalBbox; MTCNN mtcnn(model_path); double startTime = now(); mtcnn.detect(ncnn_img, finalBbox); double nDetectTime = calcElapsed(startTime, now()); printf("time: %d ms. ", (int)(nDetectTime * 1000)); int num_box = finalBbox.size(); printf("face num: %u ", num_box); for (int i = 0; i < num_box; i++) {        const uint8_t red[3] = { 255, 0, 0 };        drawRectangle(inputImage, Width, Channels, finalBbox[i].x1,                  finalBbox[i].y1,            finalBbox[i].x2,            finalBbox[i].y2, red);            const uint8_t blue[3] = { 0, 0, 255 };        for (int num = 0; num < 5; num++) {            drawPoint(inputImage, Width, Channels,                        (int)(finalBbox[i].ppoint[num] + 0.5f),                (int)(finalBbox[i].ppoint[num + 5] + 0.5f), blue);        }    }    saveImage("_done.jpg", Width, Height, Channels, inputImage);    free(inputImage);    printf("press any key to exit. ");    getchar();    return 0; }

效果图来一个。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    21

    文章

    2096

    浏览量

    73447
  • 代码
    +关注

    关注

    30

    文章

    4717

    浏览量

    68199
  • 人脸检测
    +关注

    关注

    0

    文章

    79

    浏览量

    16436

原文标题:MTCNN人脸检测

文章出处:【微信号:C_Expert,微信公众号:C语言专家集中营】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    ARM嵌入式环境中FDDB第一的人脸检测算法的运行

    YSQ(于仕琪)人脸检测介绍:YSQ人脸检测算法实现快速从视频帧中检测
    发表于 07-29 06:49

    分享一款高速人脸检测算法

    集与MTCNN算法的准确率相当,可以应用将该算法部署在边缘设备,进行人脸识别算法进行整体算法提速。上图展示了 算法 在 A73 CPU上面的运行时间, 人脸检测部分一般在 10ms-1
    发表于 12-15 07:01

    RK3399Pro是怎样去移植Tencent的mtcnn人脸检测算法的

    RK3399Pro是怎样去移植Tencent的mtcnn人脸检测算法的?有哪些移植步骤?
    发表于 02-15 06:15

    如何实现基于ncnn的RK3399上的mtcnn人脸检测

    如何在RK3399上烧录安卓系统?如何实现基于ncnn的RK3399上的mtcnn人脸检测
    发表于 03-04 07:29

    人脸识别C/C++代码

    人脸识别C/C++代码 将生物特征识别应用于人脸,实际上是包含两个方面:第一,从图像或视频帧中检测
    发表于 02-09 16:05 184次下载

    C++容器的使用代码资料总结免费下载

    本文档的主要内容详细介绍的是C++容器的使用代码资料总结免费下载。
    发表于 01-29 10:52 3次下载
    <b class='flag-5'>C++</b>容器的使用<b class='flag-5'>代码</b>资料总结免费下载

    C++的cast最完整详细的解释资料说明

    本文档的主要内容详细介绍的是C++的cast最完整详细的解释资料说明。
    发表于 01-29 15:26 0次下载
    <b class='flag-5'>C++</b>的cast最<b class='flag-5'>完整</b>最<b class='flag-5'>详细</b>的解释资料说明

    Visual C++教程之C++的基础知识介绍

    本文档的主要内容详细介绍的是Visual C++教程之C++的基础知识介绍主要内容包括了:1 类和对象,2 类的成员及特性,3 继承和派生类
    发表于 02-15 15:59 9次下载
    Visual <b class='flag-5'>C++</b>教程之<b class='flag-5'>C++</b>的基础知识<b class='flag-5'>介绍</b>

    C++串口程序第三方类代码免费下载

    本文档的主要内容详细介绍的是C++串口程序第三方类代码免费下载。
    发表于 09-11 08:00 7次下载
    <b class='flag-5'>C++</b>串口程序第三方类<b class='flag-5'>代码</b>免费下载

    汽车车牌识别系统的C++代码和工程文件免费下载

    本文档的主要内容详细介绍的是汽车车牌识别程序的C++代码和工程文件免费下载。
    发表于 09-20 08:00 2次下载
    汽车车牌识别系统的<b class='flag-5'>C++</b>源<b class='flag-5'>代码</b>和工程文件免费下载

    使用C语言和C++编写俄罗斯方块的资料和源代码免费下载

    本文档的主要内容详细介绍的是使用C语言和C++编写俄罗斯方块的资料和源代码免费下载。
    发表于 06-10 08:00 4次下载
    使用<b class='flag-5'>C</b>语言和<b class='flag-5'>C++</b>编写俄罗斯方块的资料和源<b class='flag-5'>代码</b>免费下载

    使用C++编写的2048小游戏的论文和源代码免费下载

    本文档的主要内容详细介绍的是使用C++编写的2048小游戏的论文和源代码免费下载。
    发表于 07-01 10:26 18次下载
    使用<b class='flag-5'>C++</b>编写的2048小游戏的论文和源<b class='flag-5'>代码</b>免费下载

    手机模拟系统的C++代码免费下载

    本文档的主要内容详细介绍的是手机模拟系统的C++代码免费下载。
    发表于 09-23 08:00 0次下载
    手机模拟系统的<b class='flag-5'>C++</b>源<b class='flag-5'>代码</b>免费下载

    C语言和C++的特点与用法详细说明

    本文档的主要内容详细介绍的是C语言和C++的特点与用法详细说明。
    的头像 发表于 12-26 10:58 4340次阅读

    使用MTCNN和用于ESP32-S3的TensorFlow Lite进行人脸检测

    电子发烧友网站提供《使用MTCNN和用于ESP32-S3的TensorFlow Lite进行人脸检测.zip》资料免费下载
    发表于 06-13 15:28 0次下载
    使用<b class='flag-5'>MTCNN</b>和用于ESP32-S3的TensorFlow Lite进行<b class='flag-5'>人脸</b><b class='flag-5'>检测</b>