diff --git a/Cis.Application/AppConfig.json b/Cis.Application/AppConfig.json index 07b7167..5c17e0c 100644 --- a/Cis.Application/AppConfig.json +++ b/Cis.Application/AppConfig.json @@ -1,4 +1,12 @@ { - "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", - + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + "CameraDataOptions": { + "LazyInit": false, + "LoopInterval": "1000" + }, + "PTZServer": { + "Type": "", + "Ip": "127.0.0.1", + "Port": "7022" + } } \ No newline at end of file diff --git a/Cis.Application/Core/Algo/HikMarkSeacher.cs b/Cis.Application/Core/Algo/HikMarkSeacher.cs index 78cc79e..83e9bb9 100644 --- a/Cis.Application/Core/Algo/HikMarkSeacher.cs +++ b/Cis.Application/Core/Algo/HikMarkSeacher.cs @@ -40,8 +40,8 @@ public class HikMarkSeacher : MarkSearcherBase protected override void CalcSensor() { - CameraCalcInfo.MinFocusX = 1783.6 / CameraCalcInfo.ImageWidth; - CameraCalcInfo.MinFocusY = 1781.4 / CameraCalcInfo.ImageHeight; + _cameraCalcInfo.MinFocusX = 1783.6 / _cameraCalcInfo.ImageWidth; + _cameraCalcInfo.MinFocusY = 1781.4 / _cameraCalcInfo.ImageHeight; } #endregion Implement @@ -50,13 +50,13 @@ public class HikMarkSeacher : MarkSearcherBase protected virtual double GetFx(double zoomPos) { - CameraCalcInfo calcInfo = CameraCalcInfo; + CameraCalcInfo calcInfo = _cameraCalcInfo; return calcInfo.MinFocusX * GetZoomTag(zoomPos); } protected virtual double GetFy(double zoomPos) { - CameraCalcInfo calcInfo = CameraCalcInfo; + CameraCalcInfo calcInfo = _cameraCalcInfo; return calcInfo.MinFocusY * GetZoomTag(zoomPos); } diff --git a/Cis.Application/Core/Algo/MarkSearcherBase.cs b/Cis.Application/Core/Algo/MarkSearcherBase.cs index ab8f86e..7e44e07 100644 --- a/Cis.Application/Core/Algo/MarkSearcherBase.cs +++ b/Cis.Application/Core/Algo/MarkSearcherBase.cs @@ -10,9 +10,9 @@ public abstract class MarkSearcherBase /// /// 当前相机参数信息 /// - protected CameraCalcInfo CameraCalcInfo { get; set; } + protected CameraCalcInfo _cameraCalcInfo { get; set; } - protected List MarkLabelInfoList { get; set; } = new(); + protected List _markLabelInfoList { get; set; } = new(); protected MatrixBuilder MBuilder { get; set; } = Matrix.Build; @@ -25,14 +25,7 @@ public abstract class MarkSearcherBase public MarkSearcherBase(CameraCalcInfo cameraCalcInfo) { - InitCameraCalcInfoRelated(cameraCalcInfo); - } - - protected void InitCameraCalcInfoRelated(CameraCalcInfo cameraCalcInfo) - { - CameraCalcInfo = cameraCalcInfo; - CalcSensor(); - World2CameraMatrix = ConvertWorldToCamera(cameraCalcInfo); + UpdateCameraCalcInfoRelated(cameraCalcInfo); } #region Calc @@ -41,23 +34,20 @@ public abstract class MarkSearcherBase /// 计算标签位置过程 /// /// - public void Calc(CameraCalcInfo cameraCalcInfo) + public List Calc() { - //判断 - if (IsCameraRotate(cameraCalcInfo)) - InitCameraCalcInfoRelated(cameraCalcInfo); + List resultList = new(); - if (World2CameraMatrix == null || MarkLabelInfoList.Count == 0) - return; + if (World2CameraMatrix == null || _markLabelInfoList.Count == 0) + return resultList; - for (int index = 0; index < MarkLabelInfoList.Count; index++) + foreach (MarkLabelCalcInfo item in _markLabelInfoList) { - MarkLabelCalcInfo label = MarkLabelInfoList[index]; - Matrix labelC2WMatrix = ConvertCameraToWorld(label); + Matrix labelC2WMatrix = ConvertCameraToWorld(item); Matrix labelPointMatrix = MBuilder.DenseOfArray(new double[,] { - { label.CanvasWidth / CameraCalcInfo.ImageWidth - 0.5 }, - { label.CanvasHeight / CameraCalcInfo.ImageHeight - 0.5 }, + { item.CanvasWidth / _cameraCalcInfo.ImageWidth - 0.5 }, + { item.CanvasHeight / _cameraCalcInfo.ImageHeight - 0.5 }, { 1 } }); Matrix lResult = labelC2WMatrix.Multiply(labelPointMatrix); @@ -65,18 +55,19 @@ public abstract class MarkSearcherBase double x = pResult[0, 0] / pResult[2, 0] + 0.5; double y = pResult[1, 0] / pResult[2, 0] + 0.5; - MarkLabelCalcResult labelCalcResult = new(); + MarkLabelCalcResult labelCalcResult; if (x > 0.99 || x < 0.01 || y > 0.99 || y < 0.01 || pResult[2, 0] < 0) - { - labelCalcResult.InFlag = false; - } + labelCalcResult = MarkLabelCalcResult.New(item.Id, false); else - { - labelCalcResult.InFlag = true; - labelCalcResult.CanvasLeft = x * CameraCalcInfo.ImageWidth; - labelCalcResult.CanvasTop = y * CameraCalcInfo.ImageHeight; - } + labelCalcResult = MarkLabelCalcResult.New(item.Id, true, (x * _cameraCalcInfo.ImageWidth), (y * _cameraCalcInfo.ImageHeight)); + resultList.Add(labelCalcResult); } + return resultList; + } + + public async Task> CalcAsync() + { + return await Task.Run(Calc); } /// @@ -84,12 +75,11 @@ public abstract class MarkSearcherBase /// /// /// - protected bool IsCameraRotate(CameraCalcInfo newInfo) + protected bool IsCameraRotate(PtzInfo newInfo) { - return CameraCalcInfo == null || - CameraCalcInfo.PtzInfo.Pan != newInfo.PtzInfo.Pan || - CameraCalcInfo.PtzInfo.Tilt != newInfo.PtzInfo.Tilt || - CameraCalcInfo.PtzInfo.Zoom != newInfo.PtzInfo.Zoom; + return _cameraCalcInfo.PtzInfo.Pan != newInfo.Pan || + _cameraCalcInfo.PtzInfo.Tilt != newInfo.Tilt || + _cameraCalcInfo.PtzInfo.Zoom != newInfo.Zoom; } /// @@ -204,4 +194,39 @@ public abstract class MarkSearcherBase protected abstract PointF GetFOfMatrixByZoomPos(double zoomPos); #endregion Util + + #region Operate Attr + + protected void UpdateCameraCalcInfoRelated(CameraCalcInfo cameraCalcInfo) + { + _cameraCalcInfo = cameraCalcInfo; + CalcSensor(); + World2CameraMatrix = ConvertWorldToCamera(cameraCalcInfo); + } + + public void UpdateCameraCalcInfo(PtzInfo ptzInfo) + { + if (IsCameraRotate(ptzInfo)) + { + _cameraCalcInfo.PtzInfo = ptzInfo; + World2CameraMatrix = ConvertWorldToCamera(_cameraCalcInfo); + } + } + + public void AddMarkLabelCalcInfo(MarkLabelCalcInfo markLabelCalcInfo) + { + _markLabelInfoList.Add(markLabelCalcInfo); + } + + public bool ExistsMarkLabelCalcInfo(object id) + { + foreach (MarkLabelCalcInfo info in _markLabelInfoList) + { + if (info.Id.Equals(id)) + return true; + } + return false; + } + + #endregion Operate Attr } \ No newline at end of file diff --git a/Cis.Application/Core/Api/PtzServerApi.cs b/Cis.Application/Core/Api/PtzServerApi.cs index 4f65872..f85b487 100644 --- a/Cis.Application/Core/Api/PtzServerApi.cs +++ b/Cis.Application/Core/Api/PtzServerApi.cs @@ -24,7 +24,7 @@ public class PtzServerApi : IPtzApi, ISingleton _stream = _tcpClient.GetStream(); } - public RequestRealControl GetPtzInfo(int cameraId) + public RequestRealControl GetPtzRrc(int cameraId) { RequestRealControl realControl = new(); try @@ -54,6 +54,13 @@ public class PtzServerApi : IPtzApi, ISingleton return realControl; } + public PtzInfo GetPtzInfo(int cameraId) + { + RequestRealControl rrc = GetPtzRrc(cameraId); + PtzInfo ptzInfo = PtzInfo.New(rrc.PTZPositionInfo.FP, rrc.PTZPositionInfo.FT, rrc.PTZPositionInfo.FZ); + return ptzInfo; + } + public static byte[] StructToByte(object structObj) { //获取结构体大小 diff --git a/Cis.Application/Core/Center/CameraDataCenter.cs b/Cis.Application/Core/Center/CameraDataCenter.cs index 3791f54..ea766c7 100644 --- a/Cis.Application/Core/Center/CameraDataCenter.cs +++ b/Cis.Application/Core/Center/CameraDataCenter.cs @@ -13,10 +13,29 @@ public class CameraDataCenter private readonly SqlSugarRepository _cmMarkLableRep; private readonly SqlSugarRepository _tbPtzCameraRep; private readonly PtzServerApi _ptzServerApi; + private readonly CameraDataOptions options = App.GetOptions(); private Thread _thread { get; set; } - private List _tbPtzCameraList { get; set; } - private ConcurrentDictionary _cameraPtzInfoDict { get; set; } + + /// + /// (cbCameraId, MarkSearcherBase) + /// + private ConcurrentDictionary _markSearcherDict { get; set; } = new(); + + /// + /// (cbCameraId, cbCameraIp) + /// + private Dictionary _cbCameraId2IpDict { get; set; } = new(); + + /// + /// (cameraIp, TbPtzCamera) + /// + private ConcurrentDictionary _tbPtzCameraDict { get; set; } = new(); + + /// + /// (cameraIp, PtzInfo) + /// + private ConcurrentDictionary _cameraPtzInfoDict { get; set; } = new(); #endregion Attr @@ -31,29 +50,16 @@ public class CameraDataCenter private void Init() { - // 初始化 tbPtzCameraList - _tbPtzCameraList = _tbPtzCameraRep.GetList(); - // 根据 Ip 去重 - _tbPtzCameraList = _tbPtzCameraList.Where((a, i) => _tbPtzCameraList.FindIndex(b => b.Ip == a.Ip) == i).ToList(); - - // 初始化 ptzInfoDict - _cameraPtzInfoDict = new ConcurrentDictionary(); - - // 初始化 thread - _thread = new Thread(WorkLoop) + if (!options.LazyInit) { - IsBackground = true// 设置后台线程 - }; - _thread.Start(); - } - - private void LazyInit() - { - // 初始化 tbPtzCameraList - _tbPtzCameraList = new(); - - // 初始化 ptzInfoDict - _cameraPtzInfoDict = new ConcurrentDictionary(); + List list = _tbPtzCameraRep.GetList(); + // 根据 Ip 去重 + foreach (TbPtzCamera item in list) + { + if (!_tbPtzCameraDict.ContainsKey(item.Ip)) + _tbPtzCameraDict[item.Ip] = item; + } + } // 初始化 thread _thread = new Thread(WorkLoop) @@ -65,47 +71,100 @@ public class CameraDataCenter #region Loop + /// + /// 循环运行 + /// private void WorkLoop() { while (true) { - GetPtzInfoByApi(); - Thread.Sleep(10000); + RefreshPtzInfoByApi(); + RefreshMarkSearcher(); + Thread.Sleep(options.LoopInterval); } } - private void GetPtzInfoByApi() + private void RefreshPtzInfoByApi() { - foreach (TbPtzCamera item in _tbPtzCameraList) + foreach (TbPtzCamera item in _tbPtzCameraDict.Values) { - RequestRealControl rrc = _ptzServerApi.GetPtzInfo(item.CameraId); - CameraCalcInfo ptzInfo = new() - { - Pan = rrc.PTZPositionInfo.FP, - Tilt = rrc.PTZPositionInfo.FT, - Zoom = rrc.PTZPositionInfo.FZ - }; + PtzInfo ptzInfo = _ptzServerApi.GetPtzInfo(item.CameraId); _cameraPtzInfoDict[item.Ip] = ptzInfo; } } - private void Calc() + private void RefreshMarkSearcher() { + foreach (KeyValuePair pair in _markSearcherDict) + { + long cameraId = pair.Key; + MarkSearcherBase markSearcher = pair.Value; + string cameraIp = _cbCameraId2IpDict[cameraId]; + if (cameraIp == null) continue; + PtzInfo ptzInfo = _cameraPtzInfoDict[cameraIp]; + if (ptzInfo == null) continue; + markSearcher.UpdateCameraCalcInfo(ptzInfo); + List resultList = markSearcher.Calc(); + } } #endregion Loop #region external call - public bool GetCamera(string ip) + /// + /// 激活 cbCamera 进入运算 + /// + /// + /// + public bool ActiveCamera(long cameraId) { - return false; + CbCamera cbCamera = _cbCameraRep.GetById(cameraId); + if (cbCamera == null) return false; + TbPtzCamera tbPtzCamera; + string cameraIp = cbCamera.Ip; + if (!_tbPtzCameraDict.IsExistKey(cameraIp)) + { + tbPtzCamera = _tbPtzCameraRep.GetFirst(u => u.Ip == cameraIp); + if (tbPtzCamera == null) return false; + _tbPtzCameraDict[cameraIp] = tbPtzCamera; + } + else + { + tbPtzCamera = _tbPtzCameraDict[cameraIp]; + } + _cbCameraId2IpDict[cbCamera.Id] = cameraIp; + CameraCalcInfo cameraCalcInfo = CameraCalcInfo.New(cameraId, _ptzServerApi.GetPtzInfo(tbPtzCamera.Id)); + HikMarkSeacher markSeacher = new(cameraCalcInfo); + List cmMarkLabelList = _cmMarkLableRep.GetList(u => u.CbCameraId == cameraId); + foreach (CmMarkLabel item in cmMarkLabelList) + { + MarkLabelCalcInfo markLabelCalcInfo = MarkLabelCalcInfo.New( + item.Id, + PtzInfo.New(item.PanPosition, item.TiltPosition, item.ZoomPosition), + item.CanvasWidth, + item.CanvasHeight, + item.CanvasLeft, + item.CanvasTop + ); + markSeacher.AddMarkLabelCalcInfo(markLabelCalcInfo); + } + _markSearcherDict[cameraId] = markSeacher; + return true; } - public bool ActiveCamera(string ip) + /// + /// 解除 cbCamera 进入运算 + /// + /// + /// + public bool DeActiveCamera(long cameraId) { + return false; + } - + public bool UpdateCamera(long cameraId, long markLabelId) + { return false; } diff --git a/Cis.Application/Core/Common/Options.cs b/Cis.Application/Core/Common/Options.cs index c121c2a..6eb32fa 100644 --- a/Cis.Application/Core/Common/Options.cs +++ b/Cis.Application/Core/Common/Options.cs @@ -1,5 +1,18 @@ namespace Cis.Application.Core; +public class CameraDataOptions : IConfigurableOptions +{ + /// + /// 是否懒加载 + /// + public bool LazyInit { get; set; } + + /// + /// 循环间隔,单位毫秒 + /// + public int LoopInterval { get; set; } +} + /// /// PtzServer选项 /// diff --git a/Cis.Application/Core/Entity/CameraCalcInfo.cs b/Cis.Application/Core/Entity/CameraCalcInfo.cs index 49ff7b7..f4c6bf7 100644 --- a/Cis.Application/Core/Entity/CameraCalcInfo.cs +++ b/Cis.Application/Core/Entity/CameraCalcInfo.cs @@ -5,6 +5,11 @@ /// public class CameraCalcInfo { + /// + /// Camera Id + /// + public long Id { get; set; } + /// /// Ptz 信息 /// @@ -26,6 +31,15 @@ public class CameraCalcInfo public double MinFocusX { get; set; } = 0f; public double MinFocusY { get; set; } = 0f; + + public static CameraCalcInfo New(long id, PtzInfo ptzInfo) + { + return new() + { + Id = id, + PtzInfo = ptzInfo + }; + } } /// @@ -47,6 +61,16 @@ public class PtzInfo /// Zoom 坐标 /// public double Zoom { get; set; } + + public static PtzInfo New(double pan, double tilt, double zoom) + { + return new() + { + Pan = pan, + Tilt = tilt, + Zoom = zoom + }; + } } /// @@ -54,6 +78,11 @@ public class PtzInfo /// public class MarkLabelCalcInfo { + /// + /// MarkLabel Id + /// + public long Id { get; set; } + /// /// Ptz 信息 /// @@ -78,6 +107,19 @@ public class MarkLabelCalcInfo /// 画布 top 距离 /// public double CanvasTop { get; set; } + + public static MarkLabelCalcInfo New(long id, PtzInfo ptzInfo, double canvasWidth, double canvasHeight, double canvasLeft, double canvasTop) + { + return new() + { + Id = id, + PtzInfo = ptzInfo, + CanvasWidth = canvasWidth, + CanvasHeight = canvasHeight, + CanvasLeft = canvasLeft, + CanvasTop = canvasTop + }; + } } /// @@ -85,6 +127,11 @@ public class MarkLabelCalcInfo /// public class MarkLabelCalcResult { + /// + /// MarkLabel Id + /// + public long Id { get; set; } + /// /// true 显示(在当前视频画面里面) /// false 不显示(不在当前视频画面里面) @@ -101,4 +148,23 @@ public class MarkLabelCalcResult /// public double CanvasTop { get; set; } + public static MarkLabelCalcResult New(long id, bool inFlag) + { + return new() + { + Id = id, + InFlag = inFlag + }; + } + + public static MarkLabelCalcResult New(long id, bool inFlag, double canvasLeft, double canvasTop) + { + return new() + { + Id = id, + InFlag = inFlag, + CanvasLeft = canvasLeft, + CanvasTop = canvasTop + }; + } } \ No newline at end of file diff --git a/Cis.Application/Startup.cs b/Cis.Application/Startup.cs index 19a7348..43c51e4 100644 --- a/Cis.Application/Startup.cs +++ b/Cis.Application/Startup.cs @@ -14,6 +14,7 @@ public class Startup : AppStartup /// public void ConfigureServices(IServiceCollection services) { + services.AddConfigurableOptions(); services.AddConfigurableOptions(); services.AddSingleton(new CameraDataCenter()); diff --git a/Cis.Application/Tb/Common/TbInfo.cs b/Cis.Application/Tb/Common/TbInfo.cs index 135f94d..b2e4830 100644 --- a/Cis.Application/Tb/Common/TbInfo.cs +++ b/Cis.Application/Tb/Common/TbInfo.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cis.Application.Tb; +namespace Cis.Application.Tb; public class TbInfo { @@ -25,5 +19,4 @@ public class TbInfo public const string TbPtzCameraTbName = "tb_ptzcamera"; #endregion Table Info -} - +} \ No newline at end of file diff --git a/Cis.Application/Tb/Service/TbPtzCameraService.cs b/Cis.Application/Tb/Service/TbPtzCameraService.cs index 03cb5bf..724403f 100644 --- a/Cis.Application/Tb/Service/TbPtzCameraService.cs +++ b/Cis.Application/Tb/Service/TbPtzCameraService.cs @@ -19,7 +19,7 @@ public class TbPtzCameraService : ITransient public async Task> GetList(string queryJson = "") { - JObject queryObj = !string.IsNullOrEmpty(queryJson) ? queryJson.ToJObject():default; + JObject queryObj = !string.IsNullOrEmpty(queryJson) ? queryJson.ToJObject() : default; List list = await _tbPtzCameraRep.AsQueryable() .ToListAsync(); return list; diff --git a/Cis.Core/CoreConfig.json b/Cis.Core/CoreConfig.json index 471e3b9..ac54671 100644 --- a/Cis.Core/CoreConfig.json +++ b/Cis.Core/CoreConfig.json @@ -21,14 +21,9 @@ ] }, "Cache": { - "CacheType": "Redis", // Memory、Redis + "CacheType": "Memory", // Memory、Redis "RedisConnectionString": "127.0.0.1:6379;password=123456;db=2" }, - "PTZServer": { - "Type": "", - "Ip": "127.0.0.1", - "Port": "7022" - }, "AppSettings": { "InjectSpecificationDocument": true // 生产环境是否开启Swagger }, diff --git a/Cis.Core/Extension/ObjectExtension.cs b/Cis.Core/Extension/ObjectExtension.cs index a080cf4..635ce49 100644 --- a/Cis.Core/Extension/ObjectExtension.cs +++ b/Cis.Core/Extension/ObjectExtension.cs @@ -138,4 +138,14 @@ public static class ObjectExtension var sc = pi.GetCustomAttributes(false).FirstOrDefault(u => u.IsIgnore == true); return sc != null; } + + public static bool IsExistKey(this IDictionary dict, object key) + { + foreach (object item in dict.Keys) + { + if (Equals(key, item)) + return true; + } + return false; + } } \ No newline at end of file