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 {//做以图搜图
|
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) {
|
//暂时没有提供方法
|
|
}
|