panlei
2019-08-06 55470d9b9aa1c61d895f01d593373b8ac625ba0c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
package ruleserver
 
import (
    "ruleprocess/cache"
    "ruleprocess/logger"
    "sort"
    "strconv"
    "strings"
    "time"
 
    "basic.com/pubsub/protomsg.git"
    "github.com/knetic/govaluate"
)
 
// 每个目标的参数:相似度,占比,尺寸
type Arg struct {
    Id         uint64
    Score      float64 // 区域内的目标的相似度
    Proportion float64 // 区域内的目标的占比
    Size       float64 // 区域内的目标的尺寸
    IsYolo     bool    // 是否是yolo数据
    Location   Rect    // 记下每个目标的位置参数,最后给结果装配人脸数据的时候用的到
    Feature    []byte
    ThftRes    protomsg.ThftResult
    Liker      []*BaseInfo
}
 
// 每个区域内的图片数据集合
type AreaMap struct {
    cameraId      string
    areaId        string
    groupId       string
    taskId        string
    sdkId         string
    sdkName       string
    areaJson      string
    triggerLine   string
    directionLine string
    targetNum     int    // 区域内目标数量
    args          []*Arg // 区域内目标集合
    filterData    []*Arg // 过滤后区域内目标集合
    time          string // 当前时间(用以匹配时间规则)
    keepRight     bool   // 是否靠右行
    isStatic      bool   // 是否静止
}
 
// sdk输出的图片上单个目标的数据
type PhotoMap struct {
    Id      uint64
    Rects   Rect    // 矩形区域参数
    Score   float64 // 相似度得分(有多大程度像一个目标。人脸,人体或车等等)
    IsYolo  bool    // 是否是yolo数据
    ThftRes protomsg.ThftResult
    Feature []byte
}
 
// 每个算法对于当前帧画面自己提取的数据
type SdkData struct {
    TaskId      string
    IpcId       string
    IsYolo      bool
    Photo       []PhotoMap // yolo算法结构,也可以存人脸的数据,毕竟人脸中能用规则来测的还是那些参数
    KeepRight   bool       // 是否靠右行 算法判断的与上一帧图像的比较结果
    IsStatic    bool       // 是否静止
    ImageWidth  int        // 摄像机拍摄的图像宽 像素
    ImageHeight int        // 摄像机拍摄的图像高 像素
    AreaMapList []*AreaMap // 本sdk提取的数据按照区域划分后的数据集合
}
 
// 从算法模块儿拿来的对一帧图像各个算法提取的数据集合
type SdkDatas struct {
    CameraId   string
    TaskId     string
    Sdkdata    []*SdkData
    RuleResult map[string]interface{} // 过完规则后打的标签 face: []FaceResult, yolo: []Result
}
 
type ResultMsg struct {
    *protomsg.SdkMessage
    RuleResult map[string]interface{} // 过完规则后打的标签 face: []FaceResult, yolo: []Result
}
 
// 过规则库打上的标签
type Result struct {
    TaskId       string // 任务id
    SdkName      string
    RuleGroupId  string // 规则组id
    DefenceState bool   // 是否布防
    AlarmLevel   int32  // 报警等级
    RuleText     string // 文字版规则组
    Location     []Rect // 目标的坐标
    AlarmPolygon string // 触发的报警框
    Others
}
type Others struct {
    CacheData []ResultMsg //(本组规则中含有持续时间的规则开启的定时器缓存的数据帧)
    LinkCache []ResultMsg
    TimeLabel string
}
 
// 过规则库打上的标签
type FaceResult struct {
    Result
    Args []Arg
}
type LittleRuleResult struct {
    SdkName string // 记录下此结果是哪个sdk的结果
    Result  string // 已包含了前置连接符
    Sort    int32
}
 
