panlei
2019-12-06 bf32a74cbb28405eb116495eb2046880ecfceb66
fix 追踪bug
7个文件已修改
633 ■■■■ 已修改文件
algorithm/middleware/readyData.go 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
algorithm/personTrack/personTrack.go 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
insertdata/insertDataToEs.go 279 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruleserver/ruleToformula.go 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
structure/rule.go 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
algorithm/middleware/readyData.go
@@ -74,9 +74,6 @@
    return rect
}
// 将外部传进来的sdk数据包解成 SdkDatas
func ParamFormat(msg []byte, args *structure.SdkDatas) protomsg.SdkMessage {
    defer func() {
@@ -113,17 +110,13 @@
            extractFace(args,m,sdkinfo,i)
        case "Plate":
            extractCar(args,m,sdkinfo,i)
        case "Track":
        case "HumanTrack":
            extractTrack(args,m,sdkinfo,i)
        }
    }
    return m
}
// 把人脸放进对应的人体
func FacePush2Body () {
}
// 提取face
func extractFace(args *structure.SdkDatas,m protomsg.SdkMessage,sdkinfo *protomsg.SdkmsgWithTask,i protomsg.Image) {
    arg := structure.SdkData{}
@@ -142,7 +135,7 @@
        logger.Info("--------------追踪之后人脸的个数:", len(faceParam.Faces))
        for _, info := range faceParam.Faces {
            //logger.Info("_______________________________________________第一次看相似值:",info.Pos.FAngle.Confidence*100)
            photoMap := structure.PhotoMap{Id: strconv.Itoa(int(info.Pos.FaceID)) , Rects: rectFormat(info.Pos.RcFace), Score: float64(info.Pos.FAngle.Confidence * 100), Type: "face", ThftRes: *(info.Result), Feature: info.Feats}
            photoMap := structure.PhotoMap{structure.SourcePhoto{Id: strconv.Itoa(int(info.Pos.FaceID)) , Rects: rectFormat(info.Pos.RcFace), Score: float64(info.Pos.FAngle.Confidence * 100), Type: "face", ThftRes: *(info.Result), Feature: info.Feats},nil}
            arg.Photo = append(arg.Photo, photoMap)
        }
        args.Sdkdata = append(args.Sdkdata, &arg)
@@ -169,7 +162,7 @@
        for _, info := range yoloParam.Infos {
            if info.Typ == 0 {
                //logger.Debug("-------------yolo的坐标有几个",info.RcObj)
                photoMap := structure.PhotoMap{Rects: rectFormat(info.RcObj), Score: float64(info.Prob) * 100, Type: "yolo",Id:strconv.Itoa(int(info.ObjID))}
                photoMap := structure.PhotoMap{structure.SourcePhoto{Rects: rectFormat(info.RcObj), Score: float64(info.Prob) * 100, Type: "yolo",Id:strconv.Itoa(int(info.ObjID))},nil}
                arg.Photo = append(arg.Photo, photoMap)
                yoloNum++
            }
@@ -200,7 +193,7 @@
            logger.Info("接收车牌数据:",info.FvdConf,info.NVehicleColor1,info.NPlateFlag,info.RcCarLocation)
            if info.NConfidence > 70 {
                logger.Info("车牌也符合的数据",info.FvdConf,info.NVehicleColor1,info.NPlateFlag,info.RcCarLocation,info.NConfidence,)
                photoMap := structure.PhotoMap{Id: info.License,Score: float64(info.FvdConf)*100,Rects: rectFormat(info.RcCarLocation), Type: "plate", Car:info}
                photoMap := structure.PhotoMap{structure.SourcePhoto{Id: info.License,Score: float64(info.FvdConf)*100,Rects: rectFormat(info.RcCarLocation), Type: "plate", Car:info},nil}
                arg.Photo = append(arg.Photo, photoMap)
            }
        }
@@ -219,22 +212,57 @@
    arg.ImageWidth = int(i.Width)
    arg.ImageHeight = int(i.Height)
    if len(sdkinfo.Sdkdata) > 1 {
        plateIDResult  := protomsg.PlateIDResult {}
        err := proto.Unmarshal(sdkinfo.Sdkdata, &plateIDResult )
        Track := protomsg.HumanTrackResult {}
        err := proto.Unmarshal(sdkinfo.Sdkdata, &Track)
        if err != nil {
            logger.Info("解析跟踪目标数据时出现错误", err)
            return
        }
        for _, info := range plateIDResult.Result {
            logger.Info("接收车牌数据:",info.FvdConf,info.NVehicleColor1,info.NPlateFlag,info.RcCarLocation)
            if info.NConfidence > 70 {
                logger.Info("车牌也符合的数据",info.FvdConf,info.NVehicleColor1,info.NPlateFlag,info.RcCarLocation,info.NConfidence,)
                photoMap := structure.PhotoMap{Id: info.License,Score: float64(info.FvdConf)*100,Rects: rectFormat(info.RcCarLocation), Type: "plate", Car:info}
                arg.Photo = append(arg.Photo, photoMap)
            }
        for _, info := range Track.Result {
            logger.Info("接收跟踪数据:",info.Id,info.Confidence)
            photoMap := structure.PhotoMap{structure.SourcePhoto{Id: strconv.Itoa(int(info.Id)),Score: float64(info.Confidence)*100,Rects: rectFormat(info.RcHuman), Type: "track"},nil}
            FacePush2Body(&photoMap,m.Tasklab.Sdkinfos)
            logger.Info("组装后的跟踪数据:",photoMap)
            arg.Photo = append(arg.Photo, photoMap)
        }
        args.Sdkdata = append(args.Sdkdata, &arg)
    } else {
        return
    }
}
// 把人脸放进对应的人体
func FacePush2Body (photomap *structure.PhotoMap,sdkInfos []*protomsg.SdkmsgWithTask) {
    for _,sdkinfo := range sdkInfos {
        if sdkinfo.Sdktype == "FaceDetect" {
            faceParam := protomsg.ParamFacePos{}
            err := proto.Unmarshal(sdkinfo.Sdkdata, &faceParam)
            if err != nil {
                logger.Info("解析FACE sdk数据时出现错误", err)
                return
            }
            logger.Info("--------------追踪之后人脸的个数:", len(faceParam.Faces))
            for _, info := range faceParam.Faces {
                percent := ruleserver.PgsInterPercent(Rect2Point(photomap.Rects),rectFormat(info.Pos.RcFace), 1, 1)
                if percent > 99 {
                    photomap.AttachObj = structure.SourcePhoto{Id:strconv.Itoa(int(info.Pos.FaceID)),Rects: rectFormat(info.Pos.RcFace),Score: float64(info.Pos.FAngle.Confidence * 100), Type: "face", ThftRes: *(info.Result), Feature: info.Feats}
                }
            }
        }
    }
}
func Rect2Point(rect structure.Rect) []structure.Point{
    // 按逆时针转化
    points := []structure.Point{}
    leftTop := structure.Point{rect.X,rect.Y}
    points = append(points,leftTop)
    leftBottom := structure.Point{rect.X,rect.Y+rect.Height}
    points = append(points,leftBottom)
    rightBottom := structure.Point{rect.X+rect.Width,rect.Y+rect.Height}
    points = append(points,rightBottom)
    rightTop := structure.Point{rect.X+rect.Width,rect.Y}
    points = append(points,rightTop)
    return  points
}
algorithm/personTrack/personTrack.go
@@ -3,8 +3,10 @@
import (
    "encoding/json"
    "errors"
    uuid "github.com/satori/go.uuid"
    "net"
    "strconv"
    "time"
    "nanomsg.org/go-mangos"
    "nanomsg.org/go-mangos/protocol/req"
@@ -94,7 +96,8 @@
// 给目标填充liker
func fillLiker(compareThreshold float32,arg *structure.Arg,am *structure.AreaMap) {
    trackArg := make(map[string]interface{})
    trackArg["esId"] = ""
    esId := uuid.NewV4().String()
    trackArg["esId"] = esId
    trackArg["cameraId"] = am.CameraId
    trackArg["bodyFeature"] = arg.Feature
    trackArg["faceFeature"]    = arg.AttachArg.Feature
@@ -102,10 +105,15 @@
    if err != nil {
        _ = logger.Error("json序列化错误", err)
    }
    esId := getCompareMsg(b)
    logger.Info("比对出来的esid:",esId)
    base := structure.BaseInfo{TargetId:esId}
    arg.Liker = append(arg.Liker, &base)
    dataId := getCompareMsg(b)
    if esId == dataId { // 说明没比到相似的人
        logger.Info("没比到人")
        arg.Uuid = dataId
    } else {
        logger.Info("比对出来的dataId:",dataId)
        base := structure.BaseInfo{TargetId:dataId}
        arg.Liker = append(arg.Liker, &base)
    }
}
func track (rule *protomsg.Rule,am *structure.AreaMap) structure.LittleRuleResult{
@@ -113,18 +121,20 @@
    if th,err := strconv.ParseFloat(rule.SdkArgValue,32); err == nil {
        threshold = float32(th)
    }
    for i, arg := range am.FilterData {
    for _, arg := range am.FilterData {
        fillLiker(threshold,arg,am)
        if len(arg.Liker) == 0 {
            // 如果没有相似者则删除本目标数据
            am.FilterData = append(am.FilterData[:i],am.FilterData[i+1:]...)
        }
        //if len(arg.Liker) == 0 {
        //    // 如果没有相似者则删除本目标数据
        //    am.FilterData = append(am.FilterData[:i],am.FilterData[i+1:]...)
        //}
    }
    if len(am.FilterData) > 0 {
        return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
    } else {
        return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
    }
    //if len(am.FilterData) > 0 {
    //    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
    //} else {
    //    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
    //}
    // 无论有没有相似者都要返回true
    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
}
func Push(){
@@ -148,13 +158,8 @@
    initFlag = true
    for {
        select {
        // case <-ctx.Done():
        //     return
        case data := <- sender:
            logger.Info("数据长度为:",len(data))
            logger.Debug("推送数据")
            logger.Debug("推送数据:",len(data))
            if err = sock.Send(data); err != nil {
                _ = logger.Error("推送socket发送数据失败: %s", err.Error())
            }
@@ -164,7 +169,7 @@
            logger.Debug("数据推送成功!收到响应,数据长度为:",len(msg))
            receiver <- string(msg)
        default:
            time.Sleep(time.Millisecond * 10)
        }
    }
}
go.mod
@@ -6,21 +6,22 @@
    basic.com/dbapi.git v0.0.0-20191025084729-a04db890e7b5
    basic.com/fileserver/WeedFSClient.git v0.0.0-20191105073656-98059e699477
    basic.com/pubsub/cache.git v0.0.0-20190718093725-6a413e1d7d48
    basic.com/pubsub/protomsg.git v0.0.0-20191121033547-7af037c469a7
    basic.com/pubsub/esutil.git v0.0.0-20191205065552-198b5ecaefce
    basic.com/pubsub/protomsg.git v0.0.0-20191206064248-c404f7d36eb2
    basic.com/valib/deliver.git v0.0.0-20190927081905-2d390df9ede3
    basic.com/valib/gopherdiscovery.git v0.0.0-20190605034340-15d89d8b4e28
    basic.com/valib/logger.git v0.0.0-20190928113028-4907b08c4159
    basic.com/valib/shm.git v0.0.0-20190829074754-ad2e00879627 // indirect
    github.com/Microsoft/go-winio v0.4.12 // indirect
    github.com/ajg/form v1.5.1 // indirect
    github.com/alecthomas/log4go v0.0.0-20180109082532-d146e6b86faa // indirect
    github.com/alecthomas/log4go v0.0.0-20180109082532-d146e6b86faa
    github.com/go-yaml/yaml v2.1.0+incompatible
    github.com/gogo/protobuf v1.2.1
    github.com/golang/protobuf v1.3.1
    github.com/jeanphorn/log4go v0.0.0-20190526082429-7dbb8deb9468 // indirect
    github.com/kirinlabs/HttpRequest v0.1.5 // indirect
    github.com/kirinlabs/HttpRequest v0.1.5
    github.com/knetic/govaluate v3.0.0+incompatible
    github.com/panjf2000/ants/v2 v2.2.2 // indirect
    github.com/panjf2000/ants/v2 v2.2.2
    github.com/pierrec/lz4 v2.2.3+incompatible
    github.com/satori/go.uuid v1.2.0
    github.com/spf13/viper v1.4.0
go.sum
@@ -6,6 +6,8 @@
basic.com/fileserver/WeedFSClient.git v0.0.0-20191105073656-98059e699477/go.mod h1:oiXPn3wwwOi/Sbm6cDWpNWofoG5iV2Nb1V/DxLEAqYY=
basic.com/pubsub/cache.git v0.0.0-20190718093725-6a413e1d7d48 h1:BBA30Rgljn6MRieC4gUncETJDyna3ObyubTo9HEQ2M0=
basic.com/pubsub/cache.git v0.0.0-20190718093725-6a413e1d7d48/go.mod h1:gHLJZz2ee1cGL0X0ae69fs56bAxkDgEQwDhhXZJNUcY=
basic.com/pubsub/esutil.git v0.0.0-20191205065552-198b5ecaefce h1:VBdSBX9HZJB93+CA5Vv7XU+laljn6d997KvLwZBg3A4=
basic.com/pubsub/esutil.git v0.0.0-20191205065552-198b5ecaefce/go.mod h1:yIvppFPFGC61DOdm71ujnsxZBMFUu2yKjr5O43bMWCw=
basic.com/pubsub/protomsg.git v0.0.0-20190905061607-7b96dafe8f99 h1:YSmWZPp/mHoq+/L5d0iTsqjiCcVwZqEQRQAXxQFSbvY=
basic.com/pubsub/protomsg.git v0.0.0-20190905061607-7b96dafe8f99/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/protomsg.git v0.0.0-20191025080939-9b30ac3be52d h1:Lhny6vIq3GNjunE+r0ymLnpg+/n0lqwnsOAy6HbARfk=
@@ -20,6 +22,12 @@
basic.com/pubsub/protomsg.git v0.0.0-20191121023847-bd1d8f822f8f/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/protomsg.git v0.0.0-20191121033547-7af037c469a7 h1:JFN0eyyRZ2Ty/FMtoCGHDtEcJdQrIkpGfHcKk2N4IQs=
basic.com/pubsub/protomsg.git v0.0.0-20191121033547-7af037c469a7/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/protomsg.git v0.0.0-20191206061611-4dd5374a4e31 h1:oz/P7JqMHNAOlXyyZ2WGWW6H1C3BnPdjsPa82BAfLsU=
basic.com/pubsub/protomsg.git v0.0.0-20191206061611-4dd5374a4e31/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/protomsg.git v0.0.0-20191206062708-331a33663565 h1:8Pkfz7XKj2mbV9ggqbmQ0pdQ6OLStPF549TUUPUmFZA=
basic.com/pubsub/protomsg.git v0.0.0-20191206062708-331a33663565/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/protomsg.git v0.0.0-20191206064248-c404f7d36eb2 h1:uDXeWCPB6ZuaK2a6CpYbs7attGB2fNudzEPRTP15se0=
basic.com/pubsub/protomsg.git v0.0.0-20191206064248-c404f7d36eb2/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU=
basic.com/pubsub/sdkcompare.git v0.0.0-20190715013640-f536a4647d00 h1:sK+Tx7rvM9J2WnNIwrzMDjZSylWiKNfQO0prUBfKsDk=
basic.com/pubsub/sdkcompare.git v0.0.0-20190715013640-f536a4647d00/go.mod h1:8by33F9E1w17Pw/rDgJGJXAo122w0wDENG14hiMS+RE=
basic.com/valib/deliver.git v0.0.0-20190531095353-25d8c3b20051 h1:9flC2o3kasaM2Y6I+mY+mxmve/pyAY/UzGQZLT3lFHM=
insertdata/insertDataToEs.go
@@ -15,12 +15,14 @@
    "ruleprocess/cache"
    "ruleprocess/structure"
    "basic.com/pubsub/protomsg.git"
    "basic.com/pubsub/esutil.git"
    "ruleprocess/ruleserver"
    "ruleprocess/util"
)
var weedfsUrl, videoPersonUrl, personAction string
var serverIp string
var serverPort string
type conf struct {
    PhotoUrl       string `yaml:"photoUrl"`
    VideoPersons   string `yaml:"videoPersons"`
@@ -105,7 +107,7 @@
func InsertToEs(msg structure.ResultMsg) {
    defer func() {
        if err := recover(); err != nil {
            logger.Error("es模块儿的异常捕获:", err)
            _ = logger.Error("es模块儿的异常捕获:", err)
        }
    }()
    localConfig1, err := cache.GetServerInfo()
@@ -114,122 +116,151 @@
    }
    weedfsUrl = "http://" + localConfig1.WebPicIp + ":" + strconv.Itoa(int(localConfig1.WebPicPort)) + "/submit"
    videoPersonUrl = "http://" + localConfig1.AlarmIp + ":" + strconv.Itoa(int(localConfig1.AlarmPort)) + "/" + EsInfo.EsIndex.AIOcean.IndexName + "/" + EsInfo.EsIndex.AIOcean.IndexType+"?refresh=true"
    InsertFace(msg)
    InsertYolo(msg)
    InsertTarget(msg)
    serverIp = localConfig1.AlarmIp
    serverPort = strconv.Itoa(int(localConfig1.AlarmPort))
    for k,results := range msg.RuleResult {
        if results != nil && len(results.([]structure.Result)) > 0{
            switch k {
            case "yolo":
                InsertYolo(msg,k,results)
            case "face":
                InsertFace(msg,k,results)
            case "plate":
                InsertFace(msg,k,results)
            case "track":
                InsertFace(msg,k,results)
            case "target":
                InsertLastTarget(msg)
            }
        }
    }
}
// 往es中插入人脸类型数据
func InsertFace(msg structure.ResultMsg) {
    if (msg.RuleResult["face"] != nil && len(msg.RuleResult["face"].([]structure.Result)) > 0) || (msg.RuleResult["plate"] != nil && len(msg.RuleResult["plate"].([]structure.Result)) > 0) || (msg.RuleResult["track"] != nil && len(msg.RuleResult["track"].([]structure.Result)) > 0) {
        for key, results := range msg.RuleResult {
            if key == "face" || key == "plate" || key == "track"{
                logger.Info("往ES插人脸数据(或车牌数据)")
                faces := []*ObjAndRules{}
                faces = PutFace(faces, results.([]structure.Result))
                //logger.Info("整理后的数据:",faces)
                if faces != nil {
                    logger.Warn("face不为nil")
                    var imgMaxUrl []string = []string{}
                    var picTime string = ""
                    for _, face := range faces {
                        // 上传大图
                        // 解压缩并上传图片
                        bdata, err := util.UnCompress(msg.Data)
                        if err != nil {
                            panic("解压缩图片时出现错误")
                        }
                        alarmRules := []AlarmRule{}
                        //logger.Info("循环每一个目标")
                        for _, faceResult := range face.rules {
                            alarm := ChangeToString(faceResult.DefenceState, faceResult.AlarmLevel)
                            alarmRules = append(alarmRules, AlarmRule{faceResult.RuleGroupId, alarm, faceResult.RuleText, faceResult.DefenceState, ""})
                        }
                        i := protomsg.Image{}
                        err = proto.Unmarshal(bdata, &i)
                        // 先传小图,再传大图,防止脸上有线
                        bytes := util.SubImg(i, int(face.Location.X), int(face.Location.Y), int(face.Location.X+face.Location.Width), int(face.Location.Y+face.Location.Height),face.Type)
                        resp, err := util.PostFormBufferData1(weedfsUrl, bytes, uuid.NewV4().String())
                        if err != nil {
                            logger.Error("上传小图出错")
                        }
                        // 上传大图
                        if len(imgMaxUrl) == 0 {
                            bigPhotoUrl := make(map[string]interface{})
                            bigPhotoUrl, err = util.DrawPolygonOnImageForFace(msg.Cid, i, msg.RuleResult["face"].([]structure.Result), weedfsUrl)
                            logger.Debug("========大图路径:", bigPhotoUrl)
                            imgMaxUrl = append(imgMaxUrl, bigPhotoUrl["fileUrl"].(string))
                            picTime = i.Timestamp
                        }
                        lable, lableAttach := Feature2Jsonstr(*face)
                        var target = new(Target)
                        target.TargetId = face.Id
                        target.TargetScore = face.Score
                        target.TargetType = face.Type
                        target.Feature = base64.StdEncoding.EncodeToString(face.Feature)
                        target.PicSmUrl = resp["fileUrl"].(string)
                        target.TargetLocation = Points{TopLeft: Point{face.Location.X, face.Location.Y}, BottomRight: Point{face.Location.X + face.Location.Width, face.Location.Y + face.Location.Height}}
                        target.AttachTarget = SourceTarget{face.AttachArg.Id,face.AttachArg.Score,face.AttachArg.Type,base64.StdEncoding.EncodeToString(face.AttachArg.Feature),"",Points{TopLeft: Point{face.AttachArg.Location.X, face.AttachArg.Location.Y}, BottomRight: Point{face.AttachArg.Location.X + face.AttachArg.Location.Width, face.AttachArg.Location.Y + face.AttachArg.Location.Height}}}
                        var targetInfos []Target
                        targetInfos = append(targetInfos, *target)
func InsertFace(msg structure.ResultMsg,key string, results interface{}) {
        logger.Info("往es插入抓拍数据")
        faces := []*ObjAndRules{}
        faces = PutFace(faces, results.([]structure.Result))
        //logger.Info("整理后的数据:",faces)
        if faces != nil {
            _ = logger.Warn("face不为nil")
            var imgMaxUrl []string = []string{}
            var picTime string = ""
            for _, face := range faces {
                // 上传大图
                // 解压缩并上传图片
                bdata, err := util.UnCompress(msg.Data)
                if err != nil {
                    panic("解压缩图片时出现错误")
                }
                alarmRules := []AlarmRule{}
                //logger.Info("循环每一个目标")
                for _, faceResult := range face.rules {
                    alarm := ChangeToString(faceResult.DefenceState, faceResult.AlarmLevel)
                    alarmRules = append(alarmRules, AlarmRule{faceResult.RuleGroupId, alarm, faceResult.RuleText, faceResult.DefenceState, ""})
                }
                i := protomsg.Image{}
                err = proto.Unmarshal(bdata, &i)
                // 先传小图,再传大图,防止脸上有线
                bytes := util.SubImg(i, int(face.Location.X), int(face.Location.Y), int(face.Location.X+face.Location.Width), int(face.Location.Y+face.Location.Height),face.Type)
                resp, err := util.PostFormBufferData1(weedfsUrl, bytes, uuid.NewV4().String())
                if err != nil {
                    _ = logger.Error("上传小图出错")
                }
                // 上传大图
                if len(imgMaxUrl) == 0 {
                    bigPhotoUrl := make(map[string]interface{})
                    bigPhotoUrl, err = util.DrawPolygonOnImageForFace(msg.Cid, i, msg.RuleResult["face"].([]structure.Result), weedfsUrl)
                    logger.Debug("========大图路径:", bigPhotoUrl)
                    imgMaxUrl = append(imgMaxUrl, bigPhotoUrl["fileUrl"].(string))
                    picTime = i.Timestamp
                }
                lable, lableAttach := Feature2Jsonstr(*face)
                var target = new(Target)
                target.TargetId = face.Id
                target.TargetScore = face.Score
                target.TargetType = face.Type
                target.Feature = base64.StdEncoding.EncodeToString(face.Feature)
                target.PicSmUrl = resp["fileUrl"].(string)
                target.TargetLocation = Points{TopLeft: Point{face.Location.X, face.Location.Y}, BottomRight: Point{face.Location.X + face.Location.Width, face.Location.Y + face.Location.Height}}
                target.AttachTarget = SourceTarget{face.AttachArg.Id,face.AttachArg.Score,face.AttachArg.Type,base64.StdEncoding.EncodeToString(face.AttachArg.Feature),"",Points{TopLeft: Point{face.AttachArg.Location.X, face.AttachArg.Location.Y}, BottomRight: Point{face.AttachArg.Location.X + face.AttachArg.Location.Width, face.AttachArg.Location.Y + face.AttachArg.Location.Height}}}
                var targetInfos []Target
                targetInfos = append(targetInfos, *target)
                        sdkname := ""
                        switch key {
                        case "face":
                            sdkname = "人脸"
                        case "plate":
                            sdkname = "车牌识别"
                        }
                        //logger.Info("人脸目标target:",targetInfos)
                        pervideo := PerVideoPicture{LinkInfo{
                            face.Uuid,
                            msg.Cid,
                            msg.Push.Cam.Addr,
                            msg.Push.Cam.Name,
                            picTime,
                            imgMaxUrl,
                            msg.Tasklab.Taskid,
                            msg.Tasklab.Taskname,
                            sdkname,
                            "",
                            alarmRules,
                            time.Now().Format("2006-01-02 15:04:05"), // 只检测,没有比对时间
                            lable,
                            lableAttach,
                            "",
                            msg.Push.ServerId,
                            msg.Push.ServerName,
                            msg.Push.LocalIp,
                            "",
                            true,
                            false,
                            false,
                            false,
                            face.Liker,
                            targetInfos,
                        },
                            "",
                            []*LinkInfo{},
                        }
                        requstbody, err := json.Marshal(pervideo)
                sdkname := ""
                id := face.Uuid
                switch key {
                case "face":
                    sdkname = "人脸"
                case "plate":
                    sdkname = "车牌识别"
                case "track":
                    sdkname = "人员跟踪"
                    if len(face.Liker) == 1{
                        id = face.Liker[0].TargetId
                    }
                }
                //logger.Info("人脸目标target:",targetInfos)
                        if err != nil {
                            logger.Info("json parse error ", err)
                            return
                        }
                        resp1, err1 := EsReq("POST", videoPersonUrl, requstbody)
                        if err1 != nil {
                            logger.Error("上传ES出错!---", err1)
                        } else {
                            logger.Info("插入es返回的信息:", sdkname, "---", resp1)
                            // 发出录像信号
                            ruleserver.AddLxMessage(&protomsg.VideotapeInfo{EsDataId: face.Uuid, CameraId: msg.Cid, TaskId: msg.Tasklab.Taskid, VideoUrl: msg.Push.VideoUrl, ImgId: i.Id, SdkIds: []string{"-1"}, Type: 1})
                        }
                pervideo := PerVideoPicture{LinkInfo{
                    id,
                    msg.Cid,
                    msg.Push.Cam.Addr,
                    msg.Push.Cam.Name,
                    picTime,
                    imgMaxUrl,
                    msg.Tasklab.Taskid,
                    msg.Tasklab.Taskname,
                    sdkname,
                    "",
                    alarmRules,
                    time.Now().Format("2006-01-02 15:04:05"), // 只检测,没有比对时间
                    lable,
                    lableAttach,
                    "",
                    msg.Push.ServerId,
                    msg.Push.ServerName,
                    msg.Push.LocalIp,
                    "",
                    true,
                    false,
                    false,
                    false,
                    face.Liker,
                    targetInfos,
                },
                    "",
                    []*LinkInfo{},
                }
                requstbody, err := json.Marshal(pervideo)
                if err != nil {
                    logger.Info("json parse error ", err)
                    return
                }
                if key == "track" && len(face.Liker) == 1{
                    esid := face.Liker[0].TargetId
                    returnMsg, err1 := esutil.AppendTargetInfo(esid, string(requstbody),EsInfo.EsIndex.AIOcean.IndexName,serverIp,serverPort)
                    if err1 != nil {
                        _ = logger.Error("追加数据出错!---", err1)
                    } else {
                        logger.Info("插入es返回的信息:", returnMsg)
                        // 发出录像信号
                        ruleserver.AddLxMessage(&protomsg.VideotapeInfo{EsDataId: face.Uuid, CameraId: msg.Cid, TaskId: msg.Tasklab.Taskid, VideoUrl: msg.Push.VideoUrl, ImgId: i.Id, SdkIds: []string{"-1"}, Type: 1})
                    }
                } else {
                    resp1, err1 := EsReq("POST", videoPersonUrl, requstbody)
                    if err1 != nil {
                        _ = logger.Error("上传ES出错!---", err1)
                    } else {
                        logger.Info("插入es返回的信息:", resp1)
                        // 发出录像信号
                        ruleserver.AddLxMessage(&protomsg.VideotapeInfo{EsDataId: face.Uuid, CameraId: msg.Cid, TaskId: msg.Tasklab.Taskid, VideoUrl: msg.Push.VideoUrl, ImgId: i.Id, SdkIds: []string{"-1"}, Type: 1})
                    }
                }
            }
        }
    }
}
// 归置人脸
@@ -274,8 +305,7 @@
}
// 往es中插入yolo数据
func InsertYolo(msg structure.ResultMsg) {
    if msg.RuleResult["yolo"] != nil && len(msg.RuleResult["yolo"].([]structure.Result)) > 0 {
func InsertYolo(msg structure.ResultMsg,key string, results interface{}) {
        // 先判断一下数据带的规则标签是否有可以插入的
        flag := false
        for _, res := range msg.RuleResult["yolo"].([]structure.Result) {
@@ -290,7 +320,7 @@
            alarmRules := []AlarmRule{}
            var targetInfos []Target
            url := []string{}
            for _, yoloResult := range msg.RuleResult["yolo"].([]structure.Result) {
            for _, yoloResult := range results.([]structure.Result) {
                if yoloResult.Others.TimeLabel == "01" || yoloResult.Others.TimeLabel == "10" {
                    // 拼出sdkname
                    //logger.Info("应该进来才对的")
@@ -317,7 +347,7 @@
                            err = proto.Unmarshal(bdata, &i)
                            resp1, err1 := util.DrawPolygonOnImageForYolo(msg1.Cid, i, msg1.RuleResult["yolo"].([]structure.Result), weedfsUrl)
                            if err1 != nil {
                                logger.Error("缓存数据画框或上传图片服务器出错", err)
                                _ = logger.Error("缓存数据画框或上传图片服务器出错", err)
                            } else {
                                logger.Info("上传的图片信息:", resp1)
                            }
@@ -377,7 +407,7 @@
                //resp, err = util.PostFormBufferData(weedfsUrl, i, uuid.NewV4().String())
                resp, err = util.DrawPolygonOnImageForYolo(msg.Cid, i, msg.RuleResult["yolo"].([]structure.Result), weedfsUrl)
                if err != nil {
                    logger.Error("画框或上传图片服务器出错", err)
                    _ = logger.Error("画框或上传图片服务器出错", err)
                    return
                } else {
                    logger.Info("上传的图片信息:", resp)
@@ -431,7 +461,7 @@
                }
                resp1, err2 := EsReq("POST", videoPersonUrl, requstbody)
                if err2 != nil {
                    logger.Error("往ES插入数据失败", err)
                    _ = logger.Error("往ES插入数据失败", err)
                } else {
                    logger.Debug("插入es返回的数据信息是(yolo):", resp1)
                    // 发出录像信号
@@ -440,19 +470,16 @@
                        logger.Info("联动任务的录像信号:", index)
                        ruleserver.AddLxMessage(&protomsg.VideotapeInfo{EsDataId: msg.Push.PushId, CameraId: link.CameraId, TaskId: msg.Tasklab.Taskid, VideoUrl: msg.Push.VideoUrl, ImgId: i.Id, SdkIds: []string{strconv.Itoa(index)}, Type: 2})
                    }
                    logger.Warn("__________________________________________往ES插入yolo数据成功")
                    _ = logger.Warn("__________________________________________往ES插入yolo数据成功")
                    //os.Exit(1)
                }
            }
        }
    } else {
        logger.Debug("timeLabel条件都不符合!")
    }
}
// 插入目标持续时间数据
func InsertTarget(msg structure.ResultMsg) {
func InsertLastTarget(msg structure.ResultMsg) {
    if msg.RuleResult["target"] != nil && len(msg.RuleResult["target"].([]structure.Result)) > 0 {
        // 先判断一下数据带的规则标签是否有可以插入的
        logger.Info("插入定时目标信息:", len(msg.RuleResult["target"].([]structure.Result)))
@@ -517,7 +544,7 @@
                    //resp, err = util.PostFormBufferData(weedfsUrl, i, uuid.NewV4().String())
                    resp, err = util.DrawPolygonOnImageForYolo(msg.Cid, i, msg.RuleResult["target"].([]structure.Result), weedfsUrl)
                    if err != nil {
                        logger.Error("画框或上传图片服务器出错", err)
                        _ = logger.Error("画框或上传图片服务器出错", err)
                        return
                    } else {
                        logger.Info("上传的图片信息:", resp)
@@ -594,7 +621,7 @@
                    }
                    resp1, err2 := EsReq("POST", videoPersonUrl, requstbody)
                    if err2 != nil {
                        logger.Error("往ES插入数据失败", err)
                        _ = logger.Error("往ES插入数据失败", err)
                    } else {
                        logger.Debug("插入es返回的数据信息是(target):", resp1)
                        // 发出录像信号
@@ -603,7 +630,7 @@
                            logger.Info("联动任务的录像信号:", index)
                            ruleserver.AddLxMessage(&protomsg.VideotapeInfo{EsDataId: msg.Push.PushId, CameraId: link.CameraId, TaskId: msg.Tasklab.Taskid, VideoUrl: msg.Push.VideoUrl, ImgId: i.Id, SdkIds: []string{strconv.Itoa(index)}, Type: 2})
                        }
                        logger.Warn("__________________________________________往ES插入target数据成功")
                        _ = logger.Warn("__________________________________________往ES插入target数据成功")
                        //os.Exit(1)
                    }
                }
@@ -677,7 +704,7 @@
    err = proto.Unmarshal(bdata, &i)
    resp1, err1 := util.DrawPolygonOnImageForTarget(msg.Cid, i, msg.RuleResult["target"].([]structure.Result), weedfsUrl)
    if err1 != nil {
        logger.Error("缓存数据画框或上传图片服务器出错", err)
        _ = logger.Error("缓存数据画框或上传图片服务器出错", err)
    } else {
        logger.Info("上传的图片信息:", resp1)
    }
@@ -786,7 +813,7 @@
                            err = proto.Unmarshal(bdata, &i)
                            resp1, err1 := util.DrawPolygonOnImageForYolo(msg1.Cid, i, msg1.RuleResult["yolo"].([]structure.Result), weedfsUrl)
                            if err1 != nil {
                                logger.Error("缓存数据画框或上传图片服务器出错", err)
                                _ = logger.Error("缓存数据画框或上传图片服务器出错", err)
                            } else {
                                logger.Info("上传的图片信息:", resp1)
                            }
@@ -829,7 +856,7 @@
                //resp, err = util.PostFormBufferData(weedfsUrl, i, uuid.NewV4().String())
                resp, err = util.DrawPolygonOnImageForYolo(msg.Cid, i, msg.RuleResult["yolo"].([]structure.Result), weedfsUrl)
                if err != nil {
                    logger.Error("画框或上传图片服务器出错", err)
                    _ = logger.Error("画框或上传图片服务器出错", err)
                    return nil
                } else {
                    logger.Info("上传的图片信息:", resp)
ruleserver/ruleToformula.go
@@ -37,6 +37,7 @@
        args.RuleResult["face"] = []structure.Result{}
        args.RuleResult["target"] = []structure.Result{}
        args.RuleResult["plate"] = []structure.Result{}
        args.RuleResult["track"] = []structure.Result{}
        //logger.Warn("传进去之前是什么德行:",args.RuleResult["yolo"])
        if taskGroup != nil && len(taskGroup.GroupRules) > 0 {
            // 先过独立,再过联动
@@ -137,132 +138,7 @@
        // 进行定时器的处理和判断
        timeFlag := TimerAlarm(&label, groupRule.GroupId, result)
        if timeFlag == "01" || timeFlag == "10" || timeFlag == "11"{ // 没有定时器或者满足定时器条件
            // 打人脸标签和yolo标签
            // 最后成功报警才把符合条件的人脸数据塞进结果标签里
            // 配了人脸的算法才把人脸的数据甩出来打标签
            faces := []*structure.Arg{}
            faceFlag := false
            for j := 0; j < len(groupRule.Rules); j++ {
                if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
                    faceFlag = true
                }
            }
            for _, sdkData := range args.Sdkdata {
                if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" && faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
                    for _, areaMap := range sdkData.AreaMapList {
                        if areaMap.IsEffective {
                            faces = append(faces, putFaceToResult(areaMap, faces)...)
                        }
                    }
                }
            }
            //logger.Info("face标签的长度:",len(faces))
            //for _,face := range faces  {
            //    //logger.Debug("————————————————________________看看人脸的坐标:",face.Location)
            //}
            //logger.Warn("___________________________________________________________________________终于走完万里长征")
            // 把他们的位置数据也传下去
            yolos := []*structure.Arg{}
            for _, sdkData := range args.Sdkdata {
                if sdkData.IpcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && sdkNames != "" { // 把yolo数据的各个目标的坐标输出方便后面画框
                    for _, areaMap := range sdkData.AreaMapList {
                        if areaMap.IsEffective {
                            yolos = append(yolos, putYolosToResult(areaMap)...)
                        }
                    }
                }
            }
            //logger.Debug("------locations的内容:", yolos)
            // 处理目标定时数据
            targets := []*structure.Arg{}
            for _, sdkData := range args.Sdkdata {
                if sdkData.IpcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && sdkNames != "" { // 输出目标数据
                    for _, areaMap := range sdkData.AreaMapList {
                        if areaMap.IsEffective {
                            targets = append(targets, putTargetsToResult(areaMap)...)
                        }
                    }
                }
            }
            // 车辆目标统计
            cars := []*structure.Arg{}
            for _, sdkData := range args.Sdkdata {
                //logger.Info("看看sdkNames",sdkNames)
                if sdkData.IpcId == "91d923ef-6200-4549-ab1b-8e773e85d729" { // 把车牌数据的各个目标的坐标输出方便后面画框
                    for _, areaMap := range sdkData.AreaMapList {
                        if areaMap.IsEffective {
                            cars = append(cars, putFaceToResult(areaMap, cars)...)
                        }
                    }
                }
            }
            // 跟踪目标统计
            personTrack := []*structure.Arg{}
            for _, sdkData := range args.Sdkdata {
                //logger.Info("看看sdkNames",sdkNames)
                if sdkData.IpcId == "跟踪的ipcId" { // 把跟踪页面的各个目标的坐标输出
                    for _, areaMap := range sdkData.AreaMapList {
                        if areaMap.IsEffective {
                            personTrack = append(personTrack, putFaceToResult(areaMap, personTrack)...)
                        }
                    }
                }
            }
            var islink bool
            if groupRule.SetType == "linkTask" {
                islink = true
            } else {
                islink = false
            }
            //logger.Info("触发的区域id:",polygonId)
            var labelTypes []int // 0为yolo标签,1为face标签 2为两者标签
            if sdkNames != "" && len(targets) == 0 {
                args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, yolos, polygonId, islink,label})
                labelTypes = append(labelTypes,0)
                //logger.Info("-------------------yolo结果标签长度", len(args.RuleResult["yolo"].([]Result)))
            }
            if faceFlag {
                args.RuleResult["face"] = append(args.RuleResult["face"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, faces, polygonId, islink,label})
                //logger.Info("-------------------face结果标签", len(args.RuleResult["face"].([]structure.Result)))
                labelTypes = append(labelTypes,1)
            }
            if len(targets) > 0 {
                args.RuleResult["target"] = append(args.RuleResult["target"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, targets, polygonId, islink,label})
                //logger.Info("-------------------目标持续结果标签", len(args.RuleResult["target"].([]structure.Result)))
                //labelTypes = append(labelTypes,2)
            }
            if len(cars) > 0 {
                args.RuleResult["plate"] = append(args.RuleResult["plate"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, cars, polygonId, islink,label})
                //logger.Info("-------------------车牌结果标签", len(args.RuleResult["plate"].([]structure.Result)))
                //labelTypes = append(labelTypes,2)
            }
            if len(personTrack) > 0 {
                args.RuleResult["track"] = append(args.RuleResult["track"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, personTrack, polygonId, islink,label})
                //logger.Info("-------------------车牌结果标签", len(args.RuleResult["plate"].([]structure.Result)))
                //labelTypes = append(labelTypes,2)
            }
            // 给持续时间的第一张赋予缓存数据(遍历复制)
            //if cacheId != "" { // 有这帧数据的缓存
            //    tempMap := make(map[string]interface{})
            //    for k, result := range args.RuleResult {
            //        if k == "yolo" {
            //            tempMap[k] = []structure.Result{}
            //            for _, res := range result.([]structure.Result) {
            //                tempMap[k] = append(tempMap[k].([]structure.Result), res)
            //            }
            //        }
            //        if k == "face" {
            //            tempMap[k] = []structure.Result{}
            //            for _, res := range result.([]structure.Result) {
            //                tempMap[k] = append(tempMap[k].([]structure.Result), res)
            //            }
            //        }
            //    }
            //    rw.Lock()
            //    TimeEleList[cacheId].CacheSdkData.RuleResult = tempMap
            //    rw.Unlock()
            //}
            labelTypes := AssembResultLabel(args,groupRule,sdkNames,taskId,polygonId,label)
            return true,labelTypes
        } else {
            return false,[]int{}
@@ -493,3 +369,87 @@
    return
}
func AssembResultLabel(args *structure.SdkDatas, groupRule *protomsg.GroupRule,sdkNames string,taskId string,polygonId string,label structure.Others) []int{
    faces := []*structure.Arg{}
    yolos := []*structure.Arg{}
    targets := []*structure.Arg{}
    personTrack := []*structure.Arg{}
    cars := []*structure.Arg{}
    faceFlag := false
    for j := 0; j < len(groupRule.Rules); j++ {
        if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
            faceFlag = true
        }
    }
    for _, sdkData := range args.Sdkdata {
        switch sdkData.IpcId {
        case "A8B73405-373D-4F23-CED2-A617EBD7EC55" :
            if faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
                for _, areaMap := range sdkData.AreaMapList {
                    if areaMap.IsEffective {
                        faces = append(faces, putFaceToResult(areaMap, faces)...)
                    }
                }
            }
        case "02D54B61-0F16-C604-8567-FC4BE493C523":
            if sdkNames != "" { // 把yolo数据的各个目标的坐标输出方便后面画框
                for _, areaMap := range sdkData.AreaMapList {
                    if areaMap.IsEffective {
                        yolos = append(yolos, putYolosToResult(areaMap)...)
                        // 处理目标定时数据
                        targets = append(targets, putTargetsToResult(areaMap)...)
                    }
                }
            }
        case "91d923ef-6200-4549-ab1b-8e773e85d729":
            // 车辆数据
            for _, areaMap := range sdkData.AreaMapList {
                if areaMap.IsEffective {
                    cars = append(cars, putFaceToResult(areaMap, cars)...)
                }
            }
        case "跟踪的ipcId":
            // 跟踪目标
            for _, areaMap := range sdkData.AreaMapList {
                if areaMap.IsEffective {
                    personTrack = append(personTrack, putFaceToResult(areaMap, personTrack)...)
                }
            }
        }
    }
    var islink bool
    if groupRule.SetType == "linkTask" {
        islink = true
    } else {
        islink = false
    }
    //logger.Info("触发的区域id:",polygonId)
    var labelTypes []int // 0为yolo标签,1为face标签 2为两者标签
    if sdkNames != "" && len(targets) == 0 {
        args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, yolos, polygonId, islink,label})
        labelTypes = append(labelTypes,0)
        //logger.Info("-------------------yolo结果标签长度", len(args.RuleResult["yolo"].([]Result)))
    }
    if faceFlag {
        args.RuleResult["face"] = append(args.RuleResult["face"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, faces, polygonId, islink,label})
        //logger.Info("-------------------face结果标签", len(args.RuleResult["face"].([]structure.Result)))
        labelTypes = append(labelTypes,1)
    }
    if len(targets) > 0 {
        args.RuleResult["target"] = append(args.RuleResult["target"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, targets, polygonId, islink,label})
        //logger.Info("-------------------目标持续结果标签", len(args.RuleResult["target"].([]structure.Result)))
        labelTypes = append(labelTypes,2)
    }
    if len(cars) > 0 {
        args.RuleResult["plate"] = append(args.RuleResult["plate"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, cars, polygonId, islink,label})
        //logger.Info("-------------------车牌结果标签", len(args.RuleResult["plate"].([]structure.Result)))
        labelTypes = append(labelTypes,3)
    }
    if len(personTrack) > 0 {
        args.RuleResult["track"] = append(args.RuleResult["track"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, personTrack, polygonId, islink,label})
        //logger.Info("-------------------车牌结果标签", len(args.RuleResult["plate"].([]structure.Result)))
        labelTypes = append(labelTypes,4)
    }
    return labelTypes
}
structure/rule.go
@@ -45,8 +45,7 @@
    IsEffective   bool   // 规则中是否用到了此区域
}
// sdk输出的图片上单个目标的数据
type PhotoMap struct {
type SourcePhoto struct {
    Id      string
    Rects   Rect    // 矩形区域参数
    Score   float64 // 相似度得分(有多大程度像一个目标。人脸,人体或车等等)
@@ -55,6 +54,11 @@
    Feature []byte
    Car     *protomsg.PlateIDVehicle
}
// sdk输出的图片上单个目标的数据
type PhotoMap struct {
    SourcePhoto
    AttachObj SourcePhoto
}
// 每个算法对于当前帧画面自己提取的数据
type SdkData struct {