sunty
2020-08-20 9303b69ea569bcb5e581147543a3fd58e90d0d25
controllers/fileController.go
@@ -3,33 +3,35 @@
import (
   "basic.com/dbapi.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"
   "bytes"
   "encoding/base64"
   "encoding/json"
   "errors"
   "fmt"
   "github.com/gin-gonic/gin"
   "github.com/satori/go.uuid"
   "image"
   "image/color"
   "image/jpeg"
   "io/ioutil"
   "log"
   "mime/multipart"
   "net/http"
   "path"
   "sort"
   "strconv"
   "strings"
   "sync"
   "time"
   "webserver/cache"
   "webserver/extend/code"
   "webserver/extend/config"
   "webserver/extend/esutil"
   "webserver/extend/logger"
   "webserver/extend/util"
   "webserver/models"
   "webserver/service"
   esApi "basic.com/pubsub/esutil.git"
)
type FileController struct {
@@ -46,57 +48,65 @@
//var weedfsUri = "http://192.168.1.182:9500/submit"
// @Summary 依据图片添加底库人员
// @Description  依据图片添加底库返回数据人员
// @Accept  mpfd
// @Security ApiKeyAuth
// @Summary 图片上传
// @Description  图片上传
// @Accept  multipart/form-data
// @Produce json
// @Tags dbperson 底库人员
// @Param file formData file true "底库人员图片"
// @Param tableId formData string false "底库id,有id 则加入底库,无则只上传图片"
// @Success 200 {string} json "{"code":200, msg:"目录结构数据", success:true}"
// @Failure 500 {string} json "{"code":500,  msg:"返回错误信息", success:false}"
// @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(c *gin.Context) {
   //得到上传的文件
   file, header, err := c.Request.FormFile("file") //image这个是uplaodify参数定义中的   'fileObjName':'image'
   tableId := c.Request.FormValue("tableId")
   if err != nil {
      c.String(http.StatusBadRequest, "Bad request")
   picType := c.Request.FormValue("picType") //图片类型
   if err != nil || (picType != "0" && picType != "1") {
      util.ResponseFormat(c, code.RequestParamError, "参数有误")
      return
   }
   //文件的名称
   filename := header.Filename
   fmt.Println(file, err, filename)
   if err != nil {
      log.Fatal(err)
      filename = uuid.NewV4().String()
   }
   // fastdfs
   {
      //fileSuffix := path.Ext(filename)[1:] //获取文件后缀
      //fmt.Println("文件后缀 =", fileSuffix)
      //data, _ := ioutil.ReadAll(file)
      // fastdfs 上传  暂废弃
      //field := fdfsclient.UploadFileByBuffer(data, fileSuffix)
   }
   fileNameOnly, result, err := uploadFileReturnAddr(file, filename, tableId)
   if err != nil {
      if err.Error() == "NotFeatureFindError" {
         util.ResponseFormat(c, code.NotFeatureFindError, filename)
      } else {
         util.ResponseFormat(c, code.ServiceInsideError, err.Error())
   var result = make(map[string]string)
   if picType == "1" {
      _, _, err, faceFeature, faceUrlPath := uploadFileReturnAddr(file, filename, "", false)
      if err != nil {
         if err.Error() == "NotFeatureFindError" {
            util.ResponseFormat(c, code.NotFeatureFindError, filename)
         } else {
            util.ResponseFormat(c, code.ServiceInsideError, err.Error())
         }
         return
      }
      return
   }
   if tableId != "" { //  上传
      if result["success"].(bool) {
         util.ResponseFormat(c, code.Success, result["data"])
      } else {
         util.ResponseFormat(c, code.ServiceInsideError, result["data"])
      }
      result["picUrl"] = faceUrlPath
      result["faceFeature"] = faceFeature
   } else {
      util.ResponseFormat(c, code.Success, fileNameOnly)
      localConf, err2 := cache.GetServerInfo()
      if err2 !=nil || localConf.WebPicIp == "" {
         logger.Debug("localConfig is wrong!!!")
         util.ResponseFormat(c,code.ComError,"")
         return
      }
      defer file.Close()
      // weedfs 上传
      fileBytes, err := ioutil.ReadAll(file)
      if err !=nil {
         util.ResponseFormat(c,code.ComError,"")
         return
      }
      var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
      weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, filename, fileBytes)
      if e != nil {
         logger.Debug("WeedFSClient.UploadFile err:", e)
         util.ResponseFormat(c,code.ComError,"UploadFile err")
         return
      }
      result["picUrl"] = weedFilePath
   }
   util.ResponseFormat(c, code.Success, result)
}
@@ -106,8 +116,10 @@
}
var faceExtractedMap = make(map[string]FaceExtract,0)
// @Security ApiKeyAuth
// @Summary 人脸提取
// @Description  人脸提取
// @Accept multipart/form-data
// @Produce json
// @Tags 以图搜图
// @Param file formData file true "人员图片"
@@ -120,7 +132,13 @@
      util.ResponseFormat(c, code.RequestParamError, "参数有误")
      return
   }
   var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit"
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.WebPicIp == "" {
      logger.Debug("localConfig is wrong!!!")
      return
   }
   var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
   logger.Debug("weedfsUri:",weedfsUri)
   resultMap :=make(map[string]interface{},0)
   //将上传的图片交人脸检测和人脸提取,获得特征
   fileBytes, _ := ioutil.ReadAll(file)
@@ -130,7 +148,11 @@
      urlArr := make([]string,0)
      for _,r := range faceArr {
         rcFace := r.Pos.RcFace
         cutFaceImgData := util.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom))
         cutFaceImgData,cutErr := util.SubCutImg(pI, rcFace, 20)
         if cutErr != nil {
            logger.Debug("util.SubCutImg err:", cutErr)
            continue
         }
         weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", cutFaceImgData)
         if e == nil{
            faceExtractedMap[weedFilePath] = FaceExtract{
@@ -141,7 +163,9 @@
         }
      }
      //2.大图画框,标识人脸位置
      originFilePath, _ := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", fileBytes)
      drawedB, _ := drawPolygonOnImg(pI, &faceArr)
      originFilePath, _ := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", *drawedB)
      resultMap["uploadImage"] = originFilePath
      resultMap["smImage"] = urlArr
      util.ResponseFormat(c,code.Success, resultMap)
@@ -150,43 +174,81 @@
   }
}
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 float32 `json:"compareScore"`
   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 int `json:"isAlarm"`
   PicMaxUrl string `json:"picMaxUrl"`
   PicSmUrl []string `json:"picSmUrl"`
   Sex string `json:"sex"`
   AgeDescription string `json:"ageDescription"`
   Race string `json:"race"`
   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 {
   BwType string `json:"bwType"`
   CompareScore float32 `json:"compareScore"`
   IdCard string `json:"idCard"`
   MonitorLevel string `json:"monitorLevel"`
   PersonId string `json:"personId"`
   PersonName string `json:"personName"`
   PersonPicUrl string `json:"personPicUrl"`
   PhoneNum string `json:"phoneNum"`
   Sex string `json:"sex"`
   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 float32
   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"`
}
//填充向前端返回的数据
@@ -201,42 +263,41 @@
      if v.Tableid == service.CaptureTable {
         captureM[v.Id] = ScoreIndex{
            Index: idx,
            CompareScore: v.CompareScore,
            CompareScore: util.ParseScore64(float64(v.CompareScore)),
         }
         captureIds = append(captureIds,v.Id)
      } else {
         dbPersonM[v.Id] = ScoreIndex{
            Index: idx,
            CompareScore: v.CompareScore,
            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))
   esServerIp := config.EsInfo.Masterip
   esServerPort := config.EsInfo.Httpport
   index := config.EsInfo.EsIndex.Dbtablepersons.IndexName
   var dbpersons []protomsg.Dbperson
   if len(personIds) >0 {
      dbpersons, _ = esApi.Dbpersoninfosbyid(personIds, index, esServerIp, esServerPort)
      var dbpApi dbapi.DbPersonApi
      dbpersons, _ = dbpApi.Dbpersoninfosbyid(personIds)
   }
   if len(dbpersons) >0 {
      var dtApi dbapi.DbTableApi
      for _,p :=range dbpersons {
         var dbP = DbPersonVo {
            PersonId: p.Id,
            IdCard: p.IdCard,
            CompareScore: util.ParseScore(dbPersonM[p.Id].CompareScore),
            TargetId: p.Id,
            CompareScore: dbPersonM[p.Id].CompareScore,
            MonitorLevel: p.MonitorLevel,
            PersonName: p.PersonName,
            PersonPicUrl: p.PersonPicUrl,
            PhoneNum: p.PhoneNum,
            Sex: p.Sex,
            TargetName: p.PersonName,
            TargetPicUrl: p.PersonPicUrl,
            Labels: p.PhoneNum+"/"+p.Sex+"/"+p.IdCard,
            TableId: p.TableId,
            Content: p.Reserved,
            Enable: p.Enable,
         }
         dbTableInfos, _ := esApi.Dbtablefosbyid([]string{p.TableId}, config.EsInfo.EsIndex.DbTables.IndexName, esServerIp, esServerPort)
         dbTableInfos, _ := dtApi.DbtablesById([]string{ p.TableId })
         if dbTableInfos !=nil{
            dbP.BwType = dbTableInfos[0].BwType
            dbP.TableName = dbTableInfos[0].TableName
@@ -248,43 +309,83 @@
      }
   }
   if len(captureIds) >0 {
      videopersons, _ := esApi.Videopersonsinfosbyid(captureIds, config.EsInfo.EsIndex.VideoPersons.IndexName, config.EsInfo.Masterip, config.EsInfo.Httpport)
      logger.Debug("comp videoPersons.len:",len(videopersons))
      for _,vp :=range videopersons {
         isAlarmInt, _ := strconv.Atoi(vp.IsAlarm)
         bi := make([]DbPersonVo,0)
      localConf, err2 := cache.GetServerInfo()
      if err2 !=nil || localConf.AlarmIp == "" || localConf.ServerId == "" {
         logger.Debug("localConfig is wrong!!!")
         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{
               PersonId: p.PersonId,
               IdCard: p.IdCard,
               CompareScore: util.ParseScore(p.CompareScore),
               MonitorLevel: parseMonitorLevel(p.MonitorLevel),
               PersonName: p.PersonName,
               PersonPicUrl: p.PersonPicUrl,
               PhoneNum: p.PhoneNum,
               Sex: p.Sex,
               TargetId: p.TargetId,
               CompareScore: util.ParseScore64(p.CompareScore),
               MonitorLevel: p.MonitorLevel,
               TargetName: p.TargetName,
               TargetPicUrl: p.TargetPicUrl,
               Labels: p.Labels,
               TableId: p.TableId,
               BwType: strconv.Itoa(int(p.BwType)),
               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: util.ParseScore(captureM[vp.Id].CompareScore),
            CompareScore: captureM[vp.Id].CompareScore,
            CameraId: vp.CameraId,
            CameraName: vp.CameraName,
            CameraAddr: vp.CameraAddr,
            PicDate: vp.PicDate,
            PicMaxUrl: vp.PicMaxUrl,
            PicSmUrl: vp.PicSmUrl,
            IsAlarm: isAlarmInt,
            Sex: vp.Sex,
            AgeDescription: vp.AgeDescription,
            Race: vp.Race,
            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
      }
@@ -305,6 +406,37 @@
   return level
}
func GetFeaFromOneFaceImg(fileBytes []byte) (faceB []byte,oriImg string,smImgs []string, err error){
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.WebPicIp == "" {
      logger.Debug("localConfig is wrong!!!")
      return nil,"",nil,errors.New("localConf err")
   }
   var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
   logger.Debug("weedfsUri:",weedfsUri)
   faceArr, err, pI := service.GetFaceFeaFromSdk(fileBytes, time.Second*60)
   if err ==nil && len(faceArr) ==1 {
      rcFace := faceArr[0].Pos.RcFace
      cutFaceImgData,_ := util.SubCutImg(pI, rcFace, 20)
      weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", cutFaceImgData)
      if e == nil{
         faceExtractedMap[weedFilePath] = FaceExtract{
            Url:weedFilePath,
            FaceBytes:faceArr[0].Feats,
         }
         smImgs = append(smImgs, weedFilePath)
      }
      //2.大图画框,标识人脸位置
      drawedB, _ := drawPolygonOnImg(pI, &faceArr)
      originFilePath, _ := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", *drawedB)
      return faceArr[0].Feats,originFilePath,smImgs,nil
   } else {
      return nil,"",nil,errors.New("no face")
   }
}
// @Security ApiKeyAuth
// @Summary 以图搜图
// @Description  以图搜图
// @Accept json
@@ -314,49 +446,73 @@
// @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/searchByPhoto [POST]
func (controller FileController) SearchByPhoto(c *gin.Context) {
func (fc FileController) SearchByPhoto(c *gin.Context) {
   var searchBody models.EsSearch
   err := c.BindJSON(&searchBody)
   if err !=nil{
      util.ResponseFormat(c, code.RequestParamError, "参数有误")
      return
   }
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.AlarmIp == "" || localConf.ServerId == "" {
      logger.Debug("localConfig is wrong!!!")
      util.ResponseFormat(c,code.ComError,"localConf wrong")
      return
   }
   var faceB []byte
   if searchBody.CaptureId != "" {//做查找此人,搜所有抓拍和底库
      searchBase64Fea, err := esApi.GetVideoPersonFaceFeatureById(searchBody.CaptureId, config.EsInfo.EsIndex.VideoPersons.IndexName, config.EsInfo.Masterip, config.EsInfo.Httpport)
      if err !=nil {
         util.ResponseFormat(c, code.ComError, "抓拍数据不存在,请检查")
         return
      }
      if searchBase64Fea !=""{
         decodeF, err := base64.StdEncoding.DecodeString(searchBase64Fea)
         if err !=nil {
            util.ResponseFormat(c, code.ComError, "本条抓怕特征不是base64,请检查")
   logger.Debug("compTargetId:",searchBody.CompTargetId,",compTargetType:",searchBody.CompTargetType)
   if searchBody.CompTargetId != "" {//做查找此人,按抓拍的人脸或者底库的人脸以图搜图
      if searchBody.CompTargetType == 0 {//本张人脸是底库人脸
         var dbpApi dbapi.DbPersonApi
         dbPersons, e := dbpApi.Dbpersoninfosbyid([]string{searchBody.CompTargetId})
         if e ==nil && dbPersons !=nil && len(dbPersons) ==1 {
            searchBase64Fea := dbPersons[0].FaceFeature
            if searchBase64Fea != "" {
               decodeF, err := base64.StdEncoding.DecodeString(dbPersons[0].FaceFeature)
               if err !=nil {
                  util.ResponseFormat(c, code.ComError, "本条底库人员特征不是base64,请检查")
                  return
               }
               faceB = decodeF
            } else {
               util.ResponseFormat(c, code.ComError, "本条底库人员特征为空,请检查")
               return
            }
         } else {
            util.ResponseFormat(c, code.ComError, "底库人员查询失败,请检查")
            return
         }
         faceB = decodeF
      } else {
         searchBase64Fea, err := esApi.GetVideoPersonFaceFeatureById(searchBody.CompTargetId, config.EsInfo.EsIndex.AiOcean.IndexName, localConf.AlarmIp, strconv.Itoa(int(localConf.AlarmPort)))
         if err !=nil {
            util.ResponseFormat(c, code.ComError, "抓拍数据不存在,请检查")
            return
         }
         if searchBase64Fea !=""{
            decodeF, err := base64.StdEncoding.DecodeString(searchBase64Fea)
            if err !=nil {
               util.ResponseFormat(c, code.ComError, "本条抓怕特征不是base64,请检查")
               return
            }
            faceB = decodeF
         } else {
            util.ResponseFormat(c, code.ComError, "本条人脸抓拍特征为空,请检查")
            return
         }
      }
   } else {//做以图搜图
      if searchBody.PicUrl == "" || len(searchBody.DataBases) == 0 {
         util.ResponseFormat(c, code.RequestParamError, "参数有误")
         util.ResponseFormat(c, code.RequestParamError, "以图搜图PicUrl不能为空")
         return
      }
      if face,ok := faceExtractedMap[searchBody.PicUrl];!ok{
         util.ResponseFormat(c, code.RequestParamError, "请重新上传图片")
         util.ResponseFormat(c, code.RequestParamError, "人脸特征未检测,请重新上传图片")
         return
      } else {
         faceB = face.FaceBytes
      }
   }
   var sysSetApi dbapi.SysSetApi
   analyServerId := ""
   flag, sysconf := sysSetApi.GetServerInfo()
   if flag {
      analyServerId = sysconf.ServerId
   } else {
      util.ResponseFormat(c, code.ComError, "analyServerId为空,配置有误")
      return
   }
   if faceB == nil {
@@ -368,11 +524,12 @@
      CompareThreshold: searchBody.Threshold,
   }
   var hasCompEsPerson = false
   if searchBody.DataBases !=nil {
      for idx,tableId :=range searchBody.DataBases {
         if tableId == "esData" {
            searchBody.DataBases = append(searchBody.DataBases[:idx], searchBody.DataBases[idx+1:]...)
            searchBody.DataBases = append(searchBody.DataBases,service.CaptureTable)
            hasCompEsPerson = true
            break
         }
      }
@@ -380,37 +537,54 @@
   } else {
      arg.TableIds = []string{}
   }
   alarmLevelTypes := strings.Replace(strings.Trim(fmt.Sprint(getAlarmLevel(searchBody.AlarmLevel)), "[]"), " ", "\",\"", -1)
   arg.Source = true // 标识来源是web
   arg.AlarmLevel = searchBody.AlarmLevel
   arg.AlarmLevel = alarmLevelTypes
   arg.Tasks = searchBody.Tasks
   arg.TreeNodes = searchBody.TreeNodes
   arg.Tabs = searchBody.Tabs
   arg.SearchTime = searchBody.SearchTime
   arg.InputValue = searchBody.InputValue
   arg.Collection = searchBody.Collection
   arg.AnalyServerId = analyServerId
   arg.AnalyServerId = localConf.ServerId
   logger.Debug("arg.TableIds:", arg.TableIds, ",alarmLevel:",arg.AlarmLevel,",treeNodes:",arg.TreeNodes,",searchTime:",arg.SearchTime,
      ",inputValue:",arg.InputValue,",tasks:",arg.Tasks,",compThreshold:",arg.CompareThreshold)
   timeStart := time.Now()
   compareService := service.NewFaceCompareService(arg)
   compareOnce := compareService.Compare()
   totalData := compareOnce.CompareData
   var totalData service.CompareList
   if len(arg.TableIds) >0 {//有比对底库
      dbPersonTargets := compareService.CompareDbPersons()
      if dbPersonTargets !=nil {
         totalData = append(totalData,*dbPersonTargets...)
      }
   }
   if hasCompEsPerson {//有比对Es抓拍
      esPersons := compareService.CompareVideoPersons()
      if esPersons !=nil {
         totalData = append(totalData, *esPersons...)
      }
   }
   logger.Debug("comp 比对结束,用时:",time.Since(timeStart))
   service.SetCompResultByNum(&service.CompareOnce{
      CompareNum: compareService.CompareNum,
      CompareData: &totalData,
   })
   m := make(map[string]interface{},3)
   if totalData != nil && totalData.Len() > 0{
      sort.Sort(totalData)
      total := totalData.Len()
      m["compareNum"] = compareOnce.CompareNum
      m["compareNum"] = compareService.CompareNum
      m["total"] = total
      var sCompResult protomsg.SdkCompareResult
      if total <= searchBody.Size {
         sCompResult.CompareResult = *totalData
         sCompResult.CompareResult = totalData
      } else {
         sCompResult.CompareResult = (*totalData)[0:searchBody.Size]
         sCompResult.CompareResult = totalData[0:searchBody.Size]
      }
      resultList := FillDataToCompareResult(&sCompResult)
      m["totalList"] = resultList
@@ -418,82 +592,143 @@
   } else {
      m["total"] = 0
      m["compareNum"] = searchBody.CompareNum
      m["compareNum"] = compareService.CompareNum
      m["totalList"] = []CompareResult{}
   }
   util.ResponseFormat(c,code.Success,m)
}
func GetCompareDataTwice(co *service.CompareOnce,arg *models.EsSearch) map[string]interface{} {
   //camIds := arg.TreeNodes
   //tabIds := arg.Tabs
   //taskIds := arg.Tasks
   //alarmLevels := arg.AlarmLevel
   //timeArr := arg.SearchTime
   //input := arg.InputValue
   //resultList := make([]CompareResult,0)
   //for _,each :=range *co.CompareData {
   //   if each.Id !=""{
   //      n :=0
   //      if len(camIds) == 0 || isInArr(each.CameraId,camIds) {
   //         n++
   //      }
   //      if len(tabIds) == 0 {
   //         n++
   //      }
   //      if len(taskIds) == 0 || isInArr(each.TaskId, taskIds) {
   //         n++
   //      }
   //      //判断报警等级
   //      if len(alarmLevels) == 0 {
   //
   //      }
   //      n++
   //      //判断时间
   //      if len(timeArr) == 0 {
   //
   //      }
   //      n++
   //      if input == ""{
   //
   //      }
   //      n++
   //      if n == 6 {
   //         resultList = append(resultList,cr)
   //      }
   //   } else {
   //      resultList = append(resultList,cr)
   //   }
   //}
type PersonId struct {
   Id string `json:"id"`
}
   //logger.Debug("GetCompareDataTwice.data:",resultList)
   //service.SortByScore(resultList)
   from := (arg.Page-1)*arg.Size
   to := from + arg.Size
   var sCompResult protomsg.SdkCompareResult
   total := len(*co.CompareData)
   if total <= to {
      sCompResult.CompareResult = (*co.CompareData)[from:total]
   } else {
      sCompResult.CompareResult = (*co.CompareData)[from:to]
   }
   resultList := FillDataToCompareResult(&sCompResult)
func GetCompareDataTwice(co *service.CompareOnce,searchBody *models.EsSearch) map[string]interface{} {
   m := make(map[string]interface{},0)
   m["total"] = total
   m["compareNum"] = arg.CompareNum
   m["totalList"] = resultList
   //if from < len(resultList) {
   //   if to <= len(resultList) {
   //      m["totalList"] = resultList[from:to]
   //   } else {
   //      lte := len(resultList)
   //      m["totalList"] = resultList[from:lte]
   //   }
   from := (searchBody.Page-1)*searchBody.Size
   to := from + searchBody.Size
   var hasCompEsPerson = false
   if searchBody.DataBases !=nil {
      for idx,tableId :=range searchBody.DataBases {
         if tableId == "esData" {
            hasCompEsPerson = true
            searchBody.DataBases = append(searchBody.DataBases[:idx], searchBody.DataBases[idx+1:]...)
            break
         }
      }
   }
   if hasCompEsPerson {//二次检索ES比对结果
      arg := protomsg.CompareArgs{
         CompareThreshold: searchBody.Threshold,
      }
      localConf, err := cache.GetServerInfo()
      if err ==nil && localConf.AlarmIp != "" && localConf.ServerId != "" {
         alarmLevelTypes := strings.Replace(strings.Trim(fmt.Sprint(getAlarmLevel(searchBody.AlarmLevel)), "[]"), " ", "\",\"", -1)
         arg.Source = true // 标识来源是web
         arg.AlarmLevel = alarmLevelTypes
         arg.Tasks = searchBody.Tasks
         arg.TreeNodes = searchBody.TreeNodes
         arg.Tabs = searchBody.Tabs
         arg.SearchTime = searchBody.SearchTime
         arg.InputValue = searchBody.InputValue
         arg.Collection = searchBody.Collection
         arg.AnalyServerId = localConf.ServerId
         captureIds := esApi.GetAllLocalVideopersonsId(arg, config.EsInfo.EsIndex.AiOcean.IndexName, localConf.AlarmIp, strconv.Itoa(int(localConf.AlarmPort)), alarmLevelTypes)
         logger.Debug("searchPhoto first Result.len:",len(*co.CompareData),"twice len(captureIds):",len(captureIds))
         if captureIds !=nil {
            var aResult protomsg.SdkCompareResult
            aList := getTwiceSearchResult(co, &captureIds, searchBody)
            aTotal := aList.Len()
            if aTotal <= to {
               aResult.CompareResult = (*aList)[from:aTotal]
            } else {
               aResult.CompareResult = (*aList)[from:to]
            }
            out := FillDataToCompareResult(&aResult)
            m["total"] = aTotal
            m["compareNum"] = searchBody.CompareNum
            m["totalList"] = out
            return m
         } else {
            m["total"] = 0
            m["compareNum"] = searchBody.CompareNum
            m["totalList"] = []interface{}{}
            return m
         }
      }
   } else {//底库数据的二次检索
      var dbpApi dbapi.DbPersonApi
      personIds, _ := dbpApi.FindLikePersonIds(searchBody.DataBases, searchBody.InputValue)
      logger.Debug("searchPhoto first Result.len:",len(*co.CompareData),"personIds:",personIds)
      if personIds !=nil {
         var pIds []PersonId
         b, _ := json.Marshal(personIds)
         json.Unmarshal(b, &pIds)
         if len(pIds) >0 {
            var personIdArr []string
            for _,pid :=range pIds{
               personIdArr = append(personIdArr, pid.Id)
            }
            var aResult protomsg.SdkCompareResult
            aList := getTwiceSearchResult(co, &personIdArr, searchBody)
            aTotal := aList.Len()
            if aTotal <= to {
               aResult.CompareResult = (*aList)[from:aTotal]
            } else {
               aResult.CompareResult = (*aList)[from:to]
            }
            out := FillDataToCompareResult(&aResult)
            m["total"] = aTotal
            m["compareNum"] = searchBody.CompareNum
            m["totalList"] = out
            return m
         }
      } else {
         m["total"] = 0
         m["compareNum"] = searchBody.CompareNum
         m["totalList"] = []interface{}{}
         return m
      }
   }
   //var sCompResult protomsg.SdkCompareResult
   //total := len(*co.CompareData)
   //if total <= to {
   //   sCompResult.CompareResult = (*co.CompareData)[from:total]
   //} else {
   //   m["totalList"] = []CompareResult{}
   //   sCompResult.CompareResult = (*co.CompareData)[from:to]
   //}
   //resultList := FillDataToCompareResult(&sCompResult)
   m["total"] = 0
   m["compareNum"] = searchBody.CompareNum
   m["totalList"] = []interface{}{}
   return m
}
func getTwiceSearchResult(co *service.CompareOnce, scopeIds *[]string, searchBody *models.EsSearch) *service.CompareList{
   m := make(map[string]string)
   for _,capId :=range *scopeIds {
      m[capId] = capId
   }
   var totalData service.CompareList
   for _,each :=range *co.CompareData {
      if _,ok :=m[each.Id];ok && each.CompareScore >= searchBody.Threshold {
         totalData = append(totalData, each)
      }
   }
   if totalData != nil && totalData.Len() > 0{
      sort.Sort(totalData)
   }
   return &totalData
}
func isInArr(id string,arr []string) bool {
@@ -514,7 +749,12 @@
      util.ResponseFormat(c, code.RequestParamError, "参数有误")
      return
   }
   var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit"
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.WebPicIp == "" {
      logger.Debug("localConfig is wrong!!!")
      return
   }
   var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
   //将上传的图片交人脸检测和人脸提取,获得特征
   fileBytes, _ := ioutil.ReadAll(file)
@@ -528,7 +768,7 @@
         break
      }
      //根据人脸坐标扣出人脸小图
      cutFaceImgData := util.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom))
      cutFaceImgData,_ := util.SubCutImg(pI, rcFace, 20)
      weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "testCutFace", cutFaceImgData)
      if e !=nil{
         util.ResponseFormat(c,code.ComError,"文件上传失败")
@@ -546,24 +786,24 @@
log.Fatalln(err)
}*/
func uploadFileReturnAddr(file multipart.File, filename string, tableId string) (string, map[string]interface{}, error) {
func uploadFileReturnAddr(file multipart.File, filename string, tableId string, add2Db bool) (string, map[string]interface{}, error, string, string) {
   defer file.Close()
   // weedfs 上传
   fileBytes, err := ioutil.ReadAll(file)
   if err !=nil {
      return "",nil,err
      return "",nil,err,"",""
   }
   //将上传的图片交人脸检测和人脸提取,获得特征
   var faceBase64=""
   faceArr, err, pI := service.GetFaceFeaFromSdk(fileBytes, time.Second*5)
   if faceArr ==nil {
      return "",nil,errors.New("NotFeatureFindError")
      return "",nil,errors.New("NotFeatureFindError"),"",""
   }
   var rcFace *protomsg.Rect
   if err ==nil && len(faceArr) >0 {
      if len(faceArr) >1 {
         return "",nil, errors.New("TooManyFaces")
         return "",nil, errors.New("TooManyFaces"),"",""
      }
      for _,r := range faceArr {
         //拿到人脸的坐标
@@ -573,41 +813,55 @@
         break
      }
   }
   var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit"
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.WebPicIp == "" {
      logger.Debug("localConfig is wrong!!!")
      return "",nil,err2,"",""
   }
   var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
   //根据人脸坐标扣出人脸小图
   t1 := time.Now()
   cutFaceImgData := util.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom))
   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)
   logger.Debug("上传到weedfs用时:", time.Since(t1))
   t1 = time.Now()
   if e != nil {
      fmt.Println(e.Error())
      return "", nil, e
      logger.Debug("WeedFSClient.UploadFile err:", e)
      return "", nil, e,"",""
   }
   ext := path.Ext(filename)
   fileNameOnly := strings.TrimSuffix(filename, ext)
   dbperson := new(models.Dbtablepersons)
   dbperson.PersonPicUrl = weedFilePath //  图片路经
   dbperson.TableId = tableId           //
   dbperson.PersonName = fileNameOnly       // 图片名
   dbperson.Enable = 1 //默认有效
   dbperson.FaceFeature = faceBase64 // 特征值base64 码
   var result map[string]interface{}
   if add2Db {
      dbperson := new(models.Dbtablepersons)
      dbperson.PersonPicUrl = weedFilePath //  图片路经
      dbperson.TableId = tableId           //
      dbperson.PersonName = fileNameOnly       // 图片名
      dbperson.Enable = 1 //默认有效
      dbperson.FaceFeature = faceBase64 // 特征值base64 码
   result := addDbPerson(dbperson)
   logger.Debug("addDbPerson用时:", time.Since(t1))
   return fileNameOnly, result, nil
      result = addDbPerson(dbperson)
   }
   logger.Debug("addDbPerson用时:", time.Since(t1), "result:", result)
   return fileNameOnly, result, nil,faceBase64, weedFilePath
}
/**上传方法**/
// @Security ApiKeyAuth
// @Summary 批量添加底库人员
// @Description  依据图片批量添加底库人员
// @Accept  mpfd
// @Accept  multipart/form-data
// @Produce json
// @Tags dbperson 底库人员
// @Param files formData file[] true "多个底库人员图片"
@@ -627,8 +881,10 @@
   }
   extNames := make([]string, 0)
   addResult := make(map[string]interface{}, 0)
   successList := make([]string, 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
@@ -638,18 +894,31 @@
         defer wg.Done()
         tIStart := time.Now()
         filename := head.Filename
         fileExt := path.Ext(filename)
         fileExt = strings.ToLower(fileExt)
         if fileExt !=".jpg" && fileExt != ".jpeg" && fileExt != ".png" {
            lock.Lock()
            failList = append(failList, filename)
            lock.Unlock()
            return
         }
         file, err := head.Open()
         fmt.Println(file, err, filename)
         if err != nil {
            lock.Lock()
            failList = append(failList, filename)
            lock.Unlock()
            return
         }
         field, _, err1 := uploadFileReturnAddr(file, filename, tableId)
         field, _, err1,_,_ := uploadFileReturnAddr(file, filename, tableId, true)
         lock.Lock()
         if err1 != nil || field == "" {
            failList = append(failList, filename)
            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)
         }
@@ -661,6 +930,8 @@
   logger.Debug("切",len(fileHeaders),"张人脸用时:", time.Since(tAllStart))
   addResult["successList"] = successList
   addResult["failList"] = failList
   addResult["noFaceList"] = noFaceList
   addResult["multiFaceList"] = multiFaceList
   addResult["fields"] = extNames
   if len(successList)>0 {
@@ -678,9 +949,10 @@
   IdCard string `json:"idCard"`
}
// @Security ApiKeyAuth
// @Summary 上传图片 并切图
// @Description  上传图片 并切图
// @Accept  mpfd
// @Accept  multipart/form-data
// @Produce json
// @Tags dbperson 底库人员
// @Param file formData file true "底库人员图片"
@@ -709,7 +981,12 @@
      util.ResponseFormat(c, code.UploadFileError, err2.Error())
      return
   }
   var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit"
   localConf, err2 := cache.GetServerInfo()
   if err2 !=nil || localConf.WebPicIp == "" {
      logger.Debug("localConfig is wrong!!!")
      return
   }
   var weedfsUri = "http://"+localConf.WebPicIp+":"+strconv.Itoa(int(localConf.WebPicPort))+"/submit?collection=persistent"
   {
      uri := weedfsUri
      fileInfo, e := esutil.PostFormBufferData(uri, filename, "file", uploadData)