// 对单帧图像的判断 thisSdkDatas  当前传入的这帧数据,cacheSdkData 定时器里缓存的一帧数据 没有就返回nil  (thisSdkDatas SdkDatas, cacheSdkDatas SdkDatas)
func Judge(args *SdkDatas, message *protomsg.SdkMessage) {
    if len(args.Sdkdata) > 0 {
        // 拿到本摄像机的区域
        cameraPolygons := GetPolygons(args.CameraId)
        // 把所有的sdk提取的数据都按所属摄像机的区域归置
        //logger.Debug("当前摄像机id为:",message.Cid,"当前摄像机执行的任务是:",message.Tasklab.Taskname)
        for _, arg := range args.Sdkdata {
            SdkDataFormat(args.CameraId, arg, cameraPolygons)
        }
        // 跑本摄像机的所有规则组 一组一组跑
        taskGroup := GetRuleGroup(args.CameraId, args.TaskId) // 本摄像机下所有任务组
        //logger.Println("看下摄像机下的任务组:",taskRuleList)
        // 得到属于该摄像机的若干组任务的完整规则(跟每一条完整规则比较之后得出本张图像对于某个规则是否报警的结果。放进map,比如本帧图像的id,所碰撞成功的规则id)
        args.RuleResult = make(map[string]interface{})
        args.RuleResult["yolo"] = []Result{}
        args.RuleResult["face"] = []FaceResult{}
        //logger.Warn("传进去之前是什么德行:",args.RuleResult["yolo"])
        if taskGroup != nil && len(taskGroup.GroupRules) > 0 {
            // 先过独立,再过联动
            for _, group := range taskGroup.GroupRules {
                //logger.Println("------------------------------任务规则:",taskRule)
                taskId := taskGroup.TaskId
                //logger.Println("------------本组任务下的规则组的数量:",len(ruleList))
                temp := group.Rules // temp为一组完整规则 在此需要判断规则是否是联动规则
                label := Others{}
                if len(temp) > 0 {
                    if group.SetType != "linkTask" {
                        // 独立任务的处理
                        RunRule(args, group, taskId, message, label)
                    }
                }
            }
            for _, group := range taskGroup.GroupRules {
                //logger.Println("------------------------------任务规则:",taskRule)
                taskId := taskGroup.TaskId
                //logger.Println("------------本组任务下的规则组的数量:",len(ruleList))
                temp := group.Rules // temp为一组完整规则 在此需要判断规则是否是联动规则
                label := Others{}
                if len(temp) > 0 {
                    if group.SetType == "linkTask" {
                        // groupId中含有link则为联动任务
                        LinkTask(args, group, taskId, message, label)
                    }
                }
            }
        }
    }
}
 
