From 58da7275a659c26b6a1fd9ec07e76f4cf521375e Mon Sep 17 00:00:00 2001
From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674>
Date: 星期三, 04 一月 2017 18:16:35 +0800
Subject: [PATCH] add dlib face trace
---
RtspFace/make.sh | 44 +++--
RtspFace/PL_SensetimeFaceTrack.h | 6
RtspFace/PL_SensetimeFaceTrack.cpp | 4
RtspFace/PL_DlibFaceTrack.cpp | 309 ++++++++++++++++++++++++++++++++++++++++++++
RtspFace/main.cpp | 18 ++
RtspFace/PL_AVFrameBGRA.cpp | 4
RtspFace/PL_DlibFaceTrack.h | 33 ++++
7 files changed, 390 insertions(+), 28 deletions(-)
diff --git a/RtspFace/PL_AVFrameBGRA.cpp b/RtspFace/PL_AVFrameBGRA.cpp
index 7ec2d11..0826c5b 100644
--- a/RtspFace/PL_AVFrameBGRA.cpp
+++ b/RtspFace/PL_AVFrameBGRA.cpp
@@ -7,10 +7,10 @@
#include <libavcodec/avcodec.h>
#include <libavutil/frame.h>
#include <libavformat/avformat.h>
-
- #include <libyuv.h>
}
+#include <libyuv.h>
+
struct PL_AVFrameBGRA_Internal
{
uint8_t buffer[1920*1080*4];//#todo from config
diff --git a/RtspFace/PL_DlibFaceTrack.cpp b/RtspFace/PL_DlibFaceTrack.cpp
new file mode 100644
index 0000000..5c5dcea
--- /dev/null
+++ b/RtspFace/PL_DlibFaceTrack.cpp
@@ -0,0 +1,309 @@
+#include "PL_DlibFaceTrack.h"
+#include "MaterialBuffer.h"
+#include "logger.h"
+
+#include <opencv2/opencv.hpp>
+#include <opencv2/highgui/highgui.hpp>
+
+#include <dlib/opencv.h>
+#include <dlib/image_processing/frontal_face_detector.h>
+#include <dlib/image_processing/render_face_detections.h>
+#include <dlib/image_processing.h>
+#include <dlib/gui_widgets.h>
+
+#include <libyuv.h>
+
+#define DLIB_POSE_MODEL_PATH "/opt/dlib/models/shape_predictor_68_face_landmarks.dat"
+
+struct PL_DlibFaceTrack_Internal
+{
+ //uint8_t buffer[1920*1080*4];
+ //size_t buffSize;
+ //size_t buffSizeMax;
+ MB_Frame lastFrame;
+ PL_DlibFaceTrack_Config config;
+
+ bool payError;
+
+ dlib::frontal_face_detector detector; // #todo reset
+ dlib::shape_predictor pose_model;
+
+ PL_DlibFaceTrack_Internal() :
+ //buffSize(0), buffSizeMax(sizeof(buffer)),
+ lastFrame(), config(), payError(true)
+ {
+ }
+
+ ~PL_DlibFaceTrack_Internal()
+ {
+ }
+
+ void reset()
+ {
+ //buffSize = 0;
+ payError = true;
+
+ MB_Frame _lastFrame;
+ lastFrame = _lastFrame;
+ PL_DlibFaceTrack_Config _config;
+ config = _config;
+ }
+};
+
+PipeLineElem* create_PL_DlibFaceTrack()
+{
+ return new PL_DlibFaceTrack;
+}
+
+PL_DlibFaceTrack::PL_DlibFaceTrack() : internal(new PL_DlibFaceTrack_Internal)
+{
+}
+
+PL_DlibFaceTrack::~PL_DlibFaceTrack()
+{
+ delete (PL_DlibFaceTrack_Internal*)internal;
+ internal= nullptr;
+}
+
+bool PL_DlibFaceTrack::init(void* args)
+{
+ PL_DlibFaceTrack_Internal* in = (PL_DlibFaceTrack_Internal*)internal;
+ in->reset();
+
+ PL_DlibFaceTrack_Config* config = (PL_DlibFaceTrack_Config*)args;
+ if (config != nullptr)
+ in->config = *config;
+
+#ifdef __AVX__
+ LOG_DEBUG << "AVX on";
+ #ifdef DLIB_HAVE_SSE2
+ LOG_DEBUG << "DLIB_HAVE_SSE2 on";
+ #endif
+ #ifdef DLIB_HAVE_SSE3
+ LOG_DEBUG << "DLIB_HAVE_SSE3 on";
+ #endif
+ #ifdef DLIB_HAVE_SSE41
+ LOG_DEBUG << "DLIB_HAVE_SSE41 on";
+ #endif
+ #ifdef DLIB_HAVE_AVX
+ LOG_DEBUG << "DLIB_HAVE_AVX on";
+ #endif
+#endif
+
+ in->detector = dlib::get_frontal_face_detector();
+ dlib::deserialize(DLIB_POSE_MODEL_PATH) >> in->pose_model;
+
+ return true;
+}
+
+void PL_DlibFaceTrack::finit()
+{
+ PL_DlibFaceTrack_Internal* in = (PL_DlibFaceTrack_Internal*)internal;
+
+}
+
+uint64_t time_msec()
+{
+ timeval tv;
+ gettimeofday(&tv, nullptr);
+
+ return (tv.tv_sec * 1000 * 1000 + tv.tv_usec) / 1000;
+}
+
+int doFaceTrack(PL_DlibFaceTrack_Internal* in,
+ uint8_t* buffer, size_t width, size_t height, MB_Frame::MBFType pixFmt)
+{
+ uint64_t tbegin = time_msec();
+
+ //uint8_t* pBuffer = new uint8_t[width * height * 3];
+
+ //#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a))
+
+ //libyuv::I420ToRGB24(buffer, width,
+ // buffer + width * height, SUBSAMPLE(width, 2),
+ // buffer + width * height + width * height / 4, SUBSAMPLE(width, 2),
+ // pBuffer, 3 * width,
+ // width, height);
+
+ //#test
+ //static size_t f=0;
+ //char fname[50];
+ //sprintf(fname, "%u.rgb", ++f);
+ //FILE * pFile = fopen (fname, "wb");
+ //fwrite (pBuffer , sizeof(char), width * height * 4, pFile);
+ //fclose(pFile);
+
+ cv::Mat yMat(cv::Size(width,height), CV_8UC1, buffer);
+ //cv::Mat rgbMat(cv::Size(width,height), CV_8UC3, pBuffer);
+
+ //dlib::cv_image<dlib::bgr_pixel> rgbImg(rgbMat);
+ dlib::cv_image<unsigned char> yImg(yMat);
+
+ dlib::array2d<unsigned char> downImg;
+ // Call pyr N times should have the same result, but one time may be faster
+
+ switch(in->config.pyramid_down_layers)
+ {
+ case 2:
+ {
+ // best for 800x600 image on a 2-core Intel(R) Xeon(R) CPU E3-1220 v5 @ 3.00GHz in VMware
+ // face distance from camera is about 50cm
+ dlib::pyramid_down<2> pyr;
+ if (in->config.pyramid_down_n >= 1)
+ {
+ pyr(yImg, downImg);
+ for(uint8_t i = 0; i < in->config.pyramid_down_n - 1; i++)
+ pyr(downImg, downImg);
+ }
+ }
+ break;
+ case 3:
+ {
+ dlib::pyramid_down<3> pyr;
+ pyr(yImg, downImg);
+ if (in->config.pyramid_down_n >= 1)
+ {
+ pyr(yImg, downImg);
+ for(uint8_t i = 0; i < in->config.pyramid_down_n - 1; i++)
+ pyr(downImg, downImg);
+ }
+ }
+ case 4:
+ {
+ dlib::pyramid_down<4> pyr;
+ pyr(yImg, downImg);
+ if (in->config.pyramid_down_n >= 1)
+ {
+ pyr(yImg, downImg);
+ for(uint8_t i = 0; i < in->config.pyramid_down_n - 1; i++)
+ pyr(downImg, downImg);
+ }
+ }
+ break;
+ case 0:
+ default:
+ // do nothing
+ break;
+ }
+
+ LOGP(DEBUG, "downImg L=%u, n=%u, nr=%u, nc=%u",
+ in->config.pyramid_down_layers, in->config.pyramid_down_n, downImg.nr(), downImg.nc());
+
+ //LOGP(DEBUG, "doFaceTrack time1=%llu (ms)", time_msec() - tbegin);
+
+ uint8_t factPosFactor = 0;
+ if (downImg.nr() > 0 && downImg.nc() > 0)
+ factPosFactor = width / downImg.nc();
+
+ // Detect faces
+ std::vector<dlib::rectangle> faces;
+ if (factPosFactor > 0)
+ faces = in->detector(downImg);
+ else
+ faces = in->detector(yImg);
+
+ //LOGP(DEBUG, "doFaceTrack time2=%llu (ms)", time_msec() - tbegin);
+
+ // Find the pose of each face.
+ std::vector<dlib::full_object_detection> shapes;
+ for (unsigned long i = 0; i < faces.size(); ++i)
+ {
+ dlib::full_object_detection posePoint;
+ if (factPosFactor > 0)
+ {
+ posePoint = in->pose_model(downImg, faces[i]);
+
+ for (size_t i = 0; i < 68; i++)
+ posePoint.part(i) = dlib::point(posePoint.part(i).x() * factPosFactor, posePoint.part(i).y() * factPosFactor);
+ }
+ else
+ {
+ posePoint = in->pose_model(yImg, faces[i]);
+ }
+
+ shapes.push_back(posePoint);
+
+ if (factPosFactor > 0)
+ {
+ faces[i].set_left(faces[i].left() * factPosFactor);
+ faces[i].set_top(faces[i].top() * factPosFactor);
+ faces[i].set_right(faces[i].right() * factPosFactor);
+ faces[i].set_bottom(faces[i].bottom() * factPosFactor);
+ }
+
+ LOGP(DEBUG, "face: %d, poseLTRB: [%d, %d, %d, %d]", i,
+ faces[i].left(), faces[i].top(), faces[i].right(), faces[i].bottom());
+
+ cv::rectangle(yMat,
+ cv::Point2i(faces[i].left(), faces[i].top()),
+ cv::Point2i(faces[i].right(), faces[i].bottom()), CV_RGB(128, 128, 128), 2);
+
+ for (int i = 0; i < shapes.size(); i++)
+ {
+ for (int j = 0; j < 68; j++)
+ cv::circle(yMat, cvPoint(shapes[i].part(j).x(), shapes[i].part(j).y()), 2, cvScalar(255, 0, 0), -1);
+ }
+ }
+
+ LOGP(DEBUG, "doFaceTrack time3=%llu (ms)", time_msec() - tbegin);
+
+ return faces.size();
+}
+
+bool PL_DlibFaceTrack::pay(const PipeMaterial& pm)
+{
+ PL_DlibFaceTrack_Internal* in = (PL_DlibFaceTrack_Internal*)internal;
+
+ if (pm.type != PipeMaterial::PMT_FRAME)
+ {
+ LOG_ERROR << "Only support PMT_FRAME";
+ return false;
+ }
+
+ if (pm.buffer == nullptr)
+ return false;
+
+ MB_Frame* frame = (MB_Frame*)pm.buffer;
+ if (frame->type != MB_Frame::MBFT_YUV420)
+ {
+ LOG_ERROR << "Only support MBFT_YUV420";
+ return false;
+ }
+
+ int face_count = doFaceTrack(
+ in, (uint8_t*)frame->buffer, frame->width, frame->height, MB_Frame::MBFT_YUV420);
+ if (face_count < 0)
+ {
+ in->payError = true;
+ return false;
+ }
+ else
+ in->payError = false;
+
+ //in->buffer readly
+in->payError = false;//#todo
+ in->lastFrame.type = MB_Frame::MBFT_YUV420;
+ in->lastFrame.buffer = frame->buffer;//#todo should copy
+ in->lastFrame.buffSize = frame->buffSize;
+ in->lastFrame.width = frame->width;
+ in->lastFrame.height = frame->height;
+ in->lastFrame.pts = frame->pts;
+ gettimeofday(&(in->lastFrame.pts),NULL);
+
+ return true;
+}
+
+bool PL_DlibFaceTrack::gain(PipeMaterial& pm)
+{
+ PL_DlibFaceTrack_Internal* in = (PL_DlibFaceTrack_Internal*)internal;
+
+ if (!in->payError)
+ {
+ pm.type = PipeMaterial::PMT_FRAME;
+ pm.buffer = &(in->lastFrame);
+ pm.buffSize = 0;
+ pm.former = this;
+ }
+ pm.former = this;
+ return !in->payError;
+}
diff --git a/RtspFace/PL_DlibFaceTrack.h b/RtspFace/PL_DlibFaceTrack.h
new file mode 100644
index 0000000..158b5e8
--- /dev/null
+++ b/RtspFace/PL_DlibFaceTrack.h
@@ -0,0 +1,33 @@
+#ifndef _PL_DLIBFACETRACK_H_
+#define _PL_DLIBFACETRACK_H_
+
+#include "PipeLine.h"
+
+struct PL_DlibFaceTrack_Config
+{
+ uint8_t pyramid_down_layers;
+ uint8_t pyramid_down_n;
+
+ PL_DlibFaceTrack_Config() : pyramid_down_layers(0), pyramid_down_n(0)
+ { }
+};
+
+class PL_DlibFaceTrack : public PipeLineElem
+{
+public:
+ PL_DlibFaceTrack();
+ virtual ~PL_DlibFaceTrack();
+
+ virtual bool init(void* args);
+ virtual void finit();
+
+ virtual bool pay(const PipeMaterial& pm);
+ virtual bool gain(PipeMaterial& pm);
+
+private:
+ void* internal;
+};
+
+PipeLineElem* create_PL_DlibFaceTrack();
+
+#endif
diff --git a/RtspFace/PL_SensetimeFaceTrack.cpp b/RtspFace/PL_SensetimeFaceTrack.cpp
index 71cb4d3..541c79c 100644
--- a/RtspFace/PL_SensetimeFaceTrack.cpp
+++ b/RtspFace/PL_SensetimeFaceTrack.cpp
@@ -189,7 +189,7 @@
if (pm.type != PipeMaterial::PMT_FRAME)
{
- LOG_ERROR << "PL_H264Encoder::pay only support PMT_FRAME";
+ LOG_ERROR << "Only support PMT_FRAME";
return false;
}
@@ -199,7 +199,7 @@
MB_Frame* frame = (MB_Frame*)pm.buffer;
if (frame->type != MB_Frame::MBFT_YUV420)
{
- LOG_ERROR << "PL_H264Encoder::pay only support MBFT_YUV420";
+ LOG_ERROR << "Only support MBFT_YUV420";
return false;
}
diff --git a/RtspFace/PL_SensetimeFaceTrack.h b/RtspFace/PL_SensetimeFaceTrack.h
index 8ce9f5c..48030e8 100644
--- a/RtspFace/PL_SensetimeFaceTrack.h
+++ b/RtspFace/PL_SensetimeFaceTrack.h
@@ -1,5 +1,5 @@
-#ifndef _PL_PL_SENSETIMEFACETRACK_H_
-#define _PL_PL_SENSETIMEFACETRACK_H_
+#ifndef _PL_SENSETIMEFACETRACK_H_
+#define _PL_SENSETIMEFACETRACK_H_
#include "PipeLine.h"
@@ -34,6 +34,6 @@
void* internal;
};
-PipeLineElem* create_PL_SensetimeFaceDetect();
+PipeLineElem* create_PL_SensetimeFaceTrack();
#endif
diff --git a/RtspFace/main.cpp b/RtspFace/main.cpp
index 412c1ac..738b9b1 100644
--- a/RtspFace/main.cpp
+++ b/RtspFace/main.cpp
@@ -10,6 +10,8 @@
#include "PL_SensetimeFaceTrack.h"
+#include "PL_DlibFaceTrack.h"
+
#include "logger.h"
int main(int argc, char** argv)
@@ -27,6 +29,8 @@
pipeLine.register_elem_creator("PL_Scale", create_PL_Scale);
pipeLine.register_elem_creator("PL_SensetimeFaceTrack", create_PL_SensetimeFaceTrack);
+
+ pipeLine.register_elem_creator("PL_DlibFaceTrack", create_PL_DlibFaceTrack);
{
PL_RTSPClient* rtspClient = (PL_RTSPClient*)pipeLine.push_elem("PL_RTSPClient");
@@ -78,9 +82,17 @@
}
}
+ //{
+ // SensetimeFaceTrackConfig config;
+ // PL_SensetimeFaceTrack* pl = (PL_SensetimeFaceTrack*)pipeLine.push_elem("PL_SensetimeFaceTrack");
+ // pl->init(&config);
+ //}
+
{
- SensetimeFaceTrackConfig config;
- PL_SensetimeFaceTrack* pl = (PL_SensetimeFaceTrack*)pipeLine.push_elem("PL_SensetimeFaceTrack");
+ PL_DlibFaceTrack_Config config;
+ config.pyramid_down_layers = 2;
+ config.pyramid_down_n = 1;
+ PL_DlibFaceTrack* pl = (PL_DlibFaceTrack*)pipeLine.push_elem("PL_DlibFaceTrack");
pl->init(&config);
}
@@ -104,7 +116,7 @@
exit(EXIT_FAILURE);
}
}
-
+
{
PL_RTSPServer* rtspServer = (PL_RTSPServer*)pipeLine.push_elem("PL_RTSPServer");
bool ret = rtspServer->init(nullptr);
diff --git a/RtspFace/make.sh b/RtspFace/make.sh
index acdd829..c15d0d2 100644
--- a/RtspFace/make.sh
+++ b/RtspFace/make.sh
@@ -29,42 +29,50 @@
OPENCV_INC=
OPENCV_LIB="-lopencv_core"
+DLIB_BASE=/opt/dlib
+DLIB_INC="-I$DLIB_BASE"
+DLIB_LIB="-L$DLIB_BASE/build/dlib -ldlib"
+
LIBLOG4CPP_BASE=/opt/log4cpp/inst
LIBLOG4CPP_INC="-I$LIBLOG4CPP_BASE/include"
LIBLOG4CPP_LIB="-L$LIBLOG4CPP_BASE/lib -llog4cpp"
-CPPFLAGS+="-pthread $LIVEMEDIA_INC $FFMPEG_INC $LIBBASE64_INC $LIBYUV_INC $SENSETIMEFACESDK_INC $LIBLOG4CPP_INC"
-LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB $LIBX264_LIB $SENSETIMEFACESDK_LIB $OPENCV_LIB $LIBLOG4CPP_LIB"
+# -O3
+CPPFLAGS+="-g -mavx -c -std=c++11 -pthread $LIVEMEDIA_INC $FFMPEG_INC $LIBBASE64_INC $LIBYUV_INC $SENSETIMEFACESDK_INC $LIBLOG4CPP_INC $DLIB_INC"
+LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB $LIBX264_LIB $SENSETIMEFACESDK_LIB $OPENCV_LIB $LIBLOG4CPP_LIB $DLIB_LIB"
CFLAGS+="-D__STDC_CONSTANT_MACROS"
rm rtsp_face
rm *.o
-g++ -g -c -std=c++11 main.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PipeLine.cpp $CFLAGS $CPPFLAGS
+g++ main.cpp $CFLAGS $CPPFLAGS
+g++ PipeLine.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_RTSPClient.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_RTSPServer.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_H264Decoder.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_H264Encoder.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_AVFrameYUV420.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_AVFrameBGRA.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_Queue.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_Scale.cpp $CFLAGS $CPPFLAGS
+g++ PL_RTSPClient.cpp $CFLAGS $CPPFLAGS
+g++ PL_RTSPServer.cpp $CFLAGS $CPPFLAGS
+g++ PL_H264Decoder.cpp $CFLAGS $CPPFLAGS
+g++ PL_H264Encoder.cpp -O3 $CFLAGS $CPPFLAGS
+g++ PL_AVFrameYUV420.cpp $CFLAGS $CPPFLAGS
+g++ PL_AVFrameBGRA.cpp $CFLAGS $CPPFLAGS
+g++ PL_Queue.cpp $CFLAGS $CPPFLAGS
+g++ PL_Scale.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_SensetimeFaceTrack.cpp $CFLAGS $CPPFLAGS
+g++ PL_SensetimeFaceTrack.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 $FFMPEGRTSPSERVER_BASE/FFmpegH264Source.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 $FFMPEGRTSPSERVER_BASE/LiveRTSPServer.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 $FFMPEGRTSPSERVER_BASE/LiveServerMediaSubsession.cpp $CFLAGS $CPPFLAGS
+g++ PL_DlibFaceTrack.cpp -O3 $CFLAGS $CPPFLAGS
+
+g++ $FFMPEGRTSPSERVER_BASE/FFmpegH264Source.cpp $CFLAGS $CPPFLAGS
+g++ $FFMPEGRTSPSERVER_BASE/LiveRTSPServer.cpp $CFLAGS $CPPFLAGS
+g++ $FFMPEGRTSPSERVER_BASE/LiveServerMediaSubsession.cpp $CFLAGS $CPPFLAGS
g++ -g -std=c++11 \
main.o PipeLine.o \
PL_RTSPClient.o PL_H264Decoder.o PL_H264Encoder.o PL_AVFrameYUV420.o PL_AVFrameBGRA.o PL_Queue.o PL_Scale.o \
PL_SensetimeFaceTrack.o \
+ PL_DlibFaceTrack.o \
$FFMPEGRTSPSERVER_OBJ PL_RTSPServer.o \
$LDFLAGS -o rtsp_face
-#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBX264_BASE/lib:$FFMPEG_BASE/lib:$SENSETIMEFACESDK_BASE/libs/linux-x86_64:$LIBLOG4CPP_BASE/lib
-#./rtsp_face rtsp://admin:admin12345@192.168.1.64:554/h264/ch1/main/av_stream
+#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBX264_BASE/lib:$FFMPEG_BASE/lib:$SENSETIMEFACESDK_BASE/libs/linux-x86_64:$LIBLOG4CPP_BASE/lib:$DLIB_BASE/build/dlib
+#./rtsp_face rtsp://admin:admin12345@192.168.1.70:554/h264/ch1/main/av_stream
--
Gitblit v1.8.0