人脸检测多尺度检测函数c语言,MTCNN人脸检测 附完整C++代码

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

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

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

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

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

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

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

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

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

林林总总,各有优劣。

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

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

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

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

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

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

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

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

上图,大家感受一下。

c7018a78ab0f565e45a1f22eba489bdc.png

MTCNN的有三个网络结构。

Stage1: Proposal Net

313a161a534c1cdfd1b2f0b07248226d.png

Stage2: Refine Net

0aa19a22f0a53bb0874eb3c2bf69d5ae.png

Stage3: Output Net

fddbd8f653717bc593e3ceda9d40d4d3.png

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

我对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[];

unsigned char *loadImage(const char *filename, int *Width, int *Height, int *Channels) {

return stbi_load(filename, Width, Height, Channels, );

}

void saveImage(const char *filename, int Width, int Height, int Channels, unsigned char *Output) {

memcpy(saveFile + strlen(saveFile), filename, strlen(filename));

*(saveFile + strlen(saveFile) + ) = ;

//保存为jpg

if (!tje_encode_to_file(saveFile, Width, Height, Channels, true, Output)) {

fprintf(stderr, "save JPEG fail.\n");

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[] && path[] == ':') {

if (drv) {

*drv++ = *path++;

*drv++ = *path++;

*drv = '\0';

}

}

else if (drv)

*drv = '\0';

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 = '\0';

}

if (dir) {

for (s = path; s < p;)

*dir++ = *s++;

*dir = '\0';

}

}

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[] = '_';

cur_saveFile[] = ;

}

void drawPoint(unsigned char *bits, int width, int depth, int x, int y, const uint8_t *color) {

for (int i = ; i < min(depth, ); ++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 = ;

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\n");

printf("blog:http://cpuimage.cnblogs.com/\n");

if (argc < ) {

printf("usage: %s model_path image_file \n ", argv[]);

printf("eg: %s ../models ../sample.jpg \n ", argv[]);

printf("press any key to exit. \n");

getchar();

return ;

}

const char *model_path = argv[];

char *szfile = argv[];

getCurrentFilePath(szfile, saveFile);

int Width = ;

int Height = ;

int Channels = ;

unsigned char *inputImage = loadImage(szfile, &Width, &Height, &Channels);

if (inputImage == nullptr || Channels != ) return -;

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.\n ", (int)(nDetectTime * ));

int num_box = finalBbox.size();

printf("face num: %u \n", num_box);

for (int i = ; i < num_box; i++) {

const uint8_t red[] = { , , };

drawRectangle(inputImage, Width, Channels, finalBbox[i].x1, finalBbox[i].y1,

finalBbox[i].x2,

finalBbox[i].y2, red);

const uint8_t blue[] = { , , };

for (int num = ; num < ; num++) {

drawPoint(inputImage, Width, Channels, (int)(finalBbox[i].ppoint[num] + 0.5f),

(int)(finalBbox[i].ppoint[num + ] + 0.5f), blue);

}

}

saveImage("_done.jpg", Width, Height, Channels, inputImage);

free(inputImage);

printf("press any key to exit. \n");

getchar();

return ;

}

效果图来一个。

13ad549421845d626a94aff263a4f162.png

项目地址:

参数也很简单,

mtcnn 模型文件路径 图片路径

例如: mtcnn ../models ../sample.jpg

用cmake即可进行编译示例代码,详情见CMakeLists.txt。

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是:

gaozhihan@vip.qq.com

音频自动增益 与 静音检测 算法 附完整C代码

前面分享过一个算法 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...

音频自动增益 与 静音检测 算法 附完整C代码【转】

转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法 主要用 ...

项目实战 - 原理讲解&lt&semi;-&gt&semi; Keras框架搭建Mtcnn人脸检测平台

Mtcnn它是2016年中国科学院深圳研究院提出的用于人脸检测任务的多任务神经网络模型,该模型主要采用了三个级联的网络,采用候选框加分类器的思想,进行快速高效的人脸检测.这三个级联的网络分别是快速生成 ...

基于RNN的音频降噪算法 &lpar;附完整C代码&rpar;

前几天无意间看到一个项目rnnoise. 项目地址: https://github.com/xiph/rnnoise 基于RNN的音频降噪算法. 采用的是 GRU/LSTM 模型. 阅读下训练代码,可 ...

音频降噪算法 附完整C代码

降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...

mser 最大稳定极值区域&lpar;文字区域定位&rpar;算法 附完整C代码

mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...

经典傅里叶算法小集合 附完整c代码

前面写过关于傅里叶算法的应用例子. 当然也就是举个例子,主要是学习傅里叶变换. 这个重采样思路还有点瑕疵, 稍微改一下,就可以支持多通 ...

自动曝光修复算法 附完整C代码

众所周知, 图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...

基于傅里叶变换的音频重采样算法 &lpar;附完整c代码&rpar;

前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

随机推荐

Java 线程池框架核心代码分析--转

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值