func RunRule(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string, message *protomsg.SdkMessage, label Others) bool {
    defer func() {
        if err := recover(); err != nil {
            logger.Error("比对规则有误", err.(string))
        }
    }()
    logger.Info("+++++++++++规则开始运行+++++++++++++++++当前大规则--:", (*groupRule).GroupText)
    //logger.Warn("传进去之后是什么德行:",args.RuleResult["yolo"])
    Compare(args, groupRule)
    resultSplice := []*LittleRuleResult{}
    sdkNames := ""
    polygonId := ""
    // 先过完条件规则
    for j := 0; j < len(groupRule.Rules); j++ {
        for _, sdkData := range args.Sdkdata {
            // 根据规则的sdkId查出其对应的ipcId,用ipcId去找该比对的数据
            sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
            if err != nil {
                logger.Error("没查到sdk的信息---", err)
            }
            ipcId := sdk.IpcId
            sdkName := sdk.SdkName
            //logger.Info("规则的ipcId与sdkData的IpcId:", ipcId, "===", sdkData.IpcId)
            if ipcId == sdkData.IpcId {
                //logger.Info("当前走的规则是--:", sdkName, "---","")
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := filterRule(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        logger.Info("条件规则结果:", ruleResult.Result)
                        // 如果此结果为真且当前过的是yolo算法,应记下此规则所对应的sdkName,另外,还要去重 (后加:把此条触碰的区域id也记录下来)
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                            sdkNames = sdkName + ","
                            polygonId = groupRule.Rules[j].PolygonId + ","
                        }
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                            polygonId = groupRule.Rules[j].PolygonId + ","
                        }
                        resultSplice = append(resultSplice, &ruleResult)
                    }
                }
            }
        }
    }
 
    // 再过其他数据 这步直接得到结果(真或假) 过目标数量
    for j := 0; j < len(groupRule.Rules); j++ {
        for _, sdkData := range args.Sdkdata {
            // 根据规则的sdkId查出其对应的ipcId,用ipcId去找该比对的数据
            sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
            if err != nil {
                logger.Error("没查到sdk的信息---", err)
            }
            ipcId := sdk.IpcId
            sdkName := sdk.SdkName
            if ipcId == sdkData.IpcId {
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := transferParameters(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        logger.Info("数量规则结果:", ruleResult.Result)
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                            sdkNames = sdkName + ","
                        }
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                            polygonId = groupRule.Rules[j].PolygonId + ","
                        }
                        resultSplice = append(resultSplice, &ruleResult)
                    }
                }
            }
        }
    }
    // 这步过的是时间段规则(时间段等)
    for j := 0; j < len(groupRule.Rules); j++ {
        for _, sdkData := range args.Sdkdata {
            sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
            if err != nil {
                logger.Error("没查到sdk的信息---", err)
            }
            ipcId := sdk.IpcId
            sdkName := sdk.SdkName
            if ipcId == sdkData.IpcId {
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := timeRuleResult(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        logger.Info("时间规则结果:", ruleResult.Result)
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                            sdkNames = sdkName + ","
                        }
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                            polygonId = groupRule.Rules[j].PolygonId + ","
                        }
                        resultSplice = append(resultSplice, &ruleResult)
                    }
                }
            }
        }
    }
 
    // 将数组按sort排序
    sort.Sort(resultList(resultSplice))
    // 排序后取各自的结果和连接符拼出规则表达式得出结果
    completeFormula := ""
    for _, va := range resultSplice {
        completeFormula = completeFormula + va.Result
    }
    if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || strings.HasPrefix(completeFormula, ">=") || strings.HasPrefix(completeFormula, "<=") || strings.HasPrefix(completeFormula, "==") || strings.HasPrefix(completeFormula, "!=") || strings.HasPrefix(completeFormula, ">") || strings.HasPrefix(completeFormula, "<") {
        // 以这些开头的基本是联动任务
        if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || strings.HasPrefix(completeFormula, ">=") || strings.HasPrefix(completeFormula, "<=") || strings.HasPrefix(completeFormula, "==") || strings.HasPrefix(completeFormula, "!=") {
            completeFormula = completeFormula[2:]
        }
        if strings.HasPrefix(completeFormula, ">") || strings.HasPrefix(completeFormula, "<") {
            completeFormula = completeFormula[1:]
        }
        logger.Info("-------------------看看拔毛后的表达式:", completeFormula)
        //expression, _ := govaluate.NewEvaluableExpression(completeFormula)
        //result, _ := expression.Evaluate(nil) // 得到数学公式的结果
        //return result.(bool)
    }
    if completeFormula != "" {
        logger.Info("结果公式-----------:", completeFormula)
        expression, err2 := govaluate.NewEvaluableExpression(completeFormula)
        if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || err2 != nil {
            panic("规则有误,得到的数学公式不可解析")
        }
        result, _ := expression.Evaluate(nil) // 得到数学公式的结果
 
        if result.(bool) {
            // 最后过持续时间等时间维度的条件   把时间规则位置调整到这个位置是为了缓存数据
            for j := 0; j < len(groupRule.Rules); j++ {
                for _, sdkData := range args.Sdkdata {
                    sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
                    if err != nil {
                        logger.Error("没查到sdk的信息---", err)
                    }
                    ipcId := sdk.IpcId
                    if ipcId == sdkData.IpcId {
                        for _, areaMap := range sdkData.AreaMapList {
                            // 去开启一个定时器
                            duration(groupRule.Rules[j], groupRule.GroupId, areaMap, args, message)
                        }
                    }
                }
            }
            // 进行定时器的处理和判断
            timeFlag := TimerAlarm(&label, groupRule.GroupId, result.(bool))
            if timeFlag == "01" || timeFlag == "10" || timeFlag == "11" { // 没有定时器或者满足定时器条件
                // 打人脸标签和yolo标签
                // 最后成功报警才把符合条件的人脸数据塞进结果标签里
                // 配了人脸的算法才把人脸的数据甩出来打标签
                faces := []Arg{}
                faceFlag := false
                for j := 0; j < len(groupRule.Rules); j++ {
                    if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
                        faceFlag = true
                    }
                }
                for _, sdkData := range args.Sdkdata {
                    if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" && faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
                        for _, areaMap := range sdkData.AreaMapList {
                            faces = append(faces, putFaceToResult(areaMap, faces)...)
                        }
                    }
                }
                //for _,face := range faces  {
                //    //logger.Debug("————————————————________________看看人脸的坐标:",face.Location)
                //}
                logger.Warn("___________________________________________________________________________终于走完万里长征")
                // 把他们的位置数据也传下去
                locations := []Rect{}
                for _, sdkData := range args.Sdkdata {
                    if sdkData.IpcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && sdkNames != "" { // 把yolo数据的各个目标的坐标输出方便后面画框
                        for _, areaMap := range sdkData.AreaMapList {
                            locations = append(locations, putYolosToResult(areaMap)...)
                        }
                    }
                }
                //logger.Debug("------locations的内容:", locations)
                if sdkNames != "" {
                    args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]Result), Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, locations, polygonId, label})
                    //logger.Info("-------------------yolo结果标签长度", len(args.RuleResult["yolo"].([]Result)))
                }
                if faceFlag {
                    args.RuleResult["face"] = append(args.RuleResult["face"].([]FaceResult), FaceResult{Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, []Rect{}, polygonId, label}, faces})
                    //logger.Info("-------------------face结果标签", len(args.RuleResult["face"].([]FaceResult)))
                    logger.Info("过完规则时查看人脸标签:")
                    if args.RuleResult["face"] != nil && len(args.RuleResult["face"].([]FaceResult)) > 0 {
                        for _, faceResult := range args.RuleResult["face"].([]FaceResult) {
                            for _,arg := range faceResult.Args {
                                logger.Info("人员分值是:",arg.Score,"liker的数量为",arg.Liker)
                            }
                        }
                    }
                }
                return true
            } else {
                return false
            }
 
        } else {
            // 结果为假时也要走,有时候为假的状态反转数据也需要记录下来
            //timeFlag := TimerAlarm(args, groupRule.GroupId, result.(bool))
            //fmt.Println(timeFlag)
            return false
        }
    } else {
        return false
    }
}
 
