0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MTCNN人臉檢測的詳細介紹及完整C++代碼你能學會嗎?

C語言專家集中營 ? 來源:未知 ? 作者:易水寒 ? 2018-07-09 11:02 ? 次閱讀

人臉檢測識別一直是圖像算法領域一個主流話題。

前年SeetaFace開源了人臉識別引擎,一度成為熱門話題。

雖然后來SeetaFace又放出來 2.0版本,但是,我說但是。。。

沒有訓練代碼,想要自己訓練一下模型那可就犯難了。

雖然可以閱讀源碼,從前向傳播的角度,反過來實現(xiàn)訓練代碼,

但是誰有那個閑功夫和時間,去折騰這個呢?

有的時候還是要站在巨人的肩膀上,你才能看得更遠。

而SeetaFace不算巨人,只是當年風口上的豬罷了。

前年,為了做一個人臉項目,也是看遍了網上各種項目。

林林總總,各有優(yōu)劣。

不多做評價,很多東西還是要具體實操,實戰(zhàn)才能見真知。

有一段時間,用SeetaFace的人臉檢測來做一些小的演示demo,

也花了一點小時間去優(yōu)化它的算法。

不過很明顯我只是把他當成玩具看待。

畢竟不能自己訓練模型,這是很大的詬病。

直到后來深度學習大放異彩,印象最深刻莫過于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的思路可以拓展到各種物體檢測和識別方向。

也許唯一缺少的就是打標好的數(shù)據(jù),

而標注五個點,足夠用于適配大多數(shù)物體了。

符合小而美的理念,這個是我比較推崇的。

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

github上也有不少MTCNN的實現(xiàn)和資源。

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

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

果斷拋棄了。

ncnn有點肥大,不合我心。

所以,我動了殺氣。。

移除NCNN與mtcnn無關的層,

梳理ncnn的一些邏輯代碼。

簡單做了一些適配和優(yōu)化。

砍掉一些邊邊角角。

不依賴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"http://ref:https://github.com/nothings/stb/blob/master/stb_image.h#define TJE_IMPLEMENTATION#include "tiny_jpeg.h"http://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 = '