package controllers import ( "basic.com/dbapi.git" "basic.com/pubsub/protomsg.git" "basic.com/fileServer/WeedFSClient.git" "basic.com/valib/deliver.git" "bytes" "encoding/base64" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/gogo/protobuf/proto" "github.com/satori/go.uuid" "image" "image/jpeg" "io/ioutil" "log" "mime/multipart" "net/http" "path" "strconv" "strings" "time" "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 { } // 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" // @Summary 依据图片添加底库人员 // @Description 依据图片添加底库返回数据人员 // @Accept mpfd // @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}" // @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") 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()) } return } if tableId != "" { // 上传 if result["success"].(bool) { util.ResponseFormat(c, code.Success, result["data"]) } else { util.ResponseFormat(c, code.ServiceInsideError, result["data"]) } } else { util.ResponseFormat(c, code.Success, fileNameOnly) } } type FaceExtract struct { Url string `json:"url"` FaceBytes []byte `json:"faceBytes"` } var faceExtractedMap = make(map[string]FaceExtract,0) // @Summary 人脸提取 // @Description 人脸提取 // @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 } var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit" 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.大图画框,标识人脸位置 originFilePath, _ := WeedFSClient.UploadFile(weedfsUri, "FaceUrl", fileBytes) resultMap["uploadImage"] = originFilePath resultMap["smImage"] = urlArr util.ResponseFormat(c,code.Success, resultMap) } else { util.ResponseFormat(c,code.ComError,"未提取到人脸") } } type CompareResult struct { Id string `json:"id"` CameraId string `json:"cameraId"` 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"` TaskName string `json:"taskName"` BaseInfo []DbPersonVo `json:"baseInfo"` VideoUrl string `json:"videoUrl"` } 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"` } var captureTable = "capturetable" // 抓拍库 // @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 (controller FileController) SearchByPhoto(c *gin.Context) { var searchBody models.EsSearch err := c.BindJSON(&searchBody) if err !=nil || searchBody.PicUrl == "" || len(searchBody.DataBases) == 0 { util.ResponseFormat(c, code.RequestParamError, "参数有误") return } var sysSetApi dbapi.SysSetApi analyServerId := "" flag, sysconf := sysSetApi.GetServerInfo() if flag { analyServerId = sysconf.ServerId } else { util.ResponseFormat(c, code.ComError, "analyServerId为空,配置有误") return } if face,ok := faceExtractedMap[searchBody.PicUrl];!ok{ util.ResponseFormat(c, code.RequestParamError, "请重新上传图片") return } else { arg := protomsg.CompareArgs{ FaceFeature: face.FaceBytes, CompareThreshold: searchBody.Threshold, } 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,captureTable) break } } arg.TableIds = searchBody.DataBases } arg.Source = true // 标识来源是web arg.AlarmLevel = searchBody.AlarmLevel 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 logger.Debug("arg.TableIds:", arg.TableIds, ",alarmLevel:",arg.AlarmLevel,",treeNodes:",arg.TreeNodes,",searchTime:",arg.SearchTime, ",inputValue:",arg.InputValue,",tasks:",arg.Tasks,",compThreshold:",arg.CompareThreshold) b, err := proto.Marshal(&arg) if err !=nil{ util.ResponseFormat(c, code.ComError, "请求marshal失败") return } compServerList := config.CompServerInfo.Url logger.Debug("compServerList:", compServerList) resultList :=make([]CompareResult,0) for _,str :=range compServerList{ reqUrl := "tcp://"+str reqClient := deliver.NewClient(deliver.ReqRep, reqUrl) err = reqClient.Send(b) if err !=nil{ logger.Debug("reqClient.Send err:",err) continue } resultB, err := reqClient.Recv() if err !=nil{ logger.Debug("reqClient.Recv err:",err) continue } rList :=make([]protomsg.Esinfo,0) err = json.Unmarshal(resultB, &rList) if err !=nil{ logger.Debug("recv result Unmarshal err:", err) continue } logger.Debug("rList:", rList) dbPersonM := make(map[string]*protomsg.Esinfo,0) captureM := make(map[string]*protomsg.Esinfo,0) personIds :=make([]string,0) captureIds := make([]string,0) for _,v :=range rList{ if v.Tableid == captureTable { captureM[v.Id] = &v captureIds = append(captureIds,v.Id) } else { dbPersonM[v.Id] = &v personIds = append(personIds,v.Id) } } logger.Debug("personIds:", personIds) logger.Debug("captureIds:",captureIds) esServerIp := config.EsInfo.Masterip esServerPort := config.EsInfo.Httpport index := config.EsInfo.EsIndex.Dbtablepersons.IndexName dbpersons, e := esApi.Dbpersoninfosbyid(personIds, index, esServerIp, esServerPort) if e !=nil { logger.Debug("Dbpersoninfosbyid.err:",e) } logger.Debug("dbpersons:", dbpersons) if e ==nil && dbpersons !=nil { for _,p :=range dbpersons { var dbP = DbPersonVo { PersonId: p.Id, IdCard: p.IdCard, CompareScore: util.ParseScore(dbPersonM[p.Id].CompareScore), MonitorLevel: p.MonitorLevel, PersonName: p.PersonName, PersonPicUrl: p.PersonPicUrl, PhoneNum: p.PhoneNum, Sex: p.Sex, TableId: p.TableId, } dbTableInfos, _ := esApi.Dbtablefosbyid([]string{p.TableId}, config.EsInfo.EsIndex.DbTables.IndexName, esServerIp, esServerPort) if dbTableInfos !=nil{ dbP.BwType = dbTableInfos[0].BwType dbP.TableName = dbTableInfos[0].TableName } var cr = CompareResult{ BaseInfo:[]DbPersonVo{ dbP }, } resultList = append(resultList,cr) } } logger.Debug("resultList:",resultList) } util.ResponseFormat(c,code.Success,resultList) } } // @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 } var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit" //将上传的图片交人脸检测和人脸提取,获得特征 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) (string, map[string]interface{}, error) { defer file.Close() field := "" // 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 { for _,r := range faceArr { //拿到人脸的坐标 rcFace = r.Pos.RcFace faceBase64 = base64.StdEncoding.EncodeToString(r.Feats)//获取提取到的第一张人脸特征 break } } var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit" //根据人脸坐标扣出人脸小图 cutFaceImgData := util.SubImg(*pI, int(rcFace.Left), int(rcFace.Top), int(rcFace.Right), int(rcFace.Bottom)) fileInfo, e := esutil.PostFormData(weedfsUri, filename, "file", cutFaceImgData) if e != nil { fmt.Println(e.Error()) return "", nil, e } else { field = fileInfo[picUrlField].(string) // 文件路径 } if strings.Contains(field,"/"){ idx := strings.Index(field, "/") field = field[idx+1:] } fmt.Println("field:",field) ext := path.Ext(filename) fileNameOnly := strings.TrimSuffix(filename, ext) dbperson := new(models.Dbtablepersons) dbperson.PersonPicUrl = field // 图片路经 dbperson.TableId = tableId // dbperson.PersonName = fileNameOnly // 图片名 // 演示base64编码 dbperson.FaceFeature = faceBase64 // 特征值base64 码 result := addDbPerson(dbperson) return fileNameOnly, result, nil } //func getFaceFeaFromSdk(fileBytes []byte) ([]*protomsg.ResultFaceExtCom,error,*protomsg.Image){ // s := service.NewFaceSdkService(fileBytes) // i, err := s.ReadFromUploadImg() // if err !=nil{ // fmt.Println("readFromUploadImg err:",err) // return nil,err,i // } // bc, err := service.ImgCompress(i) // if err !=nil { // fmt.Println("ImgCompress err:",err) // return nil,err,i // } // s.PushImgMsg(bc) // s.GetFaceFea() // if s.Result == nil{ // return nil,errors.New("no fea"),i // } else { // return s.Result,nil,i // } //} /**上传方法**/ // @Summary 批量添加底库人员 // @Description 依据图片批量添加底库人员 // @Accept mpfd // @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) for _, head := range fileHeaders { //文件的名称 filename := head.Filename file, err := head.Open() fmt.Println(file, err, filename) if err != nil { log.Fatal(err) } field, _, err1 := uploadFileReturnAddr(file, filename, tableId) //extNames = append(extNames, field) if err1 != nil || field == "" { failList = append(failList, filename) } else { successList = append(successList, filename) } } addResult["successList"] = successList addResult["failList"] = failList addResult["fields"] = extNames //addResult["detail"] = details //fields := fdfsclient.UploadFileByBuffer100(bytess, extNames) // fastdfs 上传 if len(successList)>0 { util.ResponseFormat(c, code.Success, addResult) } else { util.ResponseFormat(c, code.ServiceInsideError, err.Error()) } } type EsPersonSave struct { FaceFeature string `json:"faceFeature"` TableId string `json:"tableId"` Id string `json:"id"` PersonPicUrl string `json:"personPicUrl"` IdCard string `json:"idCard"` } // @Summary 上传图片 并切图 // @Description 上传图片 并切图 // @Accept mpfd // @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 } var weedfsUri = "http://"+config.WeedFs.Ip+":"+strconv.Itoa(config.WeedFs.UploadPort)+"/submit" { 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) { //暂时没有提供方法 }