package controllers import ( "basic.com/valib/bhomeclient.git" "basic.com/valib/bhomedbapi.git" "basic.com/fileServer/WeedFSClient.git" esApi "basic.com/pubsub/esutil.git" "basic.com/pubsub/protomsg.git" "basic.com/valib/godraw.git" "basic.com/valib/logger.git" "encoding/base64" "errors" "github.com/satori/go.uuid" "image" "image/color" "path" "strconv" "strings" "sync" "time" "vamicro/config" "vamicro/extend/util" "vamicro/compTable-service/models" "vamicro/compTable-service/service" ) type FileController struct { } // weedfs 访问路径 //var picIp = "http://192.168.1.182:6080/" var picIp = "http://" var picUrlField = "fileUrl" // @Security ApiKeyAuth // @Summary 图片上传 // @Description 图片上传 // @Accept multipart/form-data // @Produce json // @Tags 图片上传 // @Param file formData file true "图片" // @Param picType formData string true "图片类型,0:车辆照片,1:人脸照片" // @Success 200 {string} json "{"code":200, msg:"", success:true}" // @Failure 500 {string} json "{"code":500, msg:"", success:false}" // @Router /data/api-v/dbperson/fileupload [POST] func (fc FileController) Fileupload(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //得到上传的文件 file, err := c.FormFile() //image这个是uplaodify参数定义中的 'fileObjName':'image' picType := c.PostForm("picType") //图片类型 filename := c.PostForm("fileName") if err != nil || (picType != "0" && picType != "1") { return &bhomeclient.Reply{Success:false,Msg:"参数有误"} } //文件的名称 var result = make(map[string]string) if picType == "1" { _, _, err, faceFeature, faceUrlPath := uploadFileReturnAddr(file.Bytes, filename, "", false) if err != nil { if err.Error() == "NotFeatureFindError" { return &bhomeclient.Reply{Success:false, Msg:"未提取到人脸"} } else { return &bhomeclient.Reply{Success:false,Msg:err.Error()} } } result["picUrl"] = faceUrlPath result["faceFeature"] = faceFeature } else { var sApi bhomedbapi.SysSetApi flag, localConf := sApi.GetServerInfo() if !flag || localConf.AlarmIp == "" ||localConf.AlarmPort ==0 { logger.Debug("localConf err") return &bhomeclient.Reply{Success:false, Msg: "localConf err"} } var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent" weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, filename, file.Bytes, 5*time.Second) if e != nil { logger.Debug("WeedFSClient.UploadFile err:", e) return &bhomeclient.Reply{Success:false,Msg:"UploadFile err"} } result["picUrl"] = weedFilePath } return &bhomeclient.Reply{Success:true,Data:result} } /* type FaceExtract struct { Url string `json:"url"` FaceBytes []byte `json:"faceBytes"` } var faceExtractedMap = make(map[string]FaceExtract,0) // @Security ApiKeyAuth // @Summary 人脸提取 // @Description 人脸提取 // @Accept multipart/form-data // @Produce json // @Tags 以图搜图 // @Param file formData file true "人员图片" // @Success 200 {string} json "{"code":200, msg:"", data:"", success:true}" // @Failure 500 {string} json "{"code":500, msg:"", data:"", success:false}" // @Router /data/api-v/dbperson/faceExtract [POST] func (fc FileController) FaceExtract(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { file, err := c.FormFile() //image这个是uplaodify参数定义中的 'fileObjName':'image' if err != nil { return &bhomeclient.Reply{Success:false,Msg:"参数有误"} } var sApi bhomedbapi.SysSetApi flag, localConf := sApi.GetServerInfo() if !flag || localConf.AlarmIp == "" ||localConf.AlarmPort ==0 { logger.Debug("localConf err") return &bhomeclient.Reply{Success:false, Msg: "localConf err"} } var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent" logger.Debug("weedfsUri:",weedfsUri) resultMap :=make(map[string]interface{},0) //将上传的图片交人脸检测和人脸提取,获得特征 faceArr, err, pI := service.GetFaceFeaFromSdk(file.Bytes, time.Second*60) if err ==nil && len(faceArr) >0 { //1.提取每一张人脸小图 urlArr := make([]string,0) for _,r := range faceArr { rcFace := r.Pos.RcFace cutFaceImgData,cutErr := util.SubCutImg(pI, rcFace, 20) if cutErr != nil { logger.Debug("util.SubCutImg err:", cutErr) continue } weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", cutFaceImgData, 5) if e == nil{ faceExtractedMap[weedFilePath] = FaceExtract{ Url:weedFilePath, FaceBytes:r.Feats, } urlArr = append(urlArr, weedFilePath) } } //2.大图画框,标识人脸位置 drawedB, _ := drawPolygonOnImg(pI, &faceArr) originFilePath, _ := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", *drawedB, 5) resultMap["uploadImage"] = originFilePath resultMap["smImage"] = urlArr return &bhomeclient.Reply{Success:true,Data:resultMap} } else { return &bhomeclient.Reply{Msg:"未提取到人脸"} } }*/ func drawPolygonOnImg(i *protomsg.Image,faceArr *[]*protomsg.ResultFaceDetect) (*[]byte,error) { img,err := godraw.ToImage(i.Data, int(i.Width), int(i.Height)) if err != nil { return nil,err } red := color.RGBA{255, 0, 0, 0} for _,faceResult := range *faceArr { util.DrawRect(img.(*image.RGBA),int(faceResult.Pos.RcFace.Left),int(faceResult.Pos.RcFace.Top),int(faceResult.Pos.RcFace.Right), int(faceResult.Pos.RcFace.Bottom), red) } quantity := 100 jpgData, err := godraw.ImageToJpeg(img, &quantity) return &jpgData,err } type CompareResult struct { Id string `json:"id"` CompareScore float64 `json:"compareScore"` CameraId string `json:"cameraId"` CameraName string `json:"cameraName"` CameraAddr string `json:"cameraAddr"` PicDate string `json:"picDate"` Content string `json:"content"` IsAlarm bool `json:"isAlarm"` PicMaxUrl []string `json:"picMaxUrl"` TargetInfo []TargetInfo `json:"targetInfo"` TaskId string `json:"taskId"` TaskName string `json:"taskName"` BaseInfo []DbPersonVo `json:"baseInfo"` VideoUrl string `json:"videoUrl"` SdkName string `json:"sdkName"` AlarmRules []AlarmRuleVo `json:"alarmRules"` } type TargetInfo struct { TargetId string `json:"targetId"` TargetType string `json:"targetType"` TargetScore float64 `json:"targetScore"` Feature string `json:"feature"` PicSmUrl string `json:"picSmUrl"` TargetLocation TargetLocation `json:"targetLocation"` } type TargetLocation struct { TopLeft protomsg.Location `json:"topLeft"` BottomRight protomsg.Location `json:"bottomRight"` } type DbPersonVo struct { TableId string `json:"tableId"` TableName string `json:"tableName"` BwType string `json:"bwType"` CompareScore float64 `json:"compareScore"` TargetId string `json:"targetId"` TargetName string `json:"targetName"` TargetPicUrl string `json:"targetPicUrl"` MonitorLevel string `json:"monitorLevel"` Labels string `json:"labels"` Content string `json:"content"` Enable int32 `json:"enable"` } type ScoreIndex struct { CompareScore float64 Index int } type AlarmRuleVo struct { GroupId string `json:"groupId"` AlarmLevel string `json:"alarmLevel"` RuleText string `json:"ruleText"` DefenceState bool `json:"defenceState"` IsLink bool `json:"isLink"` LinkInfo string `json:"linkInfo"` } //填充向前端返回的数据 func FillDataToCompareResult(compResult *protomsg.SdkCompareResult) []CompareResult { var resultList = make([]CompareResult, len(compResult.CompareResult)) dbPersonM := make(map[string]ScoreIndex, 0) captureM := make(map[string]ScoreIndex, 0) personIds := make([]string,0) captureIds := make([]string,0) for idx,v :=range compResult.CompareResult{ if v.Tableid == "capturetable" { captureM[v.Id] = ScoreIndex{ Index: idx, CompareScore: util.ParseScore64(float64(v.CompareScore)), } captureIds = append(captureIds,v.Id) } else { dbPersonM[v.Id] = ScoreIndex{ Index: idx, CompareScore: util.ParseScore64(float64(v.CompareScore)), } personIds = append(personIds,v.Id) } } logger.Debug("comp len(personIds):", len(personIds)) logger.Debug("comp len(captureIds):", len(captureIds)) var dbpersons []protomsg.Dbperson if len(personIds) >0 { var dbpApi bhomedbapi.DbPersonApi dbpersons, _ = dbpApi.Dbpersoninfosbyid(personIds) } if len(dbpersons) >0 { var dtApi bhomedbapi.DbTableApi for _,p :=range dbpersons { var dbP = DbPersonVo { TargetId: p.Id, CompareScore: dbPersonM[p.Id].CompareScore, MonitorLevel: p.MonitorLevel, TargetName: p.PersonName, TargetPicUrl: p.PersonPicUrl, Labels: p.PhoneNum+"/"+p.Sex+"/"+p.IdCard, TableId: p.TableId, Content: p.Reserved, Enable: p.Enable, } dbTableInfos, _ := dtApi.DbtablesById([]string{ p.TableId }) if dbTableInfos !=nil{ dbP.BwType = dbTableInfos[0].BwType dbP.TableName = dbTableInfos[0].TableName } resultList[dbPersonM[p.Id].Index] = CompareResult{ BaseInfo:[]DbPersonVo{ dbP }, } } } if len(captureIds) >0 { var sApi bhomedbapi.SysSetApi flag, localConf := sApi.GetServerInfo() if !flag || localConf.AlarmIp == "" ||localConf.AlarmPort ==0 { logger.Debug("localConf err") return nil } logger.Debug("captureIds:",strings.Join(captureIds,",")) aiTargets, _ := esApi.AIOceaninfosbyid(captureIds, config.EsInfo.EsIndex.AiOcean.IndexName, localConf.AlarmIp, strconv.Itoa(int(localConf.AlarmPort))) logger.Debug("comp aiTargets.len:",len(aiTargets)) for _,vp :=range aiTargets { var bi []DbPersonVo for _,p :=range vp.BaseInfo { bi = append(bi, DbPersonVo{ TargetId: p.TargetId, CompareScore: util.ParseScore64(p.CompareScore), MonitorLevel: p.MonitorLevel, TargetName: p.TargetName, TargetPicUrl: p.TargetPicUrl, Labels: p.Labels, TableId: p.TableId, BwType: p.BwType, TableName: p.TableName, }) } var alarmRules []AlarmRuleVo if vp.AlarmRules !=nil && len(vp.AlarmRules) >0 { for _,ar :=range vp.AlarmRules { alarmRules = append(alarmRules, AlarmRuleVo{ GroupId: ar.GroupId, AlarmLevel: ar.AlarmLevel, RuleText: ar.RuleText, DefenceState: ar.DefenceState, IsLink: ar.IsLink, LinkInfo: ar.LinkInfo, }) } } var ti = make([]TargetInfo,0) if vp.TargetInfo !=nil { for _,vti :=range vp.TargetInfo { tl := protomsg.Location{ X: vti.TargetLocation.TopLeft.X, Y: vti.TargetLocation.TopLeft.Y, } br := protomsg.Location{ X: vti.TargetLocation.BottomRight.X, Y: vti.TargetLocation.BottomRight.Y, } tInfo := TargetInfo{ TargetId: vti.TargetId, TargetType: vti.TargetType, TargetScore: vti.TargetScore, Feature: vti.Feature, PicSmUrl: vti.PicSmUrl, TargetLocation: TargetLocation{ TopLeft:tl, BottomRight:br, }, } ti = append(ti, tInfo) } } vpE := CompareResult{ Id: vp.Id, CompareScore: captureM[vp.Id].CompareScore, CameraId: vp.CameraId, CameraName: vp.CameraName, CameraAddr: vp.CameraAddr, PicDate: vp.PicDate, PicMaxUrl: vp.PicMaxUrl, TargetInfo: ti, IsAlarm: vp.IsAlarm, TaskName: vp.TaskName, TaskId: vp.TaskId, VideoUrl: vp.VideoUrl, BaseInfo: bi, SdkName: "人脸", AlarmRules: alarmRules, } resultList[captureM[vp.Id].Index] = vpE } } return resultList } func parseMonitorLevel(level string) string { if level == "1" { return "一级" } if level == "2" { return "二级" } if level == "3" { return "三级" } return level } type PersonId struct { Id string `json:"id"` } // @Description 人员照片上传并获取特征值 // @Router /data/api-v/dbperson/fileUploadTest [POST] func (fc FileController) UploadPersonTest(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { file, err := c.FormFile() //image这个是uplaodify参数定义中的 'fileObjName':'image' if err != nil { return &bhomeclient.Reply{Msg:"参数有误"} } var sApi bhomedbapi.SysSetApi flag, localConf := sApi.GetServerInfo() if !flag || localConf.AlarmIp == "" ||localConf.AlarmPort ==0 { logger.Debug("localConf err") return &bhomeclient.Reply{Success:false, Msg: "localConf err"} } var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent" //将上传的图片交人脸检测和人脸提取,获得特征 faceArr, err, pI := service.GetFaceFeaFromSdk(file.Bytes, time.Second*5) if err ==nil && len(faceArr) >0 { var faceBase64= "" var rcFace *protomsg.Rect for _,r := range faceArr { rcFace = r.Pos.RcFace faceBase64 = base64.StdEncoding.EncodeToString(r.Feats)//获取提取到的第一张人脸特征 break } //根据人脸坐标扣出人脸小图 cutFaceImgData,_ := util.SubCutImg(pI, rcFace, 20) weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "testCutFace", cutFaceImgData, 5 * time.Second) if e !=nil{ return &bhomeclient.Reply{Msg:"文件上传失败"} } else { return &bhomeclient.Reply{Success:true,Data:weedFilePath + ";" + faceBase64} } } else { return &bhomeclient.Reply{Msg:"未提取到人脸"} } } func uploadFileReturnAddr(fileBytes []byte, filename string, tableId string, add2Db bool) (string, map[string]interface{}, error, string, string) { //将上传的图片交人脸检测和人脸提取,获得特征 var faceBase64="" faceArr, err, pI := service.GetFaceFeaFromSdk(fileBytes, time.Second*5) if faceArr ==nil { return "",nil,errors.New("NotFeatureFindError"),"","" } var rcFace *protomsg.Rect if err ==nil && len(faceArr) >0 { if len(faceArr) >1 { return "",nil, errors.New("TooManyFaces"),"","" } for _,r := range faceArr { //拿到人脸的坐标 rcFace = r.Pos.RcFace faceBase64 = base64.StdEncoding.EncodeToString(r.Feats)//获取提取到的第一张人脸特征 break } } var sApi bhomedbapi.SysSetApi flag, localConf := sApi.GetServerInfo() if !flag || localConf.AlarmIp == "" ||localConf.AlarmPort ==0 { logger.Debug("localConf err") return "",nil,errors.New("localConf err"),"","" } var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent" //根据人脸坐标扣出人脸小图 t1 := time.Now() cutFaceImgData,cutErr := util.SubCutImg(pI, rcFace, 20) if cutErr != nil { logger.Debug("util.SubCutImg err:", cutErr) return "", nil, cutErr,"","" } logger.Debug("SubImg用时:", time.Since(t1)) t1 = time.Now() weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, filename, cutFaceImgData, 5 * time.Second) logger.Debug("上传到weedfs用时:", time.Since(t1)) t1 = time.Now() if e != nil { logger.Debug("WeedFSClient.UploadFile err:", e) return "", nil, e,"","" } ext := path.Ext(filename) fileNameOnly := strings.TrimSuffix(filename, ext) var result = make(map[string]interface{}) if add2Db { dbperson := new(models.Dbtablepersons) dbperson.Id = uuid.NewV4().String() dbperson.PersonPicUrl = weedFilePath // 图片路经 dbperson.TableId = tableId // dbperson.PersonName = fileNameOnly // 图片名 dbperson.Enable = 1 //默认有效 dbperson.FaceFeature = faceBase64 // 特征值base64 码 dbperson.PriInsert() if ab,_ := dbperson.Add(); ab{ data := make(map[string]interface{}) data["uuid"] = dbperson.Id result["data"] = data result["success"] = true result["msg"] = "添加成功" } else { result["data"] = nil result["success"] = false result["msg"] = "服务器异常" result["code"] = 500 } } logger.Debug("addDbPerson用时:", time.Since(t1), "result:", result) return fileNameOnly, result, nil,faceBase64, weedFilePath } /**上传方法**/ // @Security ApiKeyAuth // @Summary 批量添加底库人员 // @Description 依据图片批量添加底库人员 // @Accept multipart/form-data // @Produce json // @Tags dbperson 底库人员 // @Param files formData file[] true "多个底库人员图片" // @Param tableId formData string false "底库id,有id 则加入底库,无则只上传图片" // @Success 200 {string} json "{"code":200, msg:"目录结构数据", success:true,data:{}}" // @Failure 500 {string} json "{"code":500, msg:"返回错误信息", success:false,data:null}" // @Router /data/api-v/dbperson/moreFileUpload [POST] func (fc FileController) MoreFileUpload(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //得到上传的文件 //image这个是uplaodify参数定义中的 'fileObjName':'image' fileArr, err := c.FormFiles() tableId := c.PostForm("tableId") if err != nil { return &bhomeclient.Reply{Msg:"参数有误"} } extNames := make([]string, 0) addResult := make(map[string]interface{}, 0) successList := make([]string,0) failList := make([]string,0) noFaceList := make([]string,0) multiFaceList := make([]string,0) tAllStart := time.Now() var wg sync.WaitGroup var lock sync.Mutex for _, fa := range *fileArr { wg.Add(1) go func(f bhomeclient.FileArg,tableId string) { defer wg.Done() tIStart := time.Now() filename := f.Name fileExt := path.Ext(filename) fileExt = strings.ToLower(fileExt) if fileExt !=".jpg" && fileExt != ".jpeg" && fileExt != ".png" { lock.Lock() failList = append(failList, filename) lock.Unlock() return } field, _, err1,_,_ := uploadFileReturnAddr(f.Bytes, filename, tableId, true) lock.Lock() if err1 != nil || field == "" { if err1 !=nil && err1.Error() == "NotFeatureFindError" { noFaceList = append(noFaceList, filename) } else if err1 !=nil && err1.Error() == "TooManyFaces" { multiFaceList = append(multiFaceList, filename) } else { failList = append(failList, filename) } } else { successList = append(successList, filename) } lock.Unlock() logger.Debug(filename,"切图用时:",time.Since(tIStart)) }(fa, tableId) wg.Wait() } logger.Debug("切",len(*fileArr),"张人脸用时:", time.Since(tAllStart)) addResult["successList"] = successList addResult["failList"] = failList addResult["noFaceList"] = noFaceList addResult["multiFaceList"] = multiFaceList addResult["fields"] = extNames if len(successList)>0 { return &bhomeclient.Reply{Success:true,Data:addResult} } else { return &bhomeclient.Reply{Msg:"上传失败",Data:addResult} } } type EsPersonSave struct { FaceFeature string `json:"faceFeature"` TableId string `json:"tableId"` Id string `json:"id"` PersonPicUrl string `json:"personPicUrl"` IdCard string `json:"idCard"` }