From 31e0d0c171b4d6a7dc9b9697e69e165651d3fe93 Mon Sep 17 00:00:00 2001 From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674> Date: 星期三, 28 十二月 2016 18:32:20 +0800 Subject: [PATCH] face detect ok --- RtspFace/make.sh | 19 +++ RtspFace/PL_H264Decoder.cpp | 13 + RtspFace/main.cpp | 38 ++++-- RtspFace/PL_H264Encoder.cpp | 34 +++++- RtspFace/PL_SensetimeFaceDetect.h | 11 ++ RtspFace/PL_AVFrameYUV420.cpp | 12 +- RtspFace/PL_SensetimeFaceDetect.cpp | 155 +++++++++++++++++++++++++++--- 7 files changed, 230 insertions(+), 52 deletions(-) diff --git a/RtspFace/PL_AVFrameYUV420.cpp b/RtspFace/PL_AVFrameYUV420.cpp index 5462ba9..495a852 100644 --- a/RtspFace/PL_AVFrameYUV420.cpp +++ b/RtspFace/PL_AVFrameYUV420.cpp @@ -113,12 +113,12 @@ in->lastFrame.pts = frame->pts; //#test - static size_t f=0; - char fname[50]; - sprintf(fname, "%u.yuv420", ++f); - FILE * pFile = fopen (fname,"wb"); - fwrite (in->buffer , sizeof(char), in->buffSize, pFile); - fclose(pFile); + //static size_t f=0; + //char fname[50]; + //sprintf(fname, "%u.yuv420", ++f); + //FILE * pFile = fopen (fname,"wb"); + //fwrite (in->buffer , sizeof(char), in->buffSize, pFile); + //fclose(pFile); return true; } diff --git a/RtspFace/PL_H264Decoder.cpp b/RtspFace/PL_H264Decoder.cpp index 7a3b705..11ae388 100644 --- a/RtspFace/PL_H264Decoder.cpp +++ b/RtspFace/PL_H264Decoder.cpp @@ -162,7 +162,7 @@ return true; } -bool decodeH264(H264Decoder_Internal* in, uint8_t* buffer, size_t buffSize) +bool decodeH264(H264Decoder_Internal* in, uint8_t* buffer, size_t buffSize, timeval pts) { AVPacket packet = {0}; int gotPicture = buffSize; // frameFinished @@ -171,7 +171,9 @@ { printf("av_packet_from_data error\n"); return false; - } + } + + packet.pts = packet.dts = (pts.tv_sec * 1000 * 1000 + pts.tv_usec) / 90000; // decode avcodec_decode_video2(in->pAVCodecContext, in->pAVFrame, &gotPicture, &packet); @@ -222,12 +224,15 @@ bool ret = false; if (pm.type == PipeMaterial::PMT_BYTES) - ret = decodeH264(in, pm.buffer, pm.buffSize); + { + timeval pts = {0}; + ret = decodeH264(in, pm.buffer, pm.buffSize, pts); + } else if (pm.type == PipeMaterial::PMT_FRAME) { MB_Frame* frame = (MB_Frame*)pm.buffer; - ret = decodeH264(in, frame->buffer, frame->buffSize); + ret = decodeH264(in, frame->buffer, frame->buffSize, frame->pts); if (ret) { in->lastFrame.type = MB_Frame::MBFT_PTR_AVFRAME; diff --git a/RtspFace/PL_H264Encoder.cpp b/RtspFace/PL_H264Encoder.cpp index 5547256..33ffc40 100644 --- a/RtspFace/PL_H264Encoder.cpp +++ b/RtspFace/PL_H264Encoder.cpp @@ -5,8 +5,9 @@ { #include <libavcodec/avcodec.h> #include <libavutil/frame.h> - #include <libavformat/avformat.h> #include <libavutil/imgutils.h> + #include <libavutil/opt.h> + #include <libavformat/avformat.h> #include <libyuv.h> } @@ -104,11 +105,12 @@ in->pAVCodecContext->height = 600;//#todo from config in->pAVCodecContext->time_base.num=1; in->pAVCodecContext->time_base.den=25; - in->pAVCodecContext->gop_size = 25; + in->pAVCodecContext->gop_size = 2; in->pAVCodecContext->max_b_frames = 0; + //in->pAVCodecContext->profile = FF_PROFILE_H264_MAIN; in->pAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P; - //av_opt_set(c->priv_data, "preset", "superfast", 0); + av_opt_set(in->pAVCodecContext->priv_data, "preset", "superfast", 0); //av_opt_set(c->priv_data, "tune", "zerolatency", 0); if(avcodec_open2(in->pAVCodecContext, avCodec, NULL) >= 0) @@ -261,6 +263,17 @@ return !(in->payError); } +bool encodeH264(H264Encoder_Internal* in, uint8_t* buffer, timeval pts) +{ + AVFrame avFrame; + avFrame.width = 1920;//#todo + avFrame.height = 1080; + avFrame.data[0] = buffer; + avFrame.data[1] = buffer + 1920*1080; + avFrame.data[2] = buffer + 1920*1080 + 1920*1080/4; + return encodeH264(in, &avFrame, pts); +} + bool PL_H264Encoder::pay(const PipeMaterial& pm) { H264Encoder_Internal* in = (H264Encoder_Internal*)internal; @@ -289,13 +302,20 @@ return false; MB_Frame* frame = (MB_Frame*)pm.buffer; - if (frame->type != MB_Frame::MBFT_PTR_AVFRAME) + + bool ret; + + if (frame->type == MB_Frame::MBFT_PTR_AVFRAME) + ret = encodeH264(in, (AVFrame*)(frame->buffer), frame->pts); + else if (frame->type == MB_Frame::MBFT_YUV420) + ret = encodeH264(in, (uint8_t*)(frame->buffer), frame->pts); + else { - printf("PL_H264Encoder::pay only support MBFT_PTR_AVFRAME\n"); + printf("PL_H264Encoder::pay only support MBFT_PTR_AVFRAME / MBFT_YUV420\n"); + in->payError = true; return false; } - - bool ret = encodeH264(in, (AVFrame*)(frame->buffer), frame->pts); + in->payError = !ret; if (ret) diff --git a/RtspFace/PL_SensetimeFaceDetect.cpp b/RtspFace/PL_SensetimeFaceDetect.cpp index 5df118c..f6b22c1 100644 --- a/RtspFace/PL_SensetimeFaceDetect.cpp +++ b/RtspFace/PL_SensetimeFaceDetect.cpp @@ -1,20 +1,25 @@ #include "PL_SensetimeFaceDetect.h" +#include "MaterialBuffer.h" #include <opencv2/opencv.hpp> #include <cv_face.h> struct PL_SensetimeFaceDetect_Internal { - uint8_t buffer[1920*1080*4]; - size_t buffSize; - size_t buffSizeMax; + //uint8_t buffer[1920*1080*4]; + //size_t buffSize; + //size_t buffSizeMax; MB_Frame lastFrame; + SensetimeFaceDetectConfig config; bool payError; + cv_handle_t handle_track; + PL_SensetimeFaceDetect_Internal() : - buffSize(0), buffSizeMax(sizeof(buffer)), lastFrame(), - payError(true) + //buffSize(0), buffSizeMax(sizeof(buffer)), + lastFrame(), config(), payError(true), + handle_track(nullptr) { } @@ -24,11 +29,15 @@ void reset() { - buffSize = 0; + //buffSize = 0; payError = true; MB_Frame _lastFrame; lastFrame = _lastFrame; + SensetimeFaceDetectConfig _config; + config = _config; + + handle_track = nullptr; } }; @@ -52,6 +61,37 @@ PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; in->reset(); + SensetimeFaceDetectConfig* config = (SensetimeFaceDetectConfig*)args; + in->config = *config; + if (in->config.point_size == 21) + in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_21; + else if (in->config.point_size == 106) + in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_106; + else + { + printf("alignment point size must be 21 or 106\n"); + return false; + } + + // init handle + cv_result_t cv_result = cv_face_create_tracker(&(in->handle_track), nullptr, + in->config.point_size_config | CV_FACE_TRACKING_TWO_THREAD); + if (cv_result != CV_OK) + { + printf("cv_face_create_tracker failed, error code %d\n", cv_result); + return false; + } + + int val = 0; + cv_result = cv_face_track_set_detect_face_cnt_limit(in->handle_track, in->config.detect_face_cnt_limit, &val); + if (cv_result != CV_OK) + { + printf("cv_face_track_set_detect_face_cnt_limit failed, error : %d\n", cv_result); + return false; + } + else + printf("detect face count limit : %d\n", val); + return true; } @@ -59,6 +99,78 @@ { PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; + // destroy track handle + cv_face_destroy_tracker(in->handle_track); + in->handle_track = nullptr; +} + +int doFaceDetect(PL_SensetimeFaceDetect_Internal* in, + uint8_t* buffer, size_t width, size_t height, size_t stride, cv_pixel_format cvPixFmt) +{ + //resize(bgr_frame, bgr_frame, Size(frame_width, frame_height), 0, 0, INTER_LINEAR); + + int face_count = 0; + cv_result_t cv_result = CV_OK; + cv_face_t* p_face = nullptr; + + // realtime track + cv_result = cv_face_track(in->handle_track, buffer, cvPixFmt, + width, height, stride, + CV_FACE_UP, &p_face, &face_count); + if (cv_result != CV_OK) + { + printf("cv_face_track failed, error : %d\n", cv_result); + cv_face_release_tracker_result(p_face, face_count); + return -1; + } + + // draw the video + cv::Mat yuvMat(cv::Size(1920,1080), CV_8UC3, buffer); + cv::Mat yMat(cv::Size(1920,1080), CV_8UC1, buffer); + for (int i = 0; i < face_count; i++) + { + printf("face: %d-----[%d, %d, %d, %d]-----id: %d\n", i, + p_face[i].rect.left, p_face[i].rect.top, + p_face[i].rect.right, p_face[i].rect.bottom, p_face[i].ID); + + printf("face pose: [yaw: %.2f, pitch: %.2f, roll: %.2f, eye distance: %.2f]\n", + p_face[i].yaw, + p_face[i].pitch, p_face[i].roll, p_face[i].eye_dist); + + cv::Scalar scalar_color = CV_RGB(p_face[i].ID * 53 % 256, + p_face[i].ID * 93 % 256, + p_face[i].ID * 143 % 256); + + //cv::rectangle(yMat, cv::Point2f(0, 0), cv::Point2f(50, 50), scalar_color, 2); + //cv::rectangle(yMat, cv::Point2f(500, 500), cv::Point2f(550, 550), scalar_color, 2); + + cv::rectangle(yMat, cv::Point2f(static_cast<float>(p_face[i].rect.left), + static_cast<float>(p_face[i].rect.top)), + cv::Point2f(static_cast<float>(p_face[i].rect.right), + static_cast<float>(p_face[i].rect.bottom)), scalar_color, 2); + + for (int j = 0; j < p_face[i].points_count; j++) + { + cv::circle(yMat, cv::Point2f(p_face[i].points_array[j].x, + p_face[i].points_array[j].y), 1, cv::Scalar(255, 255, 255)); + } + } + + //if (face_count > 0) + //{ + // static size_t f=0; + // char fname[50]; + // sprintf(fname, "face-%u.yuv420", ++f); + // FILE * pFile = fopen (fname,"wb"); + // fwrite (yuvMat.data , sizeof(char), 1920*1080*1.5, pFile); + // printf("write face file %s\n", fname); + // fclose(pFile); + //} + + // release the memory of face + cv_face_release_tracker_result(p_face, face_count); + + return face_count; } bool PL_SensetimeFaceDetect::pay(const PipeMaterial& pm) @@ -81,16 +193,21 @@ return false; } - + int face_count = doFaceDetect(in, frame->buffer, 1920, 1080, 1920, CV_PIX_FMT_YUV420P); + if (face_count < 0) + { + in->payError = true; + return false; + } + else + in->payError = false; //in->buffer readly - //static size_t f=0; - //char fname[50]; - //sprintf(fname, "%u.bgra", ++f); - //FILE * pFile = fopen (fname,"wb"); - //fwrite (in->buffer , sizeof(char), in->buffSize, pFile); - //fclose(pFile); + in->lastFrame.type = MB_Frame::MBFT_YUV420; + in->lastFrame.buffer = frame->buffer;//#todo should copy + in->lastFrame.buffSize = frame->buffSize; + in->lastFrame.pts = frame->pts; return true; } @@ -99,9 +216,13 @@ { PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; - pm.type = PipeMaterial::PMT_FRAME; - pm.buffer = (uint8_t*)(&(in->lastFrame)); - pm.buffSize = sizeof(in->lastFrame); + if (!in->payError) + { + pm.type = PipeMaterial::PMT_FRAME; + pm.buffer = (uint8_t*)(&(in->lastFrame)); + pm.buffSize = sizeof(in->lastFrame); + pm.former = this; + } pm.former = this; - return true; + return !in->payError; } diff --git a/RtspFace/PL_SensetimeFaceDetect.h b/RtspFace/PL_SensetimeFaceDetect.h index f1cdbb1..0d876c0 100644 --- a/RtspFace/PL_SensetimeFaceDetect.h +++ b/RtspFace/PL_SensetimeFaceDetect.h @@ -3,6 +3,17 @@ #include "PipeLine.h" +struct SensetimeFaceDetectConfig +{ + int point_size; // 21 / 106 + int point_size_config; // CV_DETECT_ENABLE_ALIGN_21 / CV_DETECT_ENABLE_ALIGN_106 + int detect_face_cnt_limit; // -1 + + SensetimeFaceDetectConfig() : + point_size(21), point_size_config(-1), detect_face_cnt_limit(-1) + { } +}; + class PL_SensetimeFaceDetect : public PipeLineElem { public: diff --git a/RtspFace/main.cpp b/RtspFace/main.cpp index b75f9ea..bf67254 100644 --- a/RtspFace/main.cpp +++ b/RtspFace/main.cpp @@ -7,6 +7,8 @@ #include "PL_AVFrameBGRA.h" #include "PL_Queue.h" +#include "PL_SensetimeFaceDetect.h" + #include <iostream> using namespace std; @@ -20,6 +22,8 @@ pipeLine.register_elem_creator("PL_AVFrameYUV420", create_PL_AVFrameYUV420); pipeLine.register_elem_creator("PL_H264Encoder", create_PL_H264Encoder); pipeLine.register_elem_creator("PL_Queue", create_PL_Queue); + + pipeLine.register_elem_creator("PL_SensetimeFaceDetect", create_PL_SensetimeFaceDetect); { PL_RTSPClient* rtspClient = (PL_RTSPClient*)pipeLine.push_elem("PL_RTSPClient"); @@ -48,6 +52,12 @@ avFrameYUV420->init(nullptr); } + { + SensetimeFaceDetectConfig config; + PL_SensetimeFaceDetect* stFaceDetect = (PL_SensetimeFaceDetect*)pipeLine.push_elem("PL_SensetimeFaceDetect"); + stFaceDetect->init(&config); + } + //{//#todo queue should support deep copy // PL_Queue_Config config; // PL_Queue* queue1 = (PL_Queue*)pipeLine.push_elem("PL_Queue"); @@ -59,21 +69,21 @@ // } //} - //{ - // PL_H264Encoder* h264Encoder = (PL_H264Encoder*)pipeLine.push_elem("PL_H264Encoder"); - // h264Encoder->init(nullptr); - //} + { + PL_H264Encoder* h264Encoder = (PL_H264Encoder*)pipeLine.push_elem("PL_H264Encoder"); + h264Encoder->init(nullptr); + } - //{ - // RTSPServerConfig config; - // PL_RTSPServer* rtspServer = (PL_RTSPServer*)pipeLine.push_elem("PL_RTSPServer"); - // bool ret = rtspServer->init(&config); - // if (!ret) - // { - // cout << "rtspServer.init error" << endl; - // exit(EXIT_FAILURE); - // } - //} + { + RTSPServerConfig config; + PL_RTSPServer* rtspServer = (PL_RTSPServer*)pipeLine.push_elem("PL_RTSPServer"); + bool ret = rtspServer->init(&config); + if (!ret) + { + cout << "rtspServer.init error" << endl; + exit(EXIT_FAILURE); + } + } while(true) { diff --git a/RtspFace/make.sh b/RtspFace/make.sh index 704fa7d..1fe8646 100644 --- a/RtspFace/make.sh +++ b/RtspFace/make.sh @@ -21,8 +21,16 @@ FFMPEGRTSPSERVER_BASE=./FFmpegRTSPServer FFMPEGRTSPSERVER_OBJ="FFmpegH264Source.o LiveRTSPServer.o LiveServerMediaSubsession.o" -CPPFLAGS+="-pthread $LIVEMEDIA_INC $FFMPEG_INC $LIBBASE64_INC $LIBYUV_INC" -LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB $LIBX264_LIB" +SENSETIMEFACESDK_BASE=/opt/SensetimeFaceSDK +SENSETIMEFACESDK_INC="-I$SENSETIMEFACESDK_BASE/include" +SENSETIMEFACESDK_LIB="-L$SENSETIMEFACESDK_BASE/libs/linux-x86_64 -lcvface_api" + +OPENCV_BASE= +OPENCV_INC= +OPENCV_LIB="-lopencv_core" + +CPPFLAGS+="-pthread $LIVEMEDIA_INC $FFMPEG_INC $LIBBASE64_INC $LIBYUV_INC $SENSETIMEFACESDK_INC" +LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB $LIBX264_LIB $SENSETIMEFACESDK_LIB $OPENCV_LIB" CFLAGS+="-D__STDC_CONSTANT_MACROS" @@ -30,6 +38,8 @@ rm *.o g++ -g -c -std=c++11 main.cpp $CFLAGS $CPPFLAGS +g++ -g -c -std=c++11 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 @@ -37,7 +47,7 @@ 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 PipeLine.cpp $CFLAGS $CPPFLAGS +g++ -g -c -std=c++11 PL_SensetimeFaceDetect.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 @@ -46,8 +56,9 @@ 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_SensetimeFaceDetect.o \ $FFMPEGRTSPSERVER_OBJ PL_RTSPServer.o \ $LDFLAGS -o rtsp_face -#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBX264_BASE/lib:$FFMPEG_BASE/lib +#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBX264_BASE/lib:$FFMPEG_BASE/lib:$SENSETIMEFACESDK_BASE/libs/linux-x86_64 #./rtsp_face rtsp://admin:admin12345@192.168.1.64:554/h264/ch1/main/av_stream -- Gitblit v1.8.0