using Edge.Core.Processor; using Edge.Core.Processor.Dispatcher.Attributes; using Edge.Core.UniversalApi; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AreaIntrudeDetecterServer { [MetaPartsDescriptor( "lang-zh-cn:区域闯入检测lang-zh-tw:區域闖入檢測lang-en-us:Area intrude detecter", "lang-zh-cn:接收某区域的闯入行为,此程序作为服务器(接收端)需要与检测客户端配合使用(如基于视频流分析的jetson inference framework)" + "lang-en-us:接收某区域的闯入行为,此程序作为服务器(接收端)需要与检测客户端配合使用(如基于视频流分析的jetson inference framework)", new[] { "lang-zh-cn:摄像头lang-en-us:Cameralang-zh-tw:攝像頭" })] public class App : IAppProcessor { private IServiceProvider services; public string MetaConfigName { get; set; } public class Area { public string Name { get; set; } public int BndBox_LeftTop_X { get; set; } public int BndBox_RightBottom_X { get; set; } public int BndBox_LeftTop_Y { get; set; } public int BndBox_RightBottom_Y { get; set; } } /// /// basically info can refer https://rawgit.com/dusty-nv/jetson-inference/python/docs/html/python/jetson.inference.html#detectNet /// public class Detection { public string AreaName { get; set; } public int? ClassID { get; set; } public string ClassName { get; set; } public double Confidence { get; set; } public int? Height { get; set; } public int? Width { get; set; } } private Timer timelyFireGenericAlarmTimer; private int busy = 0; private List cache = new List(); public App(int appConfig, IServiceProvider services) { this.services = services; this.timelyFireGenericAlarmTimer = new Timer(async (o) => { if (0 != Interlocked.CompareExchange(ref this.busy, 1, 0)) return; try { var groupByAreaName = cache.GroupBy(d => new { d.AreaName, d.ClassName }); var universalApiHub = this.services.GetRequiredService(); foreach (var g in groupByAreaName) { foreach (var ig in g) { await universalApiHub.ClearAndFirePersistGenericAlarm(this, new GenericAlarm() { Category = $"区域闯入检测", Title = $"{this.GetFriendlyAreaName(g.Key.AreaName)} - {this.GetFriendlyClassName(ig.ClassName)}闯入", Detail = $"系统有{(Math.Round(ig.Confidence, 2) * 100).ToString().Substring(0, 2)}%的确信度认为有{ig.ClassName} (ClassId: {ig.ClassID})闯入至区域: {this.GetFriendlyAreaName(g.Key.AreaName)}", Severity = GenericAlarmSeverity.Warning }, g => g.Title, g => g.Title); } } this.cache.Clear(); } finally { this.busy = 0; } }, null, 0, 1500); } int maxWaitTimes = 20; [UniversalApi] public async Task Report(IEnumerable input) { Console.WriteLine(input.Select(d => $"Detect in area: {d.AreaName} has object: {d.ClassName} with conf: {d.Confidence}").Aggregate((acc, n) => acc + " | " + n)); int waitTimes = 0; while (0 != Interlocked.CompareExchange(ref this.busy, 1, 0)) { Thread.Sleep(50); waitTimes++; if (waitTimes > maxWaitTimes) return false; } try { this.cache.AddRange(input); } finally { this.busy = 0; } return true; } private string GetFriendlyAreaName(string rawName) { switch (rawName.ToLower()) { case "indoor0": return "消防通道A"; case "indoor1": return "消防通道B"; case "indoor2": return "消防通道C"; case "indoor3": return "消防通道D"; case "indoor4": return "消防通道E"; case "outdoor0": return "卸油区通道A"; case "outdoor1": return "卸油区通道B"; case "outdoor2": return "油罐区通道A"; case "outdoor3": return "油罐区通道B"; case "outdoor4": return "油罐区通道C"; default: return rawName; } } private string GetFriendlyClassName(string rawName) { switch (rawName.ToLower()) { case "person": return "人员"; case "chair": return "座椅"; case "bird": return "鸟类"; case "truck": return "卡车"; case "car": return "小汽车"; default: return rawName; } } private List savedAreas = new List(); [UniversalApi] public async Task SaveAreas(IEnumerable input) { this.savedAreas.AddRange(input); return true; } [UniversalApi] public async Task> GetAreas() { return this.savedAreas; } [UniversalApi] public async Task ClearAreas() { this.savedAreas.Clear(); return true; } public void Init(IEnumerable processors) { //throw new NotImplementedException(); } } }