panlei
2019-06-25 514f2fb736939adbe3cebba4f33f881c26a7d512
ruleserver/ruleToformula.go
@@ -60,6 +60,12 @@
   score      float64 // 区域内的目标的相似度
   proportion float64 // 区域内的目标的占比
   size       float64 // 区域内的目标的尺寸
   liker      []LikePerson
}
type LikePerson struct {
   Id    string  // 与之相似的底库人员的id
   Score float64 // 与底库人员的相似值
}
// 每个区域内的图片数据集合
@@ -83,19 +89,20 @@
// sdk输出的图片上单个目标的数据
type PhotoMap struct {
   Rects Rect    // 矩形区域参数
   Score float64 // 相似度得分
   Score float64 // 相似度得分(有多大程度像一个目标。人脸,人体或车等等)
   Liker []LikePerson // 如果是人脸的话尤其是比对,应存下他跟底库的人员的相似情况 yolo的话给nil就行
}
// 从通道中获取的sdk输出的图像数据(目前主要是yolo算法的数据)
type ArgsFromSdk struct {
   Photo       []PhotoMap
   CameraId    string
   TaskId      string
   KeepRight   bool     // 是否靠右行 算法判断的与上一帧图像的比较结果
   IsStatic    bool     // 是否静止
   ImageWidth  int      // 摄像机拍摄的图像宽 像素
   ImageHeight int      // 摄像机拍摄的图像高 像素
   RuleResult  []Result // 过完规则后打的标签
   Photo       []PhotoMap // yolo算法结构,也可以存人脸的数据,毕竟人脸中能用规则来测的还是那些参数
   KeepRight   bool       // 是否靠右行 算法判断的与上一帧图像的比较结果
   IsStatic    bool       // 是否静止
   ImageWidth  int        // 摄像机拍摄的图像宽 像素
   ImageHeight int        // 摄像机拍摄的图像高 像素
   RuleResult  []Result   // 过完规则后打的标签
}
// 将传递过来的参数转化为
@@ -110,22 +117,14 @@
type Result struct {
   TaskId      string // 任务id
   RuleGroupId string // 规则组id
   AlarmLevel  int32  // 报警等级
   RuleText    string // 文字版规则组
}
// 包含N条规则元素的一整条规则
type CompleteRule struct {
   rule string
}
// 摄像机区域 跟数据库映射的
// type CameraPolygon struct {
//    Id            string `json:"id"`
//    CameraId      string `json:"camera_id"`
//    Name          string `json:"name"`
//    Polygon       string `json:"polygon"` // 坐标点区域
//    TriggerLine   string `json:"trigger_line"`
//    DirectionLine string `json:"direction_line"`
// }
// 根据摄像机id拿到摄像机所有区域
func GetPolygons(cameraId string) []protomsg.CameraPolygon {
@@ -146,7 +145,7 @@
}
// 规则主函数入口
func (arg *ArgsFromSdk) MainJudge() {
func MainJudge(arg *ArgsFromSdk) {
   cameraPolygons := GetPolygons(arg.CameraId)
   list := AreaMapList{}
   for _, polygon := range cameraPolygons {
@@ -196,11 +195,17 @@
// 将字符串格式的坐标序列化为Point格式
func Json2points(areaPoints string) []Point {
   var pts []Point
   err := json.Unmarshal([]byte(areaPoints), &pts)
   if err != nil {
      fmt.Println("json.Unmarshal错误", err)
      panic("序列化坐标异常,程序退出")
   if areaPoints == "" {
      pts = append(pts, Point{0, 0})
      pts = append(pts, Point{0, 540})
      pts = append(pts, Point{960, 540})
      pts = append(pts, Point{960, 0})
   } else {
      err := json.Unmarshal([]byte(areaPoints), &pts)
      if err != nil {
         fmt.Println("json.Unmarshal错误", err)
         panic("序列化坐标异常,程序退出")
      }
   }
   return pts
}
@@ -257,7 +262,7 @@
      // 根据cameraId去更新或者插入结果,然后判断是否数组是否可以得出报警的结论
      // 往联动任务的结果数组里放值或更新
      for _, va := range timeEle.RuleResults {
         if aml.areaMapList[0].cameraId != "" && va.CameraId == aml.areaMapList[0].cameraId {
         if arg.CameraId != "" && va.CameraId == arg.CameraId {
            va.Result = strconv.FormatBool(isOk)
         }
      }
@@ -291,7 +296,7 @@
      fmt.Println("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为false")
      // 所以也要去结果数组里放值或更新
      for _, va := range timeEle.RuleResults {
         if aml.areaMapList[0].cameraId != "" && va.CameraId == aml.areaMapList[0].cameraId { // aml.areaMapList[0].cameraId 随便找一个数据
         if arg.CameraId != "" && va.CameraId == arg.CameraId { // arg.CameraId 随便找一个数据
            va.Result = strconv.FormatBool(isOk)
         }
      }
@@ -303,19 +308,26 @@
func singleTask(aml *AreaMapList, arg *ArgsFromSdk, groupRule *protomsg.GroupRule, taskId string) bool {
   var completeFormula string = ""
   for _, areaMap := range aml.areaMapList {
      //fmt.Println("当前规则组为---------:",groupRule)
      for j := 0; j < len(groupRule.Rules); j++ {
         // 先过完条件数据
         filterRule(groupRule.Rules[j], &areaMap)
      }
      for j := 0; j < len(groupRule.Rules); j++ {
         // 再过其他数据 这步直接得到结果(真或假)
         // 再过其他数据 这步直接得到结果(真或假) 过目标数量
         flag := transferParameters(groupRule.Rules[j], &areaMap)
         if flag != "" {
            fmt.Println("得出的结果", flag)
            completeFormula = completeFormula + groupRule.Rules[j].RuleWithPre + "" + flag
         }
      }
      if completeFormula == "" {
         flag := splice1(&areaMap)
         if flag != "" {
            fmt.Println("强行拼凑一个人数是否大于0的结果", flag)
            completeFormula = flag
         }
      }
      for j := 0; j < len(groupRule.Rules); j++ {
         // 这步过的是时间规则(时间段等)
         flag := timeRuleResult(groupRule.Rules[j], &areaMap)
@@ -324,10 +336,12 @@
            completeFormula = completeFormula + groupRule.Rules[j].RuleWithPre + "" + flag
         }
      }
      for j := 0; j < len(groupRule.Rules); j++ {
         // 最后过持续时间等时间维度的条件
         duration(groupRule.Rules[j], &areaMap)
      }
   }
   fmt.Println("拼出的数学公式为:==== ", completeFormula)
   if completeFormula != "" {
@@ -355,7 +369,7 @@
         if flag {
            fmt.Println("定时器报警了")
            // 过完规则后打个标签,告诉调用者本帧数据针对哪个任务哪组规则报警了
            arg.RuleResult = append(arg.RuleResult, Result{TaskId: taskId, RuleGroupId: groupRule.GroupId})
            arg.RuleResult = append(arg.RuleResult, Result{taskId, groupRule.GroupId, groupRule.AlarmLevel, groupRule.GroupText})
            return true
         } else {
            return false
@@ -369,7 +383,7 @@
// 对单帧图像的判断 是舍弃(或者说对于某些需求可以放ES数据库一份)还是返回
func judge(aml *AreaMapList, arg *ArgsFromSdk) {
   // 得到属于该摄像机的若干组任务的完整规则(跟每一条完整规则比较之后得出本张图像对于某个规则是否报警的结果。放进map,比如本帧图像的id,所碰撞成功的规则id)
   taskRuleList := GetRuleGroup(aml.areaMapList[0].cameraId)
   taskRuleList := GetRuleGroup(arg.CameraId)
   if len(taskRuleList) > 0 {
      for _, taskRule := range taskRuleList {
         ruleList := taskRule.GroupRules // 获取的是task下面的任务组
@@ -377,9 +391,11 @@
         for i := 0; i < len(ruleList); i++ {
            temp := ruleList[i].Rules // temp为一组完整规则 在此需要判断规则是否是联动规则
            if len(temp) > 0 {
               if strings.Contains(ruleList[i].GroupId, "link") { // groupId中含有link则为联动任务
               if strings.Contains(ruleList[i].GroupId, "link") {
                  // groupId中含有link则为联动任务
                  linkTask(aml, arg, ruleList[i], taskId)
               } else { // 独立任务的处理
               } else {
                  // 独立任务的处理
                  singleTask(aml, arg, ruleList[i], taskId)
               }
            }
@@ -388,7 +404,7 @@
   }
}
// 过滤规则先筛选人数
// 过滤规则先筛选出符合条件的目标数量
func filterRule(rule *protomsg.Rule, am *AreaMap) {
   if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上
      if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
@@ -417,7 +433,6 @@
            }
         }
         am.targetNum = len(am.filterData) // 把符合条件的目标数量更新到targetNum字段
         //fmt.Println("筛选完后的内容:", am)
      }
   }
}
@@ -446,10 +461,19 @@
   }
}
// 冗余拼接
func splice1(am *AreaMap) string {
   args := am.targetNum
   formula := strconv.Itoa(args) + " " + ">" + "0"
   expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
   result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
   return strconv.FormatBool(result.(bool))
}
// 给数据库的规则表达式代参 args: 一条子规则,区域数据
func transferParameters(rule *protomsg.Rule, am *AreaMap) string {
   if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上
      if rule.SdkArgAlias == "targetNum" { // 如果参数是要区域内目标数量
      if rule.SdkArgAlias == "targetNum" { // 如果参数是要区域内目标数量 即yolo
         //fmt.Println("得出结果阶段", "比较的规则是:", rule)
         if rule.Operator == "" {
            return strconv.Itoa(am.targetNum) // 如果后面不跟操作符就直接返回数量  比如要跟下一个区域比较数量的就直接返回本区域的数量
@@ -460,18 +484,28 @@
         result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
         return strconv.FormatBool(result.(bool))
         // 加上关于算法的判断条件,不能只有关于规则的,有的算法本身就是一个规则,如个体静止,靠右行,所以,拿到当前子规则的sdkid来判断是否是那些特殊的规则
      } else if rule.SdkId == "个体静止" { // 暂时用汉字代替啦,晚些替换成正式的id
      } else if rule.SdkId == "IsStatic" { // 静止算法
         if am.isStatic {
            return "true"
         } else {
            return "false"
         }
      } else if rule.SdkId == "靠右行" { // 暂时用汉字代替啦,晚些替换成正式的id
      } else if rule.SdkId == "KeepRight" { // 靠右行算法
         if am.keepRight {
            return "true"
         } else {
            return "false"
         }
      } else if rule.SdkId == "FaceDetect" { // 人脸检测
         if rule.Operator == "==" || rule.Operator == ">=" || rule.Operator == "<=" || rule.Operator == "<" || rule.Operator == ">" || rule.Operator == "!=" {
            // 如果是不规矩的连接符统统返回false 规则也只能判断人脸的相似度,所以不存在别的连接符
            return "false"
         } else {
            return "false"
         }
      } else if rule.SdkId == "FaceCompare"{
      }
   }