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"
|
"time"
|
"unsafe"
|
|
"basic.com/pubsub/protomsg.git"
|
"basic.com/valib/gosdk.git"
|
"github.com/gogo/protobuf/proto"
|
)
|
|
func tconvert2ProtoFacePos(dec gosdk.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,
|
}
|
}
|
|
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():
|
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 := gosdk.ResizeFaceTracker(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)
|
|
img := gosdk.SDKImage{Data: i.Data, Width: imgW, Height: imgH}
|
|
detect := gosdk.FaceTrackSimple(img, dtchn)
|
|
var faces []*protomsg.ResultFaceDetect
|
|
//将sdk返回值转换成protomsg类型
|
for _, d := range detect {
|
|
/// 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
|
|
//运行sd
|
dec := gosdk.FaceInfo2FacePos(d)
|
prop := gosdk.FaceProperty(dec, img, dtchn)
|
feat := gosdk.FaceExtract(dec, img, dtchn)
|
|
resP := (*protomsg.ThftResult)(unsafe.Pointer(&prop))
|
|
result := tconvert2ProtoFacePos(d)
|
|
//组成结果并序列化
|
res := &protomsg.ResultFaceDetect{Pos: result, Result: resP, Feats: feat}
|
faces = append(faces, res)
|
|
}
|
|
var err error
|
var data []byte
|
if len(faces) > 0 {
|
|
// logo.Infoln("CID: ", rMsg.Msg.Cid, " TASK: ", rMsg.Msg.Tasklab.Taskid, " FACE TRACK OBJS: ", len(faces))
|
|
facePos := protomsg.ParamFacePos{Faces: faces}
|
data, err = proto.Marshal(&facePos)
|
if err != nil {
|
logo.Errorln("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(faces))
|
|
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("cahn:%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 (e *EFDetect) detectTrack(ctx context.Context, in <-chan work.MsgRS, out chan<- work.MsgRS, typ string) {
|
// tm := time.Now()
|
// sc := 0
|
//
|
// for {
|
// select {
|
// case <-ctx.Done():
|
// goconv.Free()
|
// return
|
// default:
|
// rMsg := <-in
|
// validMsg := validRemoteMessage(rMsg, typ)
|
//
|
// 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)
|
// resizeW, resizeH := util.SFI.TrackPicWidth, util.SFI.TrackPicHeight
|
// fx := (float64)(resizeW) / (float64)(imgW)
|
// fy := (float64)(resizeH) / (float64)(imgH)
|
//
|
// origData, resizeData := goconv.YUV2BGRandResize(i.Data, goconv.PIX_FMT_NV12, imgW, imgH, fx, fy)
|
// if origData == nil {
|
// ejectResult(nil, rMsg, out)
|
// continue
|
// }
|
// // resize to track
|
// if imgW < resizeW && imgH < resizeH {
|
// resizeData = origData
|
// resizeW, resizeH = imgW, imgH
|
// }
|
// // resize to track
|
//
|
// img := gosdk.SDKImage{Data: origData, Width: imgW, Height: imgH}
|
// imgTrack := gosdk.SDKImage{Data: resizeData, Width: resizeW, Height: resizeH}
|
// if !validMsg {
|
// ejectResult(nil, rMsg, out)
|
// continue
|
// }
|
// //运行sdk
|
// c, ok, _ := e.q.Get()
|
// if !ok {
|
// logo.Errorln("fdetect there is no idle thread")
|
// ejectResult(nil, rMsg, out)
|
// continue
|
// }
|
// detect := gosdk.FaceTrackSimple(imgTrack, c.(int))
|
// e.q.Put(c)
|
//
|
// // if len(detect) > 0 {
|
// // logo.Infof("FACE DETECT FROM CAMERA %s IMAGE-ID %d, TASKID %s, %d FACES COUNT\n", rMsg.Msg.Cid, i.Id, rMsg.Msg.Tasklab.Taskid, len(detect))
|
// // }
|
//
|
// var faces []*protomsg.ResultFaceDetect
|
//
|
// //将sdk返回值转换成protomsg类型
|
// for _, d := range detect {
|
//
|
// /// 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
|
//
|
// if fx < 1.0 || fy < 1.0 {
|
// d.RcFace.Left = (int32)((float64)(d.RcFace.Left) / fx)
|
// d.RcFace.Top = (int32)((float64)(d.RcFace.Top) / fy)
|
// d.RcFace.Right = (int32)((float64)(d.RcFace.Right) / fx)
|
// d.RcFace.Bottom = (int32)((float64)(d.RcFace.Bottom) / fy)
|
// d.PtLeftEye.X = (int32)((float64)(d.PtLeftEye.X) / fx)
|
// d.PtLeftEye.Y = (int32)((float64)(d.PtLeftEye.Y) / fy)
|
// d.PtRightEye.X = (int32)((float64)(d.PtRightEye.X) / fx)
|
// d.PtRightEye.Y = (int32)((float64)(d.PtRightEye.Y) / fy)
|
// d.PtMouth.X = (int32)((float64)(d.PtMouth.X) / fx)
|
// d.PtMouth.Y = (int32)((float64)(d.PtMouth.Y) / fy)
|
// d.PtNose.X = (int32)((float64)(d.PtNose.X) / fx)
|
// d.PtNose.Y = (int32)((float64)(d.PtNose.Y) / fy)
|
//
|
// faceData := d.PFacialData[:8192]
|
// data := C.CBytes(faceData)
|
// defer C.free(data)
|
// resizeP := C.resize(&data, C.float(fx), C.float(fy))
|
// fd := C.GoBytes(resizeP, 8192)
|
// d.PFacialData = *(*[8192]uint8)(unsafe.Pointer(&fd[0]))
|
//
|
// }
|
//
|
// //运行sd
|
// dec := gosdk.FaceInfo2FacePos(d)
|
//
|
// c, ok, _ := e.qprop.Get()
|
// if !ok {
|
// logo.Errorln("fproperty there is no idle thread")
|
// continue
|
// }
|
// prop := gosdk.FaceProperty(dec, imgTrack, c.(int))
|
// e.qprop.Put(c)
|
//
|
// c, ok, _ = e.qext.Get()
|
// if !ok {
|
// logo.Errorln("fextract there is no idle thread")
|
// continue
|
// }
|
// feat := gosdk.FaceExtract(dec, imgTrack, c.(int))
|
// e.qext.Put(c)
|
//
|
// resP := (*protomsg.ThftResult)(unsafe.Pointer(&prop))
|
//
|
// result := tconvert2ProtoFacePos(d)
|
//
|
// //组成结果并序列化
|
// res := &protomsg.ResultFaceDetect{Pos: result, Result: resP, Feats: feat}
|
// faces = append(faces, res)
|
//
|
// }
|
//
|
// var err error
|
// var data []byte
|
// if len(faces) > 0 {
|
//
|
// // logo.Infoln("CID: ", rMsg.Msg.Cid, " TASK: ", rMsg.Msg.Tasklab.Taskid, " FACE TRACK OBJS: ", len(faces))
|
//
|
// facePos := protomsg.ParamFacePos{Faces: faces}
|
// data, err = proto.Marshal(&facePos)
|
// if err != nil {
|
// logo.Errorln("fdetect marshal proto face pos error", err)
|
// data = nil
|
// }
|
// }
|
//
|
// // logo.Infoln("CURRENT INDEX: ",rMsg.Msg.Tasklab.Index)
|
// rMsg.BGRImg = &img
|
// ejectResult(data, rMsg, out)
|
//
|
// sc++
|
// if sc == 25 {
|
// logo.Infoln("FACE RUN 25 FRAME USE TIME: ", time.Since(tm))
|
// sc = 0
|
// tm = time.Now()
|
// }
|
//
|
// if time.Since(tm) > time.Second {
|
// logo.Infof("FACE RUN %d FRAME USE TIME: %v", sc, time.Since(tm))
|
// sc = 0
|
// tm = time.Now()
|
// }
|
//
|
// }
|
// }
|
//}
|