1、源碼下載
直接從github上克隆項目倉庫。
git clone https://github.com/ShiqiYu/libfacedetection.git
2、編譯
2.1、linux
這個項目使用了cmake腳本,先生成makefile。(我這里是在ArchLinux x86_64環境下測試的)
cmake -DENABLE_NEON=OFF -DCMAKE_BUILD_TYPE=RELEASE .
執行上面的命令成功后,執行下面語句進行編譯
make -j4
編譯完成后會同時生成動態庫和靜態庫
[ 90%] Linking CXX static library libfacedetection.a
[100%] Linking CXX shared library libfacedetection.so
2.2、Windows MINGW64
這里和上面也是一樣的。先使用cmake
生產Makefile
文件,然后執行編譯即可。這里我指定了使用g++
作為C++的編譯器,因為如果不指定會使用gcc
去鏈接,導致生成動態庫的時候找不到c++
標准庫的一些定義。
cmake -DENABLE_NEON=OFF -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_CXX_COMPILER=g++ .
其它的與上面linux的一致。
備注:我這里使用的是MSYS2環境,直接使用pacman命令安裝的gcc/g++。
2.3、VS2017 NMake編譯
因為就這么幾個文件,生成一個龐大的VS工程實在有點多余,所以我簡單寫了一個Makefile.vc
文件,使用nmake
腳本來生成靜態庫(因為源碼中並沒有對函數接口進行export,所以只生成靜態庫)。
Makefile.vc 文件內容如下:
# 編譯參數設置
CXX = cl
DEFINES = -DWIN32 -DWIN64 -DNDEBUG -D_WINDLL
CXXFLAGS = -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -EHsc $(DEFINES)
INCPATH = -I.
LIBEXE = lib
LIBFLAGS = /NOLOGO
LIBS = kernel32.lib
# 源文件
SOURCES = facedetectcnn.cpp \
facedetectcnn-floatdata.cpp \
facedetectcnn-int8data.cpp \
facedetectcnn-model.cpp
OBJECTS = facedetectcnn.obj \
facedetectcnn-floatdata.obj \
facedetectcnn-int8data.obj \
facedetectcnn-model.obj
# 輸出目標文件
DESTDIR_TARGET = libfacedetection.lib
# 編譯規則
.cpp.obj::
$(CXX) @<< -c $(CXXFLAGS) $(INCPATH) $<
<<
all: $(DESTDIR_TARGET)
$(DESTDIR_TARGET): $(OBJECTS)
$(LIBEXE) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) $(LIBS) $(OBJECTS)
facedetectcnn.obj: facedetectcnn.cpp facedetectcnn.h
facedetectcnn-floatdata.obj: facedetectcnn-floatdata.cpp facedetectcnn.h
facedetectcnn-int8data.obj: facedetectcnn-int8data.cpp facedetectcnn.h
facedetectcnn-model.obj: facedetectcnn-model.cpp facedetectcnn.h
clean:
del /Q $(OBJECTS)
在VS2017開發者命令行工具中
直接使用nmake
命令來生成靜態庫
nmake -f Makefile.vc
3、簡單測試程序
使用Qt寫了一個小程序,簡單的測試了一下。
測試的時候發現年齡始終是0
,然后就看了一下源碼,發現其並未對年齡和面部特征點進行輸出,實際在代碼中也沒有進行檢測,年齡和面部特征點相關的代碼我沒有找到(2019年4月16日)。
3.1、測試截圖
3.2、測試代碼如下
/*****************************************************
* project:libfacedetection 測試代碼 *
* anchor:ymwh@foxmail.com/solym@sohu.com *
* date:2019-4-16 *
*****************************************************/
#include <facedetectcnn.h>
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFileDialog>
#include <QPainter>
#include <QGraphicsView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QImage srcImage;
// 創建窗口
QWidget widget;
// 添加控件
QGraphicsScene* gsViewScene = new QGraphicsScene();
gsViewScene->setItemIndexMethod(QGraphicsScene::NoIndex);
QGraphicsView* gvImageView = new QGraphicsView(&widget);
gvImageView->setScene(gsViewScene);
QLineEdit* leImagePath = new QLineEdit(&widget);
QPushButton* pbSelectFile = new QPushButton(QStringLiteral("選擇文件"),&widget);
QPushButton* pbRunDetect = new QPushButton(QStringLiteral("執行檢測"),&widget);
pbRunDetect->setEnabled(false);
QHBoxLayout* hbLayout = new QHBoxLayout;
// 設置布局
hbLayout->addWidget(leImagePath);
hbLayout->addWidget(pbSelectFile);
hbLayout->addWidget(pbRunDetect);
QVBoxLayout* vbLayout = new QVBoxLayout(&widget);
vbLayout->addLayout(hbLayout);
vbLayout->addWidget(gvImageView);
// 添加處理操作
QObject::connect(pbSelectFile,&QPushButton::clicked,
[leImagePath,gvImageView,gsViewScene,pbRunDetect,&srcImage,&widget]()
{
static QString path;
path = QFileDialog::getOpenFileName(&widget,
QStringLiteral("選擇人像圖"),
path,
QString("Images (*.png *.jpg *.jpeg *.jfif)"));
if(path.isEmpty()){return;}
QImage image;
if(!image.load(path)){return;}
// 圖像太大的時候,執行太慢,先縮小一點
if(image.width() > 2048){ image = image.scaledToWidth(2048); }
if(image.width() > 1536){ image = image.scaledToWidth(1536); }
srcImage.swap(image);
leImagePath->setText(path);
gsViewScene->clear();
gsViewScene->setSceneRect(srcImage.rect());
gsViewScene->addPixmap(QPixmap::fromImage(srcImage));
gvImageView->fitInView(gvImageView->sceneRect());
pbRunDetect->setEnabled(true);
});
QObject::connect(pbRunDetect,&QPushButton::clicked,
[gvImageView,gsViewScene,&srcImage]
{
// 轉換為RGB24
QImage image = srcImage.convertToFormat(QImage::Format_RGB888);
int rows = image.height();
int cols = image.width();
int rowbytes = image.bytesPerLine();
uchar* pImgData = image.bits();
// RGB -> BGR 因為facedetect_cnn函數要求傳入圖像為BGR三波段圖像
for( int r = 0; r < rows; ++r ){
uchar* pRow = pImgData + (r * rowbytes);
for(int c = 0; c < cols; ++c ){
qSwap(pRow[c*3],pRow[c*3+2]);
}
}
// 進行檢測
QByteArray buffer(0x20000,0);
int* pResults = facedetect_cnn((uchar*)buffer.data(),pImgData,cols,rows,rowbytes);
// 將檢測結果畫到圖像上
QPixmap pixmap = QPixmap::fromImage(srcImage);
if(pResults != NULL) {
for(int i=0; i< *pResults; ++i) {
short * p = ((short*)(pResults+1))+142*i;
int x = p[0];
int y = p[1];
int w = p[2];
int h = p[3];
int confidence = p[4];
// 查看源碼可知,其並未進行人像框范圍和置信率以外的數據賦值
int angle = p[5];
QPainter painter(&pixmap);
// painter.setBrush(QBrush(QColor(255,0,0),));
painter.setPen(Qt::green);
// painter.drawEllipse(x,y,w,h);
painter.drawRect(x,y,w,h);
painter.drawText(x,y,w,h,Qt::AlignCenter,
QStringLiteral("置信:%1%\n年齡:%2").arg(confidence).arg(angle));
}
}
gsViewScene->clear();
gsViewScene->setSceneRect(pixmap.rect());
gsViewScene->addPixmap(pixmap);
gvImageView->fitInView(gvImageView->sceneRect());
});
widget.resize(1024,768);
widget.show();
return a.exec();
}