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