func putFaceToResult(am *AreaMap, faceList []Arg) []Arg {
    faces := []Arg{}
    if len(am.filterData) > 0 {
        for _, data := range am.filterData {
            flag := true
            for _, face := range faceList {
                if data.Location.X == face.Location.X && data.Location.Y == face.Location.Y && data.Location.Width == face.Location.Width && data.Location.Height == face.Location.Height {
                    flag = false
                }
            }
            if flag {
                faces = append(faces, *data)
            }
        }
    }
    //logger.Println("-----------------------------------------------听说你是空的?",faces)
    return faces
}
 
func putYolosToResult(am *AreaMap) []Rect {
    locations := []Rect{}
    if len(am.filterData) > 0 {
        for _, data := range am.filterData {
            locations = append(locations, data.Location)
        }
    }
    //logger.Println("-----------------------------------------------听说你是空的?",faces)
    return locations
}
 
// 联动任务的处理
func LinkTask(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string, message *protomsg.SdkMessage, label Others) {
    // new一个定时器,如果以此groupId为标志的定时器不存在的话
    logger.Info("------------------------------------------当前是联动任务,规则是:", groupRule.GroupText)
    var flag bool = true
    var timeEle = TimeElement{N: 2, InitN: 2, GroupId: groupRule.GroupId}
    for k, timeEle1 := range TimeEleList {
        if k == groupRule.GroupId {
            flag = false // 已经有了这个定时器就置为false 不再新增
            timeEle = *timeEle1
        }
    }
    if flag { // 如果还没有这个定时器元素就新增一个
        //timeEle := TimeElement{N: 2, InitN: 2, GroupId: groupRule.GroupId} // 扔进去一个定时器元素
        //TimeEleList = make(map[string]timeElement)
        TimeEleList[groupRule.GroupId] = &timeEle // 定时器元素以规则组id为键
        logger.Info("---------------------------------------------联动任务创建了计数器并且计数器集合为:", TimeEleList)
        // 得出这组完整规则里涉及到几个摄像机,决定着数组里有几个结构体,去重添加方式
        for j := 0; j < len(groupRule.Rules); j++ {
            var flag1 bool = true
            for _, ruleRes := range TimeEleList[groupRule.GroupId].RuleResults {
                if groupRule.Rules[j].CameraId == ruleRes.CameraId {
                    flag1 = false
                }
            }
            if flag1 {
                TimeEleList[groupRule.GroupId].RuleResults = append(TimeEleList[groupRule.GroupId].RuleResults, &RuleResult{groupRule.Rules[j].CameraId, groupRule.Rules[j].Sort, "", groupRule.Rules[j].RuleWithPre, ResultMsg{}})
            }
        }
    }
    // 往数组里赋值
    isOk := RunRule(args, groupRule, taskId, message, label)
    if isOk {
        logger.Info("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为true")
        // 根据cameraId去更新或者插入结果,然后判断是否数组是否可以得出报警的结论
        // 往联动任务的结果数组里放值或更新
        for _, va := range timeEle.RuleResults {
            if va.CameraId == args.CameraId {
                va.Result = strconv.FormatBool(isOk)
                tempMap := make(map[string]interface{})
                for k, result := range args.RuleResult {
                    if k == "yolo" {
                        tempMap[k] = []Result{}
                        for _, res := range result.([]Result) {
                            tempMap[k] = append(tempMap[k].([]Result), res)
                        }
                    }
                    if k == "face" {
                        tempMap[k] = []FaceResult{}
                        for _, res := range result.([]FaceResult) {
                            tempMap[k] = append(tempMap[k].([]FaceResult), res)
                        }
                    }
                }
                va.CacheData = ResultMsg{message, tempMap}
                logger.Info("这个摄像机--", args.CameraId, "--被赋予了result", va.Result)
            }
        }
        // 判断结果数组是否完满(即被赋值完毕)可得出报警结果
        var isPerfect = true
        for _, va := range timeEle.RuleResults {
            //logger.Info("---------------------瞅瞅当前数组________________:", *va)
            if va.Result == "" && va.RuleWithPre != "||" {
                isPerfect = false
            }
        }
        if isPerfect {
            logger.Debug("数组完满了,联动任务可以成功报警了!")
            // 将数组按sort排序
            sort.Sort(SubList(timeEle.RuleResults))
            // 排序后取各自的结果和连接符拼出规则表达式得出结果
            completeFormula := ""
            for _, va := range timeEle.RuleResults {
                completeFormula = completeFormula + va.RuleWithPre + "" + va.Result
            }
            logger.Info("---------------------------联动任务的公式", completeFormula)
            if completeFormula != "" {
                expression, _ := govaluate.NewEvaluableExpression(completeFormula)
                result, _ := expression.Evaluate(nil) // 得到数学公式的结果
                if result.(bool) {
                    logger.Info("___________________________________________________________________联动任务报警")
                    // 把数组里缓存的数据取出来一起报警
                    label.LinkCache = []ResultMsg{}
                    for _, ruleRes := range TimeEleList[groupRule.GroupId].RuleResults {
                        label.LinkCache = append(label.LinkCache, ruleRes.CacheData)
                    }
                    logger.Debug("联动任务缓存了几个数据", len(label.LinkCache))
                    for i := 0; i < len(args.RuleResult["yolo"].([]Result)); i++ {
                        if args.RuleResult["yolo"].([]Result)[i].RuleGroupId == groupRule.GroupId { // 把联动数据追加上
                            args.RuleResult["yolo"].([]Result)[i].Others.LinkCache = label.LinkCache
                        }
                    }
                    for i := 0; i < len(args.RuleResult["face"].([]FaceResult)); i++ {
                        if args.RuleResult["face"].([]FaceResult)[i].RuleGroupId == groupRule.GroupId { // 把联动数据追加上
                            args.RuleResult["face"].([]FaceResult)[i].Others.LinkCache = label.LinkCache
                        }
                    }
                }
            }
        } else {
            logger.Warn("数组不圆满不打标签")
        }
    } else { // 没有报警,
        //logger.Info("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为false")
        // 所以也要去结果数组里放值或更新   07/30备注:  不应放值,应删除定时器,等为true时再度开启
        //for _, va := range timeEle.RuleResults {
        //    if args.CameraId != "" && va.CameraId == args.CameraId {
        //        va.Result = strconv.FormatBool(isOk)
        //    }
        //}
        for k, _ := range TimeEleList {
            if k == groupRule.GroupId {
                delete(TimeEleList, k)
                logger.Debug("因为定时器的一帧数据结果为false,干掉定时器")
            }
        }
        // 因为本帧数据不符合规则,所以也不用统计结果数组里的东西
 
    }
}
 
