package sdk
|
|
/*
|
#include<stdlib.h>
|
|
#define LANDMARKS_NUM 25
|
typedef struct {
|
int id;
|
float x;
|
float y;
|
} Key_Point;
|
|
typedef struct {
|
int count;
|
int view;
|
Key_Point pts[LANDMARKS_NUM];
|
} Face_Landmarks;
|
|
void *resize(void **data, const float fx, const float fy){
|
Face_Landmarks* lms = (Face_Landmarks*)(*data);
|
for(int i = 0; i < lms->count; i++){
|
Key_Point kp = lms->pts[i];
|
kp.x /= fx;
|
kp.y /= fy;
|
lms->pts[i] = kp;
|
}
|
|
return *data;
|
}
|
*/
|
import "C"
|
import (
|
"analysis/logo"
|
"analysis/work"
|
"context"
|
"fmt"
|
"time"
|
"unsafe"
|
|
"basic.com/libgowrapper/sdkstruct.git"
|
"basic.com/pubsub/protomsg.git"
|
"github.com/gogo/protobuf/proto"
|
)
|
|
const (
|
cacheFrameNum = 3
|
trackChnTimeout = time.Duration(10)
|
)
|
|
func (e *EFDetect) cleanChnStat() {
|
e.chnLock.Lock()
|
for i := 0; i < MaxFaceDetectThreadNum; i++ {
|
e.ftrackChanStats[i] = false
|
}
|
e.chnLock.Unlock()
|
}
|
|
func (e *EFDetect) getAvailableChn() int {
|
e.chnLock.Lock()
|
defer e.chnLock.Unlock()
|
|
for i := 0; i < MaxFaceDetectThreadNum; i++ {
|
if e.ftrackChanStats[i] == false {
|
e.ftrackChanStats[i] = true
|
return i
|
}
|
}
|
return -1
|
}
|
|
func (e *EFDetect) releaseChn(chn int) {
|
e.chnLock.Lock()
|
e.ftrackChanStats[chn] = false
|
e.chnLock.Unlock()
|
}
|
|
func (e *EFDetect) detectTrack(ctx context.Context, in <-chan work.MsgRS, out chan<- work.MsgRS, typ string) {
|
|
for {
|
select {
|
case <-ctx.Done():
|
e.fnFree(e.handle)
|
return
|
default:
|
rMsg := <-in
|
if !validRemoteMessage(rMsg, typ) {
|
logo.Errorln("face track validremotemessage invalid")
|
ejectResult(nil, rMsg, out)
|
continue
|
}
|
|
if _, ok := e.ftrackChans[rMsg.Msg.Cid]; ok {
|
e.ftrackChans[rMsg.Msg.Cid] <- rMsg
|
} else {
|
|
e.ftrackChans[rMsg.Msg.Cid] = make(chan work.MsgRS, cacheFrameNum)
|
chn := e.getAvailableChn()
|
if chn < 0 {
|
logo.Infof("TOO MUCH CHANNEL")
|
ejectResult(nil, rMsg, out)
|
continue
|
}
|
e.ftrackChannels[rMsg.Msg.Cid] = chn
|
|
i := unpackImage(rMsg, typ)
|
if i == nil {
|
ejectResult(nil, rMsg, out)
|
continue
|
}
|
// conv to bgr24 and resize
|
imgW, imgH := int(i.Width), int(i.Height)
|
ret := e.fnTrackerResize(e.handle, e.ftrackChannels[rMsg.Msg.Cid], imgW, imgH)
|
logo.Infof("ResizeFaceTracker: cid:%s, chan:%d, wXh:%d x %d ,result:%d\n",
|
rMsg.Msg.Cid, e.ftrackChannels[rMsg.Msg.Cid], imgW, imgH, ret)
|
go e.detectTrackOneChn(ctx, e.ftrackChans[rMsg.Msg.Cid], out, typ, e.ftrackChannels[rMsg.Msg.Cid])
|
e.ftrackChans[rMsg.Msg.Cid] <- rMsg
|
}
|
}
|
}
|
}
|
|
func (e *EFDetect) detectTrackOneChn(ctx context.Context, in <-chan work.MsgRS, out chan<- work.MsgRS, typ string, dtchn int) {
|
tm := time.Now()
|
sc := 0
|
logo.Infof("detectTrackOneChn dtchn:%d\n", dtchn)
|
var curCid string
|
|
for {
|
select {
|
case <-ctx.Done():
|
return
|
|
case rMsg := <-in:
|
|
if !validRemoteMessage(rMsg, typ) {
|
ejectResult(nil, rMsg, out)
|
continue
|
}
|
|
i := unpackImage(rMsg, typ)
|
if i == nil || i.Data == nil || i.Width <= 0 || i.Height <= 0 {
|
ejectResult(nil, rMsg, out)
|
continue
|
}
|
|
curCid = i.Cid
|
|
// conv to bgr24 and resize
|
imgW, imgH := int(i.Width), int(i.Height)
|
|
fRes := e.fnRun(e.handle, i.Data, imgW, imgH, 3, dtchn)
|
|
var faces []*protomsg.ResultFaceDetect
|
//将sdk返回值转换成protomsg类型
|
for _, r := range fRes {
|
|
d := r.Info
|
/// filter rules
|
sdkid := rMsg.Msg.Tasklab.Sdkinfos[rMsg.Msg.Tasklab.Index].Ipcid
|
size := (d.RcFace.Right - d.RcFace.Left) * (d.RcFace.Bottom - d.RcFace.Top)
|
angle := d.FAngle
|
if !filter(rMsg.Msg.Tasklab.Taskid, sdkid, angle.Confidence, float32(angle.Yaw), int(size)) {
|
continue
|
}
|
/// filter rules
|
|
feat := r.Feat
|
prop := (*protomsg.ThftResult)(unsafe.Pointer(&r.Prop))
|
fpos := tconvert2ProtoFacePos(d)
|
|
//组成结果并序列化
|
res := &protomsg.ResultFaceDetect{Pos: fpos, Result: prop, Feats: feat}
|
faces = append(faces, res)
|
|
}
|
var err error
|
var data []byte
|
if len(faces) > 0 {
|
|
facePos := protomsg.ParamFacePos{Faces: faces}
|
data, err = proto.Marshal(&facePos)
|
if err != nil {
|
fmt.Println("fdetect marshal proto face pos error", err)
|
data = nil
|
}
|
}
|
|
ejectResult(data, rMsg, out)
|
var id, name string
|
if rMsg.Msg.Tasklab != nil {
|
id, name = rMsg.Msg.Tasklab.Taskid, rMsg.Msg.Tasklab.Taskname
|
}
|
logo.Infoln("CAMERAID: ", rMsg.Msg.Cid, " TASKID: ", id, " TASKNAME: ", name, " DETECT FACE COUNT: ", len(fRes))
|
|
sc++
|
if sc == 25 {
|
logo.Infoln("CHAN:%d, FACE RUN 25 FRAME USE TIME: ", dtchn, time.Since(tm))
|
sc = 0
|
tm = time.Now()
|
}
|
|
if time.Since(tm) > time.Second {
|
logo.Infof("CHAN:%d, FACE RUN %d FRAME USE TIME: %v", dtchn, sc, time.Since(tm))
|
sc = 0
|
tm = time.Now()
|
}
|
case <-time.After(trackChnTimeout * time.Second):
|
logo.Errorln("Timeout to get image, curCid:", curCid)
|
if curCid != "" {
|
delete(e.ftrackChans, curCid)
|
e.releaseChn(dtchn)
|
}
|
return
|
|
}
|
}
|
}
|
|
func tconvert2ProtoFacePos(dec sdkstruct.CFaceInfo) *protomsg.FacePos {
|
|
crect := dec.RcFace
|
rect := protomsg.Rect{Left: crect.Left, Top: crect.Top, Right: crect.Right, Bottom: crect.Bottom}
|
leftEye := (*protomsg.Point)(unsafe.Pointer(&dec.PtLeftEye))
|
rightEye := (*protomsg.Point)(unsafe.Pointer(&dec.PtRightEye))
|
mouth := (*protomsg.Point)(unsafe.Pointer(&dec.PtMouth))
|
nose := (*protomsg.Point)(unsafe.Pointer(&dec.PtNose))
|
angle := (*protomsg.FaceAngle)(unsafe.Pointer(&dec.FAngle))
|
faceID := uint64(dec.NFaceID)
|
|
facialData := dec.PFacialData[:512]
|
|
// facialData := make([]byte, 512)
|
// copy(facialData[:], dec.PFacialData[:512])
|
|
return &protomsg.FacePos{
|
RcFace: &rect,
|
PtLeftEye: leftEye,
|
PtRightEye: rightEye,
|
PtMouth: mouth,
|
PtNose: nose,
|
FAngle: angle,
|
Quality: dec.NQuality,
|
FacialData: facialData,
|
FaceID: faceID,
|
}
|
}
|