pybind11—目標(biāo)跟蹤demo(深度學(xué)習(xí)人臉檢測(cè)跟蹤)

前言

人臉檢測(cè)跟蹤技術(shù)在監(jiān)控安防, 消費(fèi)領(lǐng)域用途廣泛, 比如手機(jī)上的人臉解鎖美顏App。 人臉檢測(cè)技術(shù)最經(jīng)典的算法之一——Haar Cascade Classifier級(jí)聯(lián)分類器在opencv中早已經(jīng)被集成,Haar特征比較簡(jiǎn)單,巧妙利于圖像積分圖進(jìn)行快速計(jì)算,但是缺點(diǎn)就是精度不高?;谏疃葘W(xué)習(xí)的目標(biāo)檢測(cè)算法層出不窮,猶如雨后春筍,人臉檢測(cè)由于其特殊性發(fā)展出了一系列專用的檢測(cè)算法,比如深度級(jí)聯(lián)人臉檢測(cè), MTCNN等。

MTCNN是基于深度學(xué)習(xí)的人臉檢測(cè)算法,MTCNN算法不僅包含人臉檢測(cè),還可以進(jìn)行人臉對(duì)齊(Face Alignment),細(xì)節(jié)不展開(kāi)敘述。

本文采用開(kāi)源的人臉檢測(cè)跟蹤工程,利用pybind11將其封裝為python接口,在python中實(shí)現(xiàn)人臉檢測(cè)跟蹤。

News! 2019-3-16最新最快的開(kāi)源人臉檢測(cè)libfacedetection python 接口實(shí)現(xiàn)了, 最快可以達(dá)到1500fps!, 詳細(xì)請(qǐng)見(jiàn):https://github.com/ShiqiYu/libfacedetection
本人編譯好的動(dòng)態(tài)鏈接庫(kù)python接口工程

image.png


開(kāi)發(fā)測(cè)試環(huán)境

  • windows 10, 64bit
  • Anaconda3, with pyhon 3.7
  • Visual Studio 2017
  • pycharm
  • opencv3.4.0
  • ncnn(tencent開(kāi)源深度學(xué)習(xí)庫(kù))

NCNN環(huán)境配置

步驟:

下載ncnn庫(kù):
https://github.com/Tencent/ncnn

使用cmake進(jìn)行編譯

使用visual studio編譯生成ncnn.lib

image.png
image.png

python API封裝

繼承faceTrack類, 將其封裝為python的類

PYBIND11_MODULE(face_tracking_demo, m) {
    
    NDArrayConverter::init_numpy();
    
    py::class_<FaceTracker>(m, "FaceTracker")
        .def(py::init<>())
        .def("trackerInit", &FaceTracker::trackerInit, py::arg("model_path"), py::arg("min_face"))
        .def("trackerUpdate", &FaceTracker::trackerUpdate, py::arg("img"));
}

demo.cpp



#include <opencv2/opencv.hpp>
#include"include/ncnn_mtcnn_tld_so.hpp"
#include <stdio.h>
#include<pybind11/pybind11.h>
#include<pybind11/stl.h>
#include<pybind11/numpy.h>

#include"ndarray_converter.h"

using namespace cv;
using namespace std;

namespace py = pybind11;

class FaceTracker :private faceTrack
{
public:
   FaceTracker() { faceTrack(); };
   ~FaceTracker() {};

public:
   void trackerInit(const std::string& model_path, const int min_face) {
       this->Init(model_path, min_face);
   }
   std::vector<int> trackerUpdate(cv::Mat& image) {
       cv::Rect rect;
       this->DetectFace(rect, image);
       return vector<int>{rect.x, rect.y, rect.x + rect.width, rect.y + rect.height};
   };

public:
   std::string version = "v1.0.0";

};



#if 0

int main() {
   cv::VideoCapture capture;
   capture.open("./test.avi");

   cv::Mat frame;
   faceTrack tracker;
   std::string modelPath = "./models";
   int minFace = 40;
   tracker.Init(modelPath, minFace);

   while (capture.read(frame)) {
       int q = cv::waitKey(1);
       if (q == 27) break;
       cv::Rect result;
       double t1 = (double)getTickCount();
       tracker.DetectFace(result, frame);
       printf("total %gms\n", ((double)getTickCount() - t1) * 1000 / getTickFrequency());
       printf("------------------\n");
       rectangle(frame, result, Scalar(0, 0, 255), 2);
       imshow("frame", frame);
       //      outputVideo << frame;
   }
   //  outputVideo.release();
   capture.release();
   cv::destroyAllWindows();
   return 0;
}


#endif // 0


#if 1
PYBIND11_MODULE(face_tracking_demo, m) {
   
   NDArrayConverter::init_numpy();
   
   py::class_<FaceTracker>(m, "FaceTracker")
       .def(py::init<>())
       .def("trackerInit", &FaceTracker::trackerInit, py::arg("model_path"), py::arg("min_face"))
       .def("trackerUpdate", &FaceTracker::trackerUpdate, py::arg("img"));
}

#endif

python測(cè)試代碼

import demo16.face_tracking_demo as demo
import cv2

capture = cv2.VideoCapture()
capture.open('./demo16/test.avi')

tracker = demo.FaceTracker()
tracker.trackerInit(model_path='./demo16/models/', min_face=40)

while True:
    ret, frame = capture.read()
    if not ret:
        print('Finish!')
        break

    rect = tracker.trackerUpdate(frame)

    cv2.rectangle(frame, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 255), 2)
    cv2.imshow('tracking', frame)
    cv2.waitKey(33)


跟蹤結(jié)果

  • video1
image.png
image.png
image.png
  • video2


    image.png
image.png
image.png
image.png
  • video3


    image.png
image.png

libfacedetection

初次接觸這個(gè)庫(kù)的時(shí)候,發(fā)現(xiàn)比opencv提供的Haar人臉檢測(cè)器好的多,而且?guī)斓淖髡呤谴笈?,佩服?。?!?之前l(fā)ibfacedetction只提供了編譯好的DLL,現(xiàn)在最新libfacedetection已經(jīng)開(kāi)源,采用深度學(xué)習(xí)CNN,很猛?。?!

Requires

  • Ananconda3, python
  • numpy
  • opencv-python
  • opencv C++
  • pybind11

python 接口

此源碼是為了編譯python接口使用

#include<array>
#include<pybind11/pybind11.h>
#include<pybind11/numpy.h>
#include<pybind11/stl.h>
#include<opencv2/opencv.hpp>
#include<facedetectcnn.h>
#include"ndarray_converter.h"

namespace py = pybind11;


class Face {

public:
    std::array<int, 4> rect;  //[xmin,ymin,xmax,ymax]
    int angle;
    int neighbors;

public:
    Face() {};
    Face(std::array<int,4>& rect, int angle, int neighbors) {
        this->rect = rect;
        this->angle = angle;
        this->neighbors = neighbors;    
    }


    ~Face() {};
};

//define the buffer size. Do not change the size!
#define DETECT_BUFFER_SIZE 0x20000


std::vector<Face> facedetect(cv::Mat& image) {
    int * pResults = NULL;
    //pBuffer is used in the detection functions.
    //If you call functions in multiple threads, please create one buffer for each thread!
    unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);
    if (!pBuffer)
    {
        std::runtime_error("Can not alloc buffer.\n");
        //fprintf(stderr, "Can not alloc buffer.\n");
        
    }


    ///////////////////////////////////////////
    // CNN face detection 
    // Best detection rate
    //////////////////////////////////////////
    //!!! The input image must be a RGB one (three-channel)
    //!!! DO NOT RELEASE pResults !!!
    pResults = facedetect_cnn(pBuffer, (unsigned char*)(image.ptr(0)), image.cols, image.rows, (int)image.step);

    //printf("%d faces detected.\n", (pResults ? *pResults : 0));
    cv::Mat result_cnn = image.clone();;
    //print the detection results

    std::vector<Face> faces;
    for (int i = 0; i < (pResults ? *pResults : 0); 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 neighbors = p[4];
        int angle = p[5];

        std::array<int, 4> arr;
        arr[0] = x;
        arr[1] = y;
        arr[2] = x + w;
        arr[3] = y + h;
        faces.push_back(Face(arr, angle, neighbors));

        //printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
        //rectangle(result_cnn, Rect(x, y, w, h), Scalar(0, 255, 0), 2);
    }

    return faces;


}


//std::vector<Face> facedetect(std::string filename) {
//
//  cv::Mat image = cv::imread(filename);
//  if (image.empty())
//  {
//      std::runtime_error("image read failed!\n");
//  }
//
//  int * pResults = NULL;
//  //pBuffer is used in the detection functions.
//  //If you call functions in multiple threads, please create one buffer for each thread!
//  unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);
//  if (!pBuffer)
//  {
//      std::runtime_error("Can not alloc buffer.\n");
//      //fprintf(stderr, "Can not alloc buffer.\n");
//
//  }
//
//
//  ///////////////////////////////////////////
//  // CNN face detection 
//  // Best detection rate
//  //////////////////////////////////////////
//  //!!! The input image must be a RGB one (three-channel)
//  //!!! DO NOT RELEASE pResults !!!
//  pResults = facedetect_cnn(pBuffer, (unsigned char*)(image.ptr(0)), image.cols, image.rows, (int)image.step);
//
//  //printf("%d faces detected.\n", (pResults ? *pResults : 0));
//  cv::Mat result_cnn = image.clone();;
//  //print the detection results
//
//  std::vector<Face> faces;
//  for (int i = 0; i < (pResults ? *pResults : 0); 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 neighbors = p[4];
//      int angle = p[5];
//
//      std::array<int, 4> arr;
//      arr[0] = x;
//      arr[1] = y;
//      arr[2] = x + w;
//      arr[3] = y + h;
//      faces.push_back(Face(arr, angle, neighbors));
//
//      //printf("face_rect=[%d, %d, %d, %d], neighbors=%d, angle=%d\n", x, y, w, h, neighbors, angle);
//      //rectangle(result_cnn, Rect(x, y, w, h), Scalar(0, 255, 0), 2);
//  }
//
//  return faces;
//
//
//}
//

PYBIND11_MODULE(pyLibfacedetection_cnn, m) {

    m.doc() = "Simple python warper of libfacedetection-cnn";


    NDArrayConverter::init_numpy();

    py::class_<Face>(m, "Face")
        .def(py::init())
        .def_readwrite("rect", &Face::rect)
        .def_readwrite("angle", &Face::angle)
        .def_readwrite("neighbors", &Face::neighbors);

    m.def("facedetect",&facedetect);

    

        
}


編譯好之后生成pyd文件


image.png

在此路徑下,打開(kāi)python, 直接運(yùn)行


image.png

為了可移植、脫離本機(jī)平臺(tái),使用VS自帶的工具查看pyd動(dòng)態(tài)鏈接庫(kù)的依賴:


image.png
image.png

測(cè)試

image.png

image.png
image.png
dst.jpg

End

感謝甜心 的支持

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容