// 过滤规则先筛选出符合条件的目标数量
func filterRule(rule *protomsg.Rule, am *AreaMap) LittleRuleResult {
    if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
        // 处理的是人脸算法 如果这条规则配置的是人脸算法,过滤完条件之后直接得出结果,因为肯定没有数量条件,自己拼接
        //logger.Info("规则的算法id和区域的算法id:", rule.SdkId, "===", am.sdkId)
        if rule.PolygonId == am.areaId { // 算法和区域都得对的上
 
            if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a972" && rule.SdkArgAlias != "time_rule"{
                //logger.Debug("当前小规则是:",rule)
                flag := "false"
                // 把没有相似者的人脸从filterData中删除
                for index := 0; index < len(am.filterData); {
                    // 将达不到阈值的相似者从相似者数组中删除
                    logger.Info("看看相似者人数:",len(am.filterData[index].Liker))
                    if len(am.filterData[index].Liker) == 0 {
                        // Go 语言中切片删除元素的本质是:以被删除元素为分界点,将前后两个部分的内存重新连接起来。不用怀疑,数组删除元素就这么坑爹
                        am.filterData = append(am.filterData[:index], am.filterData[index+1:]...)
                    } else {
                        index++
                    }
                }
                if len(am.filterData) > 0 {
                    flag = "true"
                }
                logger.Info("---------人脸比对符合条件的数量为:",len(am.filterData))
                return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + flag, rule.Sort}
            }
            if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" { // 人脸检测
                //logger.Debug("当前小规则是:",rule)
                if rule.Operator == "==" || rule.Operator == ">=" || rule.Operator == "<=" || rule.Operator == "<" || rule.Operator == ">" || rule.Operator == "!=" {
                    // 如果是不规矩的连接符统统返回false 规则也只能判断人脸的相似度,所以不存在别的连接符
                    if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
                        logger.Info("-----------------------过规则之前区域内的人脸数量为:",am.targetNum)
                        var args []*Arg
                        if rule.RuleWithPre == "&&" {
                            args = am.filterData
                            //logger.Info("过滤后的args的长度为:",len(args))
                        } else {
                            args = am.args
                            //logger.Info("没过滤的args的长度为:",len(args))
                        }
                        // 先清空过滤后的数据,再往里塞本次过滤后的数据
                        am.filterData = am.filterData[0:0]
                        //logger.Info("-----------------------人脸过滤的args里的数量:", len(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字段
                        logger.Info("过完条件后的目标数量为:",am.targetNum)
                        if am.targetNum > 0 {
                            logger.Info("!!!!!!!!!人脸检测成功")
                            return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                        } else {
                            return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                        }
                    } else {
                        return LittleRuleResult{}
                    }
                } else {
                    return LittleRuleResult{}
                }
            } else {
                return LittleRuleResult{}
            }
        } else {
            return LittleRuleResult{}
        }
    } else {
        // 处理的都是yolo数据
        if rule.PolygonId == am.areaId { // 首先这条规则得是这个算法的规则,其次规则所对应的区域id要跟区域数据的id对的上
            if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
                var args []*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)
                    } 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 LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                } else {
                    return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                }
 
            } else {
                return LittleRuleResult{}
            }
 
        } else {
            return LittleRuleResult{}
        }
    }
}
 
// 如果有持续时间条件维护开启一个定时器
func duration(rule *protomsg.Rule, groupId string, am *AreaMap, args *SdkDatas, message *protomsg.SdkMessage) {
    if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上  配置的算法要对的上
        if rule.SdkArgAlias == "duration" { //
            logger.Info("当前小规则是:---------", rule)
            // 先看看定时器元素队列中是否有这条规则的定时器,如果有就不能再次创建了
            var flag bool = true
            for k, _ := range TimeEleList {
                if k == groupId+"+"+rule.Id {
                    flag = false // 有就置为false
                    logger.Info("有这个定时器,不再创建了:")
                }
            }
 
            if flag {
                timeLength, _ := strconv.Atoi(rule.SdkArgValue)
                timeEle := TimeElement{N: timeLength, InitN: timeLength, AlarmFlag: false, BufferFlag: 10, CacheSdkData: ResultMsg{message, args.RuleResult}} // 扔进去一个定时器元素(并缓存当前画面帧数据)
                //TimeEleList = make(map[string]timeElement)
                TimeEleList[groupId+"+"+rule.Id] = &timeEle // 定时器元素以当前持续时间小规则id为键
                logger.Info("创建了计数器")
            }
        }
    }
}
 
// 给数据库的规则表达式代参 args: 一条子规则,区域数据
func transferParameters(rule *protomsg.Rule, am *AreaMap) LittleRuleResult {
    if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上
        if rule.SdkArgAlias == "objCount" { // 如果参数是要区域内目标数量 即yolo 人脸不会有数量
            //logger.Info("当前小规则是:---------", rule)
            //logger.Info("得出结果阶段", "比较的规则是:", rule)
            if rule.Operator == "" {
                return LittleRuleResult{am.sdkName, strconv.Itoa(am.targetNum) + "" + rule.RuleWithPre, rule.Sort} // 如果后面不跟操作符就直接返回数量  比如要跟下一个区域比较数量的就直接返回本区域的数量
            }
            //args := am.targetNum     targetNum 已成所有目标的总数量,这里只算yolo的
            var num int = 0
            for _, data := range am.filterData {
                if data.IsYolo {
                    num++
                }
            }
            formula := strconv.Itoa(num) + " " + rule.Operator + " " + rule.SdkArgValue
            expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
            result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
            return LittleRuleResult{am.sdkName, rule.RuleWithPre + " " + strconv.FormatBool(result.(bool)), rule.Sort}
            // 加上关于算法的判断条件,不能只有关于规则的,有的算法本身就是一个规则,如个体静止,靠右行,所以,拿到当前子规则的sdkid来判断是否是那些特殊的规则
        } else if rule.SdkId == "IsStatic" { // 静止算法
            if am.isStatic {
                return LittleRuleResult{}
            } else {
                return LittleRuleResult{}
            }
        } else if rule.SdkId == "KeepRight" { // 靠右行算法
            if am.keepRight {
                return LittleRuleResult{}
            } else {
                return LittleRuleResult{}
            }
        }
    }
    return LittleRuleResult{}
}
func timeRuleResult(rule *protomsg.Rule, am *AreaMap) LittleRuleResult {
    if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上
        if rule.SdkArgAlias == "time_rule" { // 判断是否符合时间规
            //logger.Info("----------当前时间规则:---------", rule)
            // 根据放值字段里存的时间规则的id去另一个表里查需要比对的时间段(比如当前时间是周三,应根据区域id查出其周三的几个布防时间段,数组)
            //logger.Info("时间规则的测试")
            now := time.Now()
            index := getIndexOfWeek(now.Weekday().String())
            timeList := GetTimeById(rule.SdkArgValue, index)
            //logger.Info("当天的时间段集合:----------", timeList)
            //logger.Info("从数据库中查出的时间规则:", timeList)
            // 判断图片数据的时间是否符合当前规则 在一个即为true,全不在为false
 
            if rule.Operator == "satisfy" || rule.Operator == "==" { // 满足所选的时间规则
                flag := "false"
                for _, timeSlot := range timeList {
                    formula := "'" + timeSlot.Start + "'" + "<" + "'" + am.time + "'"
                    expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                    result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
 
                    formula1 := "'" + timeSlot.End + "'" + ">" + "'" + am.time + "'"
                    expression1, _ := govaluate.NewEvaluableExpression(formula1) // 得到数学公式
                    result1, _ := expression1.Evaluate(nil)                      // 得到数学公式的结果
                    //logger.Info("看看这两尊大神", result, result1)
                    if result.(bool) && result1.(bool) {
                        flag = "true"
                        break
                    }
                }
                return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + flag, rule.Sort}
            }
 
            if rule.Operator == "unsatisfy" || rule.Operator == "!=" { // 不满足所选的时间规则
                flag := "true"
                for _, timeSlot := range timeList {
                    formula := "'" + timeSlot.Start + "'" + " < " + "'" + am.time + "'"
                    //logger.Info("-----------------时间规则不满足的公式start:", formula)
                    expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                    result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
 
                    formula1 := "'" + timeSlot.End + "'" + " > " + "'" + am.time + "'"
                    //logger.Info("-----------------时间规则不满足的公式end:", formula1)
                    expression1, _ := govaluate.NewEvaluableExpression(formula1) // 得到数学公式
                    result1, _ := expression1.Evaluate(nil)                      // 得到数学公式的结果
                    if result.(bool) && result1.(bool) {
                        flag = "false"
                        break
                    }
                }
                return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + flag, rule.Sort}
            }
 
        }
    }
    return LittleRuleResult{}
}