package controllers import ( "basic.com/dbapi.git" "basic.com/fileServer/WeedFSClient.git" "basic.com/pubsub/protomsg.git" "bytes" "encoding/base64" "errors" "fmt" "github.com/gin-gonic/gin" "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" ) 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,"未提取到人脸") } } // @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 } if searchBody.CompareNum !="" { //二次搜索,不需要再比对了 co := service.GetCompResultByNum(searchBody.CompareNum) if co != nil { //二次搜索和排序 twiceM := GetCompareDataTwice(co,&searchBody) util.ResponseFormat(c,code.Success,twiceM) } else { m :=make(map[string]interface{},0) m["compareNum"] = searchBody.CompareNum m["total"] = 0 m["totalList"] = []service.CompareResult{} util.ResponseFormat(c,code.CompareResultGone,m) } } 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,service.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) compareService := service.NewFaceCompareService(arg) compareOnce := compareService.Compare() logger.Debug("compareResult:",*compareOnce) dataList := compareOnce.CompareData service.SortByScore(dataList) totalList := len(dataList) m := make(map[string]interface{},3) m["compareNum"] = compareOnce.CompareNum m["total"] = totalList if totalList <= searchBody.Size { m["totalList"] = dataList } else { m["totalList"] = dataList[0:searchBody.Size] } util.ResponseFormat(c,code.Success,m) } } func GetCompareDataTwice(co *service.CompareOnce,arg *models.EsSearch) map[string]interface{} { camIds := arg.TreeNodes tabIds := arg.Tabs taskIds := arg.Tasks alarmLevels := arg.AlarmLevel timeArr := arg.SearchTime input := arg.InputValue resultList := make([]service.CompareResult,0) for _,cr :=range co.CompareData { if cr.Id !=""{ n :=0 if len(camIds) == 0 || isInArr(cr.CameraId,camIds) { n++ } if len(tabIds) == 0 { n++ } if len(taskIds) == 0 || isInArr(cr.TaskId, taskIds) { n++ } //判断报警等级 if len(alarmLevels) == 0 { } n++ //判断时间 if len(timeArr) == 0 { } n++ if input == ""{ } n++ if n == 6 { resultList = append(resultList,cr) } } else { resultList = append(resultList,cr) } } logger.Debug("GetCompareDataTwice.data:",resultList) service.SortByScore(resultList) from := (arg.Page-1)*arg.Size to := from + arg.Size lenth := len(resultList) m := make(map[string]interface{},0) m["total"] = lenth m["compareNum"] = arg.CompareNum if from < len(resultList) { if to <= len(resultList) { m["totalList"] = resultList[from:to] } else { m["totalList"] = resultList[from:len(resultList)] } } else { m["totalList"] = []service.CompareResult{} } return m } 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 } 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 // 图片名 dbperson.Enable = 1 //默认有效 // 演示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.DbPersonUploadSuccess, 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) { //暂时没有提供方法 }