package controllers import ( "basic.com/dbapi.git" "basic.com/fileServer/WeedFSClient.git" esApi "basic.com/pubsub/esutil.git" "basic.com/pubsub/protomsg.git" "basic.com/valib/logger.git" "bytes" "encoding/base64" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "gocv.io/x/gocv" "image" "image/color" "image/jpeg" "io/ioutil" "log" "mime/multipart" "path" "sort" "strconv" "strings" "sync" "time" "webserver/cache" "webserver/extend/code" "webserver/extend/config" "webserver/extend/esutil" "webserver/extend/util" "webserver/models" "webserver/service" ) type FileController struct { } // weedfs 访问路径 //var picIp = "http://192.168.1.182:6080/" var picIp = "http://" var picUrlField = "fileUrl" //var picUrlField = "fid" /**上传方法**/ //var weedfsUri = "http://192.168.1.182:9500/submit" // @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(c *gin.Context) { //得到上传的文件 file, header, err := c.Request.FormFile("file") //image这个是uplaodify参数定义中的 'fileObjName':'image' picType := c.Request.FormValue("picType") //图片类型 if err != nil || (picType != "0" && picType != "1") { util.ResponseFormat(c, code.RequestParamError, "参数有误") return } //文件的名称 filename := header.Filename 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 } result["picUrl"] = faceUrlPath result["faceFeature"] = faceFeature } else { 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) } 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 (controller FileController) FaceExtract(c *gin.Context) { file, _, err := c.Request.FormFile("file") //image这个是uplaodify参数定义中的 'fileObjName':'image' if err != nil { util.ResponseFormat(c, code.RequestParamError, "参数有误") return } 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) faceArr, err, pI := service.GetFaceFeaFromSdk(fileBytes, time.Second*60) if err ==nil && len(faceArr) >0 { //1.提取每一张人脸小图 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)) weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", cutFaceImgData) 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) resultMap["uploadImage"] = originFilePath resultMap["smImage"] = urlArr util.ResponseFormat(c,code.Success, resultMap) } else { util.ResponseFormat(c,code.ComError,"未提取到人脸") } } func drawPolygonOnImg(i *protomsg.Image,faceArr *[]*protomsg.ResultFaceDetect) (*[]byte,error) { rook, _ := gocv.NewMatFromBytes(int(i.Height), int(i.Width), gocv.MatTypeCV8UC3, i.Data) defer rook.Close() //yellow := color.RGBA{255, 255, 0, 0} red := color.RGBA{255, 0, 0, 0} for _,faceResult := range *faceArr { left := int(faceResult.Pos.RcFace.Left) top := int(faceResult.Pos.RcFace.Top) right := int(faceResult.Pos.RcFace.Right) bottom := int(faceResult.Pos.RcFace.Bottom) gocv.Rectangle(&rook, image.Rect(left,top,right,bottom), red, 1) } fData,err := gocv.IMEncode(".jpg", rook) return &fData,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 == service.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 dbapi.DbPersonApi dbpersons, _ = dbpApi.Dbpersoninfosbyid(personIds) } if len(dbpersons) >0 { var dtApi dbapi.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 { 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{ 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 } 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.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom)) 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 // @Produce json // @Tags 以图搜图 // @Param condition body models.EsSearch 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/searchByPhoto [POST] 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 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 } } 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, "以图搜图PicUrl不能为空") return } if face,ok := faceExtractedMap[searchBody.PicUrl];!ok{ util.ResponseFormat(c, code.RequestParamError, "人脸特征未检测,请重新上传图片") return } else { faceB = face.FaceBytes } } if faceB == nil { util.ResponseFormat(c, code.RequestParamError, "请重新上传图片") return } arg := protomsg.CompareArgs{ FaceFeature: faceB, 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:]...) hasCompEsPerson = true break } } arg.TableIds = searchBody.DataBases } else { arg.TableIds = []string{} } 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 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) 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"] = compareService.CompareNum m["total"] = total var sCompResult protomsg.SdkCompareResult if total <= searchBody.Size { sCompResult.CompareResult = totalData } else { sCompResult.CompareResult = totalData[0:searchBody.Size] } resultList := FillDataToCompareResult(&sCompResult) m["totalList"] = resultList logger.Debug("comp 比对加排序返回用时:", time.Since(timeStart)) } else { m["total"] = 0 m["compareNum"] = compareService.CompareNum m["totalList"] = []CompareResult{} } util.ResponseFormat(c,code.Success,m) } type PersonId struct { Id string `json:"id"` } func GetCompareDataTwice(co *service.CompareOnce,searchBody *models.EsSearch) map[string]interface{} { m := make(map[string]interface{},0) 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 { // 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 { for _,v :=range arr { if v == id { return true } } return false } // @Description 人员照片上传并获取特征值 // @Router /data/api-v/dbperson/fileUploadTest [POST] func (controller FileController) UploadPersonTest(c *gin.Context) { file, _, err := c.Request.FormFile("file") //image这个是uplaodify参数定义中的 'fileObjName':'image' if err != nil { util.ResponseFormat(c, code.RequestParamError, "参数有误") return } 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) faceArr, err, pI := service.GetFaceFeaFromSdk(fileBytes, 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.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom)) weedFilePath, e := WeedFSClient.UploadFile(weedfsUri, "testCutFace", cutFaceImgData) if e !=nil{ util.ResponseFormat(c,code.ComError,"文件上传失败") } else { util.ResponseFormat(c,code.Success,weedFilePath + ";" + faceBase64) } } else { util.ResponseFormat(c,code.ComError,"未提取到人脸") } } /*// 对上面的编码结果进行base64解码 decodeBytes, err := base64.StdEncoding.DecodeString(encodeString) if err != nil { log.Fatalln(err) }*/ 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,"","" } //将上传的图片交人脸检测和人脸提取,获得特征 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 } } 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)) 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 { logger.Debug("WeedFSClient.UploadFile err:", e) return "", nil, e,"","" } ext := path.Ext(filename) fileNameOnly := strings.TrimSuffix(filename, ext) 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), "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(c *gin.Context) { //得到上传的文件 //image这个是uplaodify参数定义中的 'fileObjName':'image' form, err := c.MultipartForm() tableId := c.Request.FormValue("tableId") fileHeaders := form.File["files"] if err != nil { util.ResponseFormat(c, code.RequestParamError, err.Error()) return } 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 _, head := range fileHeaders { wg.Add(1) go func(head *multipart.FileHeader,tableId string) { 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() if err != nil { lock.Lock() failList = append(failList, filename) lock.Unlock() return } field, _, err1,_,_ := uploadFileReturnAddr(file, 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)) }(head, tableId) wg.Wait() } 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 { util.ResponseFormat(c, code.DbPersonUploadSuccess, addResult) } else { util.ResponseFormat(c, code.DbPersonUploadFail, addResult) } } type EsPersonSave struct { FaceFeature string `json:"faceFeature"` TableId string `json:"tableId"` Id string `json:"id"` PersonPicUrl string `json:"personPicUrl"` IdCard string `json:"idCard"` } // @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, data:""}" // @Failure 500 {string} json "{"code":500, msg:"返回错误信息", success:false, data:""}" // @Router /data/api-v/es/ImageUploadReturnPics [POST] func (fc FileController) ImageUploadReturnPics(c *gin.Context) { //得到上传的文件 file, header, err := c.Request.FormFile("file") //image这个是uplaodify参数定义中的 'fileObjName':'image' if err != nil { log.Fatal(err) util.ResponseFormat(c, code.RequestParamError, err.Error()) return } //文件的名称 filename := header.Filename defer file.Close() field := "" // weedfs 上传 uploadData := make([]byte, header.Size) i, err2 := file.ReadAt(uploadData, 0) if err2 != nil { fmt.Println("上传返回i:", i) util.ResponseFormat(c, code.UploadFileError, err2.Error()) return } 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) if e != nil { fmt.Println(e.Error()) util.ResponseFormat(c, code.UploadFileError, e.Error()) return // 上传失败 } else { field = fileInfo[picUrlField].(string) // 文件路径 } } // fileInfo["point"] = v.RcFace // 返回特征值 // fileInfo["feature"] = feat //features := gorun.GetSimpleFaceDetect(picIp + "/" + field) // 特征值 只在linux 下 result := make(map[string]interface{}, 0) result["uploadImage"] = picIp + field smUrl := make([]string, 0) //for _, feature := range features { // linux // 获取图片 //point := feature["point"].(gosdk.CRECT) // linux buffer := bytes.NewBuffer(uploadData) m, _, _ := image.Decode(buffer) // 图片文件解码 rgbImg := m.(*image.YCbCr) //subImg := rgbImg.SubImage(image.Rect(int(point.Left),int(point.Bottom),int(point.Right),int(point.Top))).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 linux subImg := rgbImg.SubImage(image.Rect(30, 130, 170, 20)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 windows emptyBuff := bytes.NewBuffer(nil) //开辟一个新的空buff jpeg.Encode(emptyBuff, subImg, nil) //img写入到buff bytes := emptyBuff.Bytes() fileInfo, e := esutil.PostFormBufferData(weedfsUri, filename, "file", bytes) if e != nil { fmt.Println(e.Error()) util.ResponseFormat(c, code.UploadFileError, e.Error()) return // 上传失败 smUrl = append(smUrl, "一组获取失败") } else { field = fileInfo[picUrlField].(string) // 文件路径 smUrl = append(smUrl, picIp+field) } //} // linux result["smImage"] = smUrl util.ResponseFormat(c, code.Success, result) } /**下载方法**/ func Filedown(c *gin.Context) { //暂时没有提供方法 }