panlei
2019-11-14 29db47f39c7bc0940592c96b587f51e4f0c659c1
algorithm/static/static.go
@@ -7,59 +7,252 @@
   "ruleprocess/ruleserver"
   "ruleprocess/structure"
   "strconv"
   "sync"
)
//个体静止算法
func Entrance(rule *protomsg.Rule, am *structure.AreaMap) structure.LittleRuleResult {
   for _,obj := range am.FilterData {
      var flag bool = true
      for k, _ := range ruleserver.TimeEleList {
         if k == rule.Id+""+strconv.Itoa(int(obj.Id)) {
            flag = false // 有就置为false
            logger.Info("有这个定时器,不再创建了:")
         }
func Entrance(rule *protomsg.Rule, am *structure.AreaMap,lable *structure.Others,args *structure.SdkDatas,message *protomsg.SdkMessage) structure.LittleRuleResult {
   if rule.PolygonId == am.AreaId { // 首先这条规则得是这个算法的规则,其次规则所对应的区域id要跟区域数据的id对的上
      logger.Debug("---------走了个体静止算法", rule.Id, rule.SdkArgAlias, rule.Operator, rule.SdkArgValue, am.AreaId)
      if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" || rule.SdkArgAlias == "" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
         return filterRule(rule, am)
      } else if rule.SdkArgAlias == "duration" {
         lr := CompareAndSave(rule,am,lable,args,message)
         logger.Info("个体静止规则结果:",lr)
         return lr
      } else {
         return structure.LittleRuleResult{}
      }
      if flag {
         timeEle := ruleserver.TimeElement{N: 10, InitN: 10, AlarmFlag: false, BufferFlag: 5} // 扔进去一个定时器元素
         ruleserver.TimeEleList[rule.Id+""+strconv.Itoa(int(obj.Id))] = &timeEle // 定时器元素以小规则id和目标id为键
      }
   } else {
      return structure.LittleRuleResult{}
   }
   return structure.LittleRuleResult{}
}
// 过滤规则先筛选出符合条件的目标数量
func filterRule(rule *protomsg.Rule, am *structure.AreaMap) structure.LittleRuleResult {
   // 处理的都是yolo数据
   var args []*structure.Arg
   if rule.RuleWithPre == "&&" {
      args = am.FilterData
   } else {
      args = am.Args
   }
   // 先清空过滤后的数据,再往里塞本次过滤后的数据
   am.FilterData = am.FilterData[0:0]
   //logger.Debug("看看args:::::", args)
   for _, arg := range args {
      var formula string
      if rule.SdkArgAlias == "score" {
         formula = strconv.FormatFloat(arg.Score, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
         logger.Info("当前相似度小公式:", formula)
      } else if rule.SdkArgAlias == "proportion" {
         formula = strconv.FormatFloat(arg.Proportion, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
         logger.Info("当前占比小公式:", formula)
   if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
      var args []*structure.Arg
      if rule.RuleWithPre == "&&" {
         args = am.FilterData
      } else {
         formula = strconv.FormatFloat(arg.Size, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
         logger.Info("当前尺寸小公式:", formula)
         args = am.Args
      }
      expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
      result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
      if result.(bool) {
         am.FilterData = append(am.FilterData, arg) // 得到符合条件的过滤数据
      // 先清空过滤后的数据,再往里塞本次过滤后的数据
      am.FilterData = am.FilterData[0:0]
      //logger.Debug("看看args:::::", args)
      for _, arg := range args {
         var formula string
         if rule.SdkArgAlias == "score" {
            formula = strconv.FormatFloat(arg.Score, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
            logger.Info("当前相似度小公式:", formula)
         } else if rule.SdkArgAlias == "proportion" {
            formula = strconv.FormatFloat(arg.Proportion, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
            logger.Info("当前占比小公式:", formula)
         } else {
            formula = strconv.FormatFloat(arg.Size, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
            logger.Info("当前尺寸小公式:", formula)
         }
         expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
         result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
         if result.(bool) {
            am.FilterData = append(am.FilterData, arg) // 得到符合条件的过滤数据
         }
      }
      am.TargetNum = len(am.FilterData) // 把符合条件的目标数量更新到targetNum字段
      if am.TargetNum > 0 {
         return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
      } else {
         return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
      }
   } else if rule.SdkArgAlias == "" {
      if am.TargetNum > 0 {
         return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
      } else {
         return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
      }
   }
   am.TargetNum = len(am.FilterData) // 把符合条件的目标数量更新到targetNum字段
   if am.TargetNum > 0 {
      return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
   } else {
   return structure.LittleRuleResult{}
}
// 判断两个矩形的重合度,把面积更大的做分母,即取小值
func PgsInterPercent(pgpts []structure.Point, box structure.Rect, widthScale float64, heightScale float64) (percent float64) {
   areapts, areaBox := ruleserver.GetLocation(box, 10)
   var count = 0
   for _, pts := range areapts {
      if ruleserver.PintIsInPolygon(pts, pgpts, widthScale, heightScale) {
         count++
      }
   }
   perInterBox := float64(count) / float64(len(areapts)) // 重合面积占矩形的比例
   areaInter := perInterBox * areaBox
   areaPg := ruleserver.ComputePolygonArea(pgpts)
   perInterPg := areaInter / areaPg // 重合面积占多边形区域的比例
   // 哪个占的比例小按哪个计算,比如人站起来了,大框套住了小框
   if perInterBox < perInterPg {
      return (perInterBox * 100)
   }
   return (perInterPg * 100)
}
// 判断一个区域内有没有静止的目标
func CompareAndSave(rule *protomsg.Rule, am *structure.AreaMap,lable *structure.Others,args *structure.SdkDatas,message *protomsg.SdkMessage) structure.LittleRuleResult {
   defer func() {
      if err := recover(); err != nil {
         logger.Error("个体静止规则有误", err)
      }
   }()
   logger.Info("走了个体静止核心算法")
   initN := 5
   if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a977" && rule.SdkArgAlias == "duration" {
      if init,err := strconv.Atoi(rule.SdkArgValue); err != nil {
         logger.Debug("个体静止算法读取持续时间失败",err)
      } else {
         initN = init
      }
   }
   if structure.StaticMap[am.AreaId] == nil || len(structure.StaticMap[am.AreaId].Targets) == 0 { // 即第一帧数据(也不一定),还没有缓存
      logger.Info("之前无缓存")
      objs := []*structure.Obj{}
      for _, tar := range am.FilterData {
         obj := &structure.Obj{Id: tar.Id, Location: tar.Location, N: initN,InitN:initN,CacheSdkData:structure.ResultMsg{message, nil}}
         objs = append(objs, obj)
      }
      structure.StaticMap[am.AreaId] = &structure.CameraArea{objs}
      return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
   } else {
      logger.Info("之前有缓存")
      flag := "false"
      // 以之前静止的对象为主判断是否静止
      tars := []*structure.Arg{}
      logger.Info("看一下静止区域内的目标:",am.AreaId)
      for _, tar := range structure.StaticMap[am.AreaId].Targets {
         logger.Info("具体目标:",tar.Location)
      }
      for _, tar := range structure.StaticMap[am.AreaId].Targets {
         singleResult,arg := SingleStatic(tar,am,lable,90)
         if singleResult {
            flag = "true"
            tars = append(tars,arg)
            logger.Info("静止的目标:",arg.Id,arg.Location,arg.Score)
         }
      }
      // 把满足条件的目标放进areaMap中
      am.AlarmObj = tars
      // 更新数据,把新来的数据写入缓存
      objs := []*structure.Obj{}
      for _, tar := range am.FilterData {
         flag1 := false
         for _, OBJ := range structure.StaticMap[am.AreaId].Targets {
            if tar.Id == OBJ.Id {
               flag1 = true
            }
         }
         if !flag1 { // 集合中没有的才插入
            obj := &structure.Obj{Id: tar.Id, Location: tar.Location, N: initN,InitN:initN,AlarmFlag: false, BufferFlag: 10, CacheSdkData: structure.ResultMsg{message, nil}}
            objs = append(objs, obj)
         }
      }
      structure.StaticMap[am.AreaId] = &structure.CameraArea{objs}
      return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + flag, rule.Sort}
   }
}
}
// rec变为[t]point 逆时针一圈的坐标
func Rect2Point(rect structure.Rect) []structure.Point {
   points := []structure.Point{}
   point1 := structure.Point{rect.X, rect.Y}
   points = append(points, point1)
   point2 := structure.Point{rect.X, rect.Y + rect.Height}
   points = append(points, point2)
   point3 := structure.Point{rect.X + rect.Width, rect.Y + rect.Height}
   points = append(points, point3)
   point4 := structure.Point{rect.X + rect.Width, rect.Y}
   points = append(points, point4)
   return points
}
// 判断一个目标是否静止了指定时间
func SingleStatic(person *structure.Obj, am *structure.AreaMap,lable *structure.Others, argValue float64) (bool,*structure.Arg){
   logger.Info("单个目标的判断:")
   flag := false
   var o *structure.Arg = nil
   for _, obj := range am.FilterData {
      if person.Id == obj.Id {
         coincidenceDegree := PgsInterPercent(Rect2Point(person.Location), obj.Location, 1, 1)
         logger.Info("判断目标的重合度",coincidenceDegree)
         o = obj
         if coincidenceDegree >= argValue {
            flag = true
         }
      }
   }
   if flag { // 当前检测对象保持静止(id相等并且重合度高于阈值)
      flagTime := TimerAlarm(o,person,flag,am.AreaId)
      if flagTime == "10" || flagTime == "11" {
         return flag,o
      } else {
         return false,o
      }
   } else {
      TimerAlarm(o,person,flag,am.AreaId)
      return flag,o
   }
}
var rw sync.RWMutex
// 判断是否符合定时器条件
func TimerAlarm(o *structure.Arg,person *structure.Obj, result bool,areaId string) (string) {
   var flagTime string //
   logger.Info("目标的定时器:")
   rw.Lock()
      if result { // 结果为真
         for k, tar := range structure.StaticMap[areaId].Targets {
            if tar.Id == person.Id {
               if tar.N == 0 && tar.AlarmFlag {
                  logger.Debug("-------------------------符合持续时间规则但并不是首次,不报警")
                  flagTime = "11"
               }
               if tar.N == 0 && !tar.AlarmFlag { // 这组规则的定时器要全部等于0   暂且认为一组规则只有一个定时器
                  logger.Debug("———————————-------------首次符合持续时间规则并报警")
                  flagTime = "10"
                  tar.AlarmFlag = true
                  o.CacheData = tar.CacheSdkData
               }
               if tar.N != 0 {
                  flagTime = "00"
                  // 有定时器但不为0把已打的标签删除
                  // args.RuleResult = nil
                  logger.Debug("------------------------结果为真但计数器不到0,不报警,此时的计数器", k, "的值为:", tar.N)
               }
            }
         }
      } else { // 结果为假 干掉这个计数器
         for index, tar := range structure.StaticMap[areaId].Targets {
            if tar.Id == person.Id {
               if tar.AlarmFlag {
                  if tar.BufferFlag == 0 {
                     logger.Debug("------------------------------杀死计数器,报警此帧状态改变的数据,此时的计数器的值为", tar.N)
                     flagTime = "12"
                     structure.StaticMap[areaId].Targets = append(structure.StaticMap[areaId].Targets[:index],structure.StaticMap[areaId].Targets[index+1:]...)
                  } else {
                     if tar.BufferFlag > 0 {
                        logger.Debug("缓冲区减减")
                        tar.BufferFlag--
                     }
                  }
               } else {
                  logger.Debug("-----------结果为假且不到0,杀死定时器")
                  structure.StaticMap[areaId].Targets = append(structure.StaticMap[areaId].Targets[:index],structure.StaticMap[areaId].Targets[index+1:]...)
               }
            }
         }
      }
   rw.Unlock()
   return flagTime
}