diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6639073 --- /dev/null +++ b/.gitignore @@ -0,0 +1,89 @@ +# Built Visual Studio files +*.exe +*.dll +*.pdb +*.cache +*.mdb +*.obj +*.log +*.user +*.suo +*.userprefs +*.vsp +*.vspx +*.psess +*.pidb +*.tmp +*.svclog +*.sqlite +*.db +*.db-shm +*.db-wal +*.opendb + +# Build directories +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Tt]emp/ +[Pp]ublish/ +[Rr]elease/ +[Dd]ebug/ + +# Rider / ReSharper +*.DotSettings.user +.idea/ +.Rider/ +_ReSharper*/ +*.[Rr]esult + +# Visual Studio Code +.vscode/ + +# Test results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NuGet +*.nupkg +packages/ +*.snupkg +**/[Pp]ackages/* +!**/[Pp]ackages/build/ +!**/[Pp]ackages/repositories.config +*.nuspec + +# Azure +*.azurePubxml +*.portbridge.json +PublishScripts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# Configuration files +appsettings.*.json +secrets.json +*.KeyStore +*.pfx + +# Entity Framework +Migrations/obj/ +*/migrations/obj/ + +# Coverage & analysis +*.coverage +*.coveragexml +TestResults/ +.coverlet/ + +# Others +*.bak +*.tlog +*.ipch +*.iuser +*.tlog +*.ipr +.vs/ +.DS_Store +Thumbs.db diff --git a/Configs/Entrance.json b/Configs/Entrance.json new file mode 100644 index 0000000..395d73a --- /dev/null +++ b/Configs/Entrance.json @@ -0,0 +1,15 @@ +{ + "LaneName": "Entrance", + "LaneId": "#P-001", + "LaneDescription": "Main Entrance", + "CameraIp": "192.168.100.99", + "CameraPort": 80, + "GateIp": "127.0.0.1", + "GatePort": 5000, + "LedIp": "127.0.0.1", + "LedPort": 5001, + "LedTopMessage": "어서오세요", + "LedBottomMessage": "주차관리시스템", + "CmsIp": "127.0.0.1", + "CmsPort": 6000 +} \ No newline at end of file diff --git a/Inno.Common.Stubs/Class1.cs b/Inno.Common.Stubs/Class1.cs new file mode 100644 index 0000000..de676b0 --- /dev/null +++ b/Inno.Common.Stubs/Class1.cs @@ -0,0 +1,6 @@ +namespace Inno.Common.Stubs; + +public class Class1 +{ + +} diff --git a/Inno.Common.Stubs/Inno.Common.Stubs.csproj b/Inno.Common.Stubs/Inno.Common.Stubs.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Inno.Common.Stubs/Inno.Common.Stubs.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Inno.Common.Stubs/Inno/Communication/TCP/TcpClientConnector.cs b/Inno.Common.Stubs/Inno/Communication/TCP/TcpClientConnector.cs new file mode 100644 index 0000000..f1f83be --- /dev/null +++ b/Inno.Common.Stubs/Inno/Communication/TCP/TcpClientConnector.cs @@ -0,0 +1,65 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Inno.Communication.TCP +{ + public class TcpClientConnector : IDisposable + { + private TcpClient _client; + private NetworkStream _stream; + + public bool IsConnected => _client != null && _client.Connected; + + public async Task ConnectAsync(string host, int port, int timeout, CancellationToken token) + { + _client = new TcpClient(); + var connectTask = _client.ConnectAsync(host, port); + if (await Task.WhenAny(connectTask, Task.Delay(timeout, token)) == connectTask) + { + await connectTask; + try + { + _stream = _client.GetStream(); + } + catch + { + _client.Dispose(); + throw; + } + } + else + { + _client.Dispose(); + throw new TimeoutException(); + } + } + + public async Task WriteAsync(byte[] data, CancellationToken token) + { + if (_stream == null) throw new InvalidOperationException("Not connected"); + await _stream.WriteAsync(data, 0, data.Length, token); + } + + public async Task WriteAsync(string message, Encoding encoding, CancellationToken token) + { + if (_stream == null) throw new InvalidOperationException("Not connected"); + byte[] data = encoding.GetBytes(message); + await WriteAsync(data, token); + } + + public async Task ReadAsync(byte[] buffer, CancellationToken token) + { + if (_stream == null) throw new InvalidOperationException("Not connected"); + return await _stream.ReadAsync(buffer, 0, buffer.Length, token); + } + + public void Dispose() + { + _stream?.Dispose(); + _client?.Dispose(); + } + } +} diff --git a/Inno.Common.Stubs/Inno/Communication/TCP/TcpConnectionItem.cs b/Inno.Common.Stubs/Inno/Communication/TCP/TcpConnectionItem.cs new file mode 100644 index 0000000..d0893fe --- /dev/null +++ b/Inno.Common.Stubs/Inno/Communication/TCP/TcpConnectionItem.cs @@ -0,0 +1,9 @@ +namespace Inno.Communication.TCP +{ + public class TcpConnectionItem + { + public string Host { get; set; } + public int Port { get; set; } + public TcpConnectionItem(string host, int port) { Host = host; Port = port; } + } +} diff --git a/Inno.Common.Stubs/Inno/Rtsp/RawFramesDecoding/DecodedFrames/Video/IDecodedVideoFrame.cs b/Inno.Common.Stubs/Inno/Rtsp/RawFramesDecoding/DecodedFrames/Video/IDecodedVideoFrame.cs new file mode 100644 index 0000000..78465f5 --- /dev/null +++ b/Inno.Common.Stubs/Inno/Rtsp/RawFramesDecoding/DecodedFrames/Video/IDecodedVideoFrame.cs @@ -0,0 +1,6 @@ +namespace Inno.Rtsp.RawFramesDecoding.DecodedFrames.Video +{ + public interface IDecodedVideoFrame + { + } +} diff --git a/Inno.Common.Stubs/Inno/Rtsp/RtspPlayer.cs b/Inno.Common.Stubs/Inno/Rtsp/RtspPlayer.cs new file mode 100644 index 0000000..50dc43b --- /dev/null +++ b/Inno.Common.Stubs/Inno/Rtsp/RtspPlayer.cs @@ -0,0 +1,23 @@ +using System; +using RtspModule; +using Inno.Rtsp.RawFramesDecoding.DecodedFrames.Video; + +namespace Inno.Rtsp +{ + public class RtspPlayer : IDisposable + { + public event EventHandler RtspFrameReceived; + public event EventHandler ConnectionChanged; + + public void Init(RtspConnectionParameter param) { } + public void StartRtspStreaming() { } + public void StopRtspStreaming() { } + public void ChangeAddress(RtspConnectionParameter param) { } + public void Dispose() { } + } +} + +namespace Inno.Rtsp.RawFramesReceiving +{ + public class RawFramesSource { } +} diff --git a/Inno.Common.Stubs/Inno/Wpf/EncodingCodeDefines.cs b/Inno.Common.Stubs/Inno/Wpf/EncodingCodeDefines.cs new file mode 100644 index 0000000..b968778 --- /dev/null +++ b/Inno.Common.Stubs/Inno/Wpf/EncodingCodeDefines.cs @@ -0,0 +1,7 @@ +namespace Inno.Wpf +{ + public static class EncodingCodeDefines + { + public const int CODE_EUC_KR = 51949; + } +} diff --git a/Inno.Common.Stubs/RtspModule/RtspConnectionParameter.cs b/Inno.Common.Stubs/RtspModule/RtspConnectionParameter.cs new file mode 100644 index 0000000..1043ea8 --- /dev/null +++ b/Inno.Common.Stubs/RtspModule/RtspConnectionParameter.cs @@ -0,0 +1,8 @@ +namespace RtspModule +{ + public enum Company { Novitec } + public class RtspConnectionParameter + { + public RtspConnectionParameter(Company company, string ip, string port, string id, string pw) { } + } +} diff --git a/Inno.LPR/DeepLearningLibraries/DeepLearning_Model.cs b/Inno.LPR/DeepLearningLibraries/DeepLearning_Model.cs new file mode 100644 index 0000000..bb4617f --- /dev/null +++ b/Inno.LPR/DeepLearningLibraries/DeepLearning_Model.cs @@ -0,0 +1,41 @@ +namespace DeepLearning_Model_Sharp +{ + public enum ENUM_MODEL_TYPE + { + // CPU + _TYPE_C_SSD = 0, + _TYPE_C_YLv4, + _TYPE_C_YLv5, + _TYPE_C_YLvX, // v5, v8 + // DARKNET + _TYPE_D_TINY, + _TYPE_D_NORM, + // GPU + _TYPE_G_NORM, + _TYPE_G_CUDA, + _TYPE_G_VINO, + _TYPE_G_TRT, + _TYPE_G_DML, + _TYPE_G_DNNL, + // TRT + _TYPE_T_TRT, + } + + public enum ENUM_MODEL_DLL + { + _MODEL_DLL_CPU = 0, // CPU 21.4.2 + _MODEL_DLL_CPU2, // CPU 22.3.0 XP + _MODEL_DLL_CPU3, // CPU 23.0.0 + _MODEL_DLL_GPU, // DARKNET + _MODEL_DLL_GPU2, // GPU + _MODEL_DLL_GPU3, // TRT + } + + public enum ENUM_DLL_RESULT + { + _DLL_RST_OK = 1, + _DLL_RST_ERROR = 0, + _DLL_RST_ERROR_KEY = -1, + _DLL_RST_ERROR_MODEL = -2, + } +} diff --git a/Inno.LPR/DeepLearningLibraries/DeepLearning_Wrapper.cs b/Inno.LPR/DeepLearningLibraries/DeepLearning_Wrapper.cs new file mode 100644 index 0000000..15d0473 --- /dev/null +++ b/Inno.LPR/DeepLearningLibraries/DeepLearning_Wrapper.cs @@ -0,0 +1,372 @@ +using System.Runtime.InteropServices; +using DeepLearningSharp; +using OpenCvSharp; + +namespace DeepLearning_Model_Sharp +{ + public struct BBOX_T + { + public uint x, y, w, h; + public float prob; + public uint obj_id; + } + + public struct LPR_Boxes + { + public uint x, y, w, h; + public float prob; + public uint obj_id; + } + + public struct LPR_RESULT_PTR + { + public IntPtr vLPR_Boxes_Ptr; + public int nLPR_Boxes; + + public int nRST_LP; + public string mRST_Code; + } + + public struct LPR_RESULT_RST + { + public List vLPR_Boxes; + + public LPR_Boxes mRect_LP; + public int nRST_LP; + public string mRST_Code; + } + + public class DeepLearning_Wrapper : IDisposable + { + public const string DLL_DETECTION = "DeepLearningLPR26.dll"; + public const string DLL_OCR = "DeepLearningLPR.dll"; + + private IntPtr _pModel = IntPtr.Zero; + private readonly int _nModel_DLL = (int)ENUM_MODEL_DLL._MODEL_DLL_CPU3; + private readonly int _nModel_Type = (int)ENUM_MODEL_TYPE._TYPE_C_YLvX; + private readonly int _nMulti = 1; + private readonly int _nDecryption = 1; + private readonly int _GPUID = 0; + private int _nDLL_RST = (int)ENUM_DLL_RESULT._DLL_RST_ERROR; + + private readonly string _cf = ""; + private readonly string _wf; + + private readonly DeepLearning_Model_Wrapper mModel_Wrapper; + + public DeepLearning_Wrapper(int nModel_DLL, string cf, string wf, int nModel_Type, int nMulti, int nDecryption) + { + _nModel_DLL = nModel_DLL; + _nModel_Type = nModel_Type; + _nMulti = nMulti; + _nDecryption = nDecryption; + + _cf = cf; + _wf = wf; + + mModel_Wrapper = new DeepLearning_Model_Wrapper(); + } + + public DeepLearning_Wrapper() + { + _wf = DLL_DETECTION; + mModel_Wrapper = new DeepLearning_Model_Wrapper(); + } + + public DeepLearning_Wrapper(string wf) + { + _wf = wf; + mModel_Wrapper = new DeepLearning_Model_Wrapper(); + } + + public int Model_Wrapper_Construct() + { + try + { + _nDLL_RST = mModel_Wrapper._Model_Construct(_nModel_DLL, ref _pModel, _cf, _wf, _nModel_Type, _nDecryption, _GPUID); + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + + return _nDLL_RST; + } + + public int Model_Wrapper_Destruct() + { + try + { + _nDLL_RST = mModel_Wrapper._Model_Destruct(_nModel_DLL, ref _pModel); + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + + return _nDLL_RST; + } + + public int Model_Wrapper_Getversion(ref string strVersion) + { + try + { + _nDLL_RST = mModel_Wrapper._Model_Getversion(_nModel_DLL, _pModel, ref strVersion); + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + + return _nDLL_RST; + } + + public int Model_Wrapper_Detect(Mat mat_SRC, ref List vBBOX_T) + { + IntPtr matPtr = mat_SRC.CvPtr; + + try + { + IntPtr vBBOX_TPtr = IntPtr.Zero; + int nBBOX_T = 0; + + _nDLL_RST = mModel_Wrapper._Model_Detect(_nModel_DLL, _pModel, matPtr, ref vBBOX_TPtr, ref nBBOX_T, _nModel_Type); + + if (vBBOX_TPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize = Marshal.SizeOf(typeof(BBOX_T)); + + // Iterate over the results and convert them to _LPR_Boxes structs + for (int i = 0; i < nBBOX_T; i++) + { + IntPtr structPtr = IntPtr.Add(vBBOX_TPtr, i * structSize); + BBOX_T resultItem = Marshal.PtrToStructure(structPtr); + vBBOX_T.Add(resultItem); + } + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(vBBOX_TPtr); + } + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + finally + { + ; + } + + return _nDLL_RST; + } + + public int Model_Wrapper_LPR_Plate(Mat mat_LPR, Rect mRect_ROI, ref List vLPR_Boxes) + { + IntPtr matPtr = mat_LPR.CvPtr; + IntPtr rectPtr = IntPtr.Zero; + + try + { + rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Rect))); + Marshal.StructureToPtr(mRect_ROI, rectPtr, false); + + IntPtr vLPR_BoxesPtr = IntPtr.Zero; + int nLPR_Boxes = 0; + + _nDLL_RST = mModel_Wrapper._Model_LPR_Plate(_nModel_DLL, _pModel, matPtr, rectPtr, ref vLPR_BoxesPtr, ref nLPR_Boxes, _nMulti, _nModel_Type); + + if (vLPR_BoxesPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize = Marshal.SizeOf(typeof(LPR_Boxes)); + + // Iterate over the results and convert them to _LPR_Boxes structs + for (int i = 0; i < nLPR_Boxes; i++) + { + IntPtr structPtr = IntPtr.Add(vLPR_BoxesPtr, i * structSize); + LPR_Boxes resultItem = Marshal.PtrToStructure(structPtr); + vLPR_Boxes.Add(resultItem); + } + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(vLPR_BoxesPtr); + } + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + finally + { + if (rectPtr != IntPtr.Zero) Marshal.FreeHGlobal(rectPtr); + } + + return _nDLL_RST; + } + + public int Model_Wrapper_LPR_Code(Mat mat_LPR, Rect mRect_LP, ref LPR_RESULT_RST mLPR_RESULT_RST) + { + IntPtr matPtr = mat_LPR.CvPtr; + IntPtr rectPtr = IntPtr.Zero; + + try + { + rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Rect))); + Marshal.StructureToPtr(mRect_LP, rectPtr, false); + + IntPtr LPR_ResultPtr = IntPtr.Zero; + int nLPR_Result = 0; + + _nDLL_RST = mModel_Wrapper._Model_LPR_Code(_nModel_DLL, _pModel, matPtr, rectPtr, ref LPR_ResultPtr, ref nLPR_Result, _nModel_Type); + + if (LPR_ResultPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize = Marshal.SizeOf(typeof(LPR_RESULT_PTR)); + + List vLPR_RESULT = []; + // Iterate over the results and convert them to _LPR_Boxes struct + for (int i = 0; i < nLPR_Result; i++) + { + IntPtr structPtr = IntPtr.Add(LPR_ResultPtr, i * structSize); + LPR_RESULT_PTR resultItem = Marshal.PtrToStructure(structPtr); + vLPR_RESULT.Add(resultItem); + } + + for (int k = 0; k < vLPR_RESULT.Count; k++) + { + IntPtr vLPR_BoxesPtr = vLPR_RESULT[k].vLPR_Boxes_Ptr; + int nLPR_Boxes = vLPR_RESULT[k].nLPR_Boxes; + + if (vLPR_BoxesPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize_Boxes = Marshal.SizeOf(typeof(LPR_Boxes)); + + mLPR_RESULT_RST.vLPR_Boxes = []; + // Iterate over the results and convert them to _LPR_Boxes struct + for (int i = 0; i < nLPR_Boxes; i++) + { + IntPtr structPtr = IntPtr.Add(vLPR_BoxesPtr, i * structSize); + LPR_Boxes resultItem = Marshal.PtrToStructure(structPtr); + + if (i == 0) mLPR_RESULT_RST.mRect_LP = resultItem; + else mLPR_RESULT_RST.vLPR_Boxes.Add(resultItem); + } + + mLPR_RESULT_RST.nRST_LP = vLPR_RESULT[k].nRST_LP; + mLPR_RESULT_RST.mRST_Code = vLPR_RESULT[k].mRST_Code; + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(vLPR_BoxesPtr); + } + } + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(LPR_ResultPtr); + } + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + finally + { + if (rectPtr != IntPtr.Zero) Marshal.FreeHGlobal(rectPtr); + } + + return _nDLL_RST; + } + + public int Model_Wrapper_LPR_RST(Mat mat_LPR, Rect mRect_ROI, ref List vLPR_RESULT_RST) + { + IntPtr matPtr = mat_LPR.CvPtr; + IntPtr rectPtr = IntPtr.Zero; + + try + { + rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Rect))); + Marshal.StructureToPtr(mRect_ROI, rectPtr, false); + + IntPtr LPR_ResultPtr = IntPtr.Zero; + int nLPR_Result = 0; + + _nDLL_RST = mModel_Wrapper._Model_LPR_RST(_nModel_DLL, _pModel, matPtr, rectPtr, ref LPR_ResultPtr, ref nLPR_Result, _nMulti, _nModel_Type); + + if (LPR_ResultPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize = Marshal.SizeOf(typeof(LPR_RESULT_PTR)); + + List vLPR_RESULT = []; + // Iterate over the results and convert them to _LPR_Boxes struct + for (int i = 0; i < nLPR_Result; i++) + { + IntPtr structPtr = IntPtr.Add(LPR_ResultPtr, i * structSize); + LPR_RESULT_PTR resultItem = Marshal.PtrToStructure(structPtr); + vLPR_RESULT.Add(resultItem); + } + + LPR_RESULT_RST mLPR_RESULT_RST = new(); + for (int k = 0; k < vLPR_RESULT.Count; k++) + { + IntPtr vLPR_BoxesPtr = vLPR_RESULT[k].vLPR_Boxes_Ptr; + int nLPR_Boxes = vLPR_RESULT[k].nLPR_Boxes; + + if (vLPR_BoxesPtr != IntPtr.Zero) + { + // Calculate the size of each struct element + int structSize_Boxes = Marshal.SizeOf(typeof(LPR_Boxes)); + + mLPR_RESULT_RST.vLPR_Boxes = []; + // Iterate over the results and convert them to _LPR_Boxes struct + for (int i = 0; i < nLPR_Boxes; i++) + { + IntPtr structPtr = IntPtr.Add(vLPR_BoxesPtr, i * structSize); + LPR_Boxes resultItem = Marshal.PtrToStructure(structPtr); + + if (i == 0) mLPR_RESULT_RST.mRect_LP = resultItem; + else mLPR_RESULT_RST.vLPR_Boxes.Add(resultItem); + } + + mLPR_RESULT_RST.nRST_LP = vLPR_RESULT[k].nRST_LP; + mLPR_RESULT_RST.mRST_Code = vLPR_RESULT[k].mRST_Code; + + vLPR_RESULT_RST.Add(mLPR_RESULT_RST); + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(vLPR_BoxesPtr); + } + } + + // Clean up the allocated memory + mModel_Wrapper._Model_FreeHGlobal(LPR_ResultPtr); + } + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + finally + { + if (rectPtr != IntPtr.Zero) Marshal.FreeHGlobal(rectPtr); + } + + return _nDLL_RST; + } + + public void Dispose() + { + try + { + _nDLL_RST = Model_Wrapper_Destruct(); + } + catch (Exception exception) + { + Console.WriteLine(exception.Message); + } + GC.SuppressFinalize(this); + } + } +} diff --git a/Inno.LPR/Inno.LPR.csproj b/Inno.LPR/Inno.LPR.csproj new file mode 100644 index 0000000..383a1ed --- /dev/null +++ b/Inno.LPR/Inno.LPR.csproj @@ -0,0 +1,56 @@ + + + + net8.0-windows + enable + enable + true + AnyCPU;x64 + + + + + + + + + Libraries\DeepLearning_Sharp.dll + + + + + + DeepLearningLPR.dll + Always + + + DeepLearningLPR26.dll + PreserveNewest + + + DeepLearning_CPU3.dll + Never + + + DeepLearning_Model.dll + PreserveNewest + + + DeepLearning_Sharp.dll + Never + + + opencv_world4120.dll + PreserveNewest + + + opencv_world470.dll + PreserveNewest + + + tbb12.dll + PreserveNewest + + + + diff --git a/Inno.LPR/LicensePlateMotionDetector.cs b/Inno.LPR/LicensePlateMotionDetector.cs new file mode 100644 index 0000000..76e9621 --- /dev/null +++ b/Inno.LPR/LicensePlateMotionDetector.cs @@ -0,0 +1,90 @@ +using DeepLearning_Model_Sharp; +using OpenCvSharp; + +namespace Inno.LPR +{ + public class LicensePlateMotionDetector : IDisposable + { + private readonly DeepLearning_Wrapper _wrapperDetection; + private readonly DeepLearning_Wrapper _wrapperRecognition; + + public string ModelVersion { get; private set; } + + public LicensePlateMotionDetector() + { + try + { + _wrapperDetection = new DeepLearning_Wrapper(DeepLearning_Wrapper.DLL_DETECTION); + _wrapperRecognition = new DeepLearning_Wrapper(DeepLearning_Wrapper.DLL_OCR); + + var constructResult1 = _wrapperDetection.Model_Wrapper_Construct(); + if (constructResult1 != 1) { throw new InvalidOperationException("Detection Construct Fail"); } + + var constructResult2 = _wrapperRecognition.Model_Wrapper_Construct(); + if (constructResult2 != 1) { throw new InvalidOperationException("Recognition Construct Fail"); } + + string modelVersion = string.Empty; + var getVersionResult = _wrapperDetection.Model_Wrapper_Getversion(ref modelVersion); + + if (getVersionResult != 1) { throw new InvalidOperationException("Getversion Fail"); } + ModelVersion = modelVersion; + } + catch (Exception) + { + throw; + } + } + public List DetectLicensePlateExistence(Mat image, Rect roi) + { + List vLPR_Boxes = []; + _ = _wrapperDetection.Model_Wrapper_LPR_Plate(image, roi, ref vLPR_Boxes); + return vLPR_Boxes; + } + public LicensePlateRecognitionMotionData DetectLicensePlateExistence(MotionImageData data) + { + using var originalImage = data.Image; + Rect rectangleROI = data.ROI; + List vLPR_Boxes = []; + + var isLicensePlateExist = _wrapperDetection.Model_Wrapper_LPR_Plate(originalImage, rectangleROI, ref vLPR_Boxes); + bool value = isLicensePlateExist == 1 && vLPR_Boxes.Exists(x => x.w * x.h > data.MinimumArea && x.w * x.h < data.MaximumArea); + var motionData = new LicensePlateRecognitionMotionData(originalImage, data.CreatedTime, vLPR_Boxes, value); + + return motionData; + } + public LPR_RESULT_RST DetectLicensePlateCode(Mat image, List lpList) + { + var mLPR_Boxes = lpList.OrderByDescending(box => box.y).First(); + Rect rect_LP = new((int)mLPR_Boxes.x, (int)mLPR_Boxes.y, (int)mLPR_Boxes.w, (int)mLPR_Boxes.h); + LPR_RESULT_RST mLPR_RESULT_RST = new(); + _ = _wrapperRecognition.Model_Wrapper_LPR_Code(image, rect_LP, ref mLPR_RESULT_RST); + return mLPR_RESULT_RST; + } + public LPR_RESULT_RST DetectLicensePlateCode(Mat image, LPR_Boxes mLPR_Boxes) + { + Rect rect_LP = new((int)mLPR_Boxes.x, (int)mLPR_Boxes.y, (int)mLPR_Boxes.w, (int)mLPR_Boxes.h); + LPR_RESULT_RST mLPR_RESULT_RST = new(); + _ = _wrapperRecognition.Model_Wrapper_LPR_Code(image, rect_LP, ref mLPR_RESULT_RST); + return mLPR_RESULT_RST; + } + public void DetectLicensePlateCode(LicensePlateRecognitionMotionData motionData) + { + if (!motionData.IsLicensePlateExist) { return; } + var mLPR_Boxes = motionData.SelectedTrustedLprBox; + Rect rect_LP = new((int)mLPR_Boxes.x, (int)mLPR_Boxes.y, (int)mLPR_Boxes.w, (int)mLPR_Boxes.h); + LPR_RESULT_RST mLPR_RESULT_RST = new(); + var isExistCode = _wrapperRecognition.Model_Wrapper_LPR_Code(motionData.OriginalImage, rect_LP, ref mLPR_RESULT_RST); + if (isExistCode != 1) { return; } + + //motionData.DrawLicensePlateCharacterBoxes(mLPR_RESULT_RST.vLPR_Boxes, mLPR_Boxes.x, mLPR_Boxes.y); + motionData.AddLicensePlateCode(mLPR_RESULT_RST.mRST_Code); + } + + public void Dispose() + { + _wrapperDetection?.Dispose(); + _wrapperRecognition?.Dispose(); + GC.SuppressFinalize(this); + } + } +} diff --git a/Inno.LPR/LicensePlateRecognitionMotionData.cs b/Inno.LPR/LicensePlateRecognitionMotionData.cs new file mode 100644 index 0000000..838a78f --- /dev/null +++ b/Inno.LPR/LicensePlateRecognitionMotionData.cs @@ -0,0 +1,45 @@ +using DeepLearning_Model_Sharp; +using OpenCvSharp; + +namespace Inno.LPR +{ + public class LicensePlateRecognitionMotionData + { + public Mat OriginalImage { get; private set; } + public DateTime ImageCreatedTime { get; init; } + public List DetectedLprBoxList { get; init; } = []; + public LPR_Boxes SelectedTrustedLprBox { get; private set; } + public bool IsLicensePlateExist { get; private set; } = false; + public List LicensePlateCodeList { get; set; } = []; + public string LicensePlateCode { get; private set; } = string.Empty; + public int FrameNumber { get; set; } = -1; + + public LicensePlateRecognitionMotionData(Mat originalImage, DateTime imageCreatedTime, List lprBoxes, bool isLicensePlateExist) + { + OriginalImage = originalImage.Clone(); + ImageCreatedTime = imageCreatedTime; + DetectedLprBoxList.AddRange(lprBoxes); + if (DetectedLprBoxList.Count > 0) + { + SelectedTrustedLprBox = DetectedLprBoxList.OrderByDescending(box => box.y).First(); + } + IsLicensePlateExist = isLicensePlateExist; + } + + public void DrawLicensePlateCharacterBoxes(List boxes, uint coordinateOriginX, uint coordinateOriginY) + { + if (!IsLicensePlateExist) { return; } + + //foreach (_LPR_Boxes mLPR_Chars in boxes) + //{ + // Rect rect_Char = new((int)mLPR_Chars.x + (int)coordinateOriginX, (int)mLPR_Chars.y + (int)coordinateOriginY, + // (int)mLPR_Chars.w, (int)mLPR_Chars.h); + // Cv2.Rectangle(LicensePlateDisplayImage, rect_Char, Scalar.Blue, 1); + //} + } + public void AddLicensePlateCode(string lpCode) + { + LicensePlateCode = lpCode; + } + } +} diff --git a/Inno.LPR/MotionImageData.cs b/Inno.LPR/MotionImageData.cs new file mode 100644 index 0000000..e676fec --- /dev/null +++ b/Inno.LPR/MotionImageData.cs @@ -0,0 +1,13 @@ +using OpenCvSharp; + +namespace Inno.LPR +{ + public class MotionImageData(Mat image, Rect roi, int minimumArea, int maximumArea) + { + public Mat Image { get; private set; } = image; + public DateTime CreatedTime { get; private set; } = DateTime.Now; + public Rect ROI { get; private set; } = roi; + public int MinimumArea { get; private set; } = minimumArea; + public int MaximumArea { get; private set; } = maximumArea; + } +} diff --git a/LPR_Manager.slnx b/LPR_Manager.slnx new file mode 100644 index 0000000..b94bd3a --- /dev/null +++ b/LPR_Manager.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/LPR_Manager/App.xaml b/LPR_Manager/App.xaml new file mode 100644 index 0000000..097daf1 --- /dev/null +++ b/LPR_Manager/App.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LPR_Manager/App.xaml.cs b/LPR_Manager/App.xaml.cs new file mode 100644 index 0000000..4552ca2 --- /dev/null +++ b/LPR_Manager/App.xaml.cs @@ -0,0 +1,62 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace LPR_Manager; + +/// +/// Interaction logic for App.xaml +/// +public partial class App : Application +{ + protected override async void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + // 0. Initialize Logging + var configService = new Service.ConfigService(); + var sysConfig = await configService.LoadSystemConfigAsync(); + Service.LogService.ConfigureLogging(sysConfig.LogMode); + + // 1. Create Splash Screen + var splash = new View.SplashScreen(); + + // 2. Show Main Window immediately + var main = new MainWindow(); + this.MainWindow = main; + main.Show(); + + // Center Splash on Main Window + if (main.WindowState == WindowState.Maximized) + { + // If maximized, center on screen is usually correct, but let's ensure + splash.WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + else + { + // Calculate center relative to Main + splash.WindowStartupLocation = WindowStartupLocation.Manual; + splash.Left = main.Left + (main.Width - splash.Width) / 2; + splash.Top = main.Top + (main.Height - splash.Height) / 2; + } + + splash.Topmost = true; // Re-enforce topmost just in case + splash.Show(); // Show Splash AFTER calculating position + + // 3. Wait for MainViewModel Init OR 10s Timeout + if (main.DataContext is ViewModel.MainViewModel vm) + { + var timeoutTask = Task.Delay(10000); // 10 seconds max + var initTask = vm.InitializationTask; + + await Task.WhenAny(initTask, timeoutTask); + } + else + { + await Task.Delay(3000); + } + + + splash.Close(); + } +} diff --git a/LPR_Manager/AssemblyInfo.cs b/LPR_Manager/AssemblyInfo.cs new file mode 100644 index 0000000..cc29e7f --- /dev/null +++ b/LPR_Manager/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/LPR_Manager/Code/GlobalObject/BaseInfo.cs b/LPR_Manager/Code/GlobalObject/BaseInfo.cs new file mode 100644 index 0000000..13bedda --- /dev/null +++ b/LPR_Manager/Code/GlobalObject/BaseInfo.cs @@ -0,0 +1,13 @@ +namespace LPR_Manager.Code.GlobalObject +{ + public static class BaseInfo + { + public static string DeviceCode { get; set; } = "D0001"; // Default mock + } + + public static class MainDeviceItem + { + public static string LEDDisplayMessageNoMember { get; set; } = "미등록차량"; + public static string LEDDisplayMessageMember { get; set; } = "정기권차량"; + } +} diff --git a/LPR_Manager/Converters/InverseBooleanToVisibilityConverter.cs b/LPR_Manager/Converters/InverseBooleanToVisibilityConverter.cs new file mode 100644 index 0000000..1dab0dd --- /dev/null +++ b/LPR_Manager/Converters/InverseBooleanToVisibilityConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace LPR_Manager.Converters +{ + public class InverseBooleanToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool boolValue) + { + return boolValue ? Visibility.Collapsed : Visibility.Visible; + } + return Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/LPR_Manager/Icon/CI.ico b/LPR_Manager/Icon/CI.ico new file mode 100644 index 0000000..9a35c7e Binary files /dev/null and b/LPR_Manager/Icon/CI.ico differ diff --git a/LPR_Manager/Icon/CI.png b/LPR_Manager/Icon/CI.png new file mode 100644 index 0000000..d39ffef Binary files /dev/null and b/LPR_Manager/Icon/CI.png differ diff --git a/LPR_Manager/LPR_Manager.csproj b/LPR_Manager/LPR_Manager.csproj new file mode 100644 index 0000000..3c59980 --- /dev/null +++ b/LPR_Manager/LPR_Manager.csproj @@ -0,0 +1,52 @@ + + + + WinExe + net8.0-windows + enable + enable + true + AnyCPU;x64 + Icon\CI.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NtcClientAPI4Net.dll + PreserveNewest + + + + diff --git a/LPR_Manager/LPR_Manager_0jqb0m4x_wpftmp.csproj b/LPR_Manager/LPR_Manager_0jqb0m4x_wpftmp.csproj new file mode 100644 index 0000000..e9387c2 --- /dev/null +++ b/LPR_Manager/LPR_Manager_0jqb0m4x_wpftmp.csproj @@ -0,0 +1,264 @@ + + + LPR_Manager + obj\Debug\ + obj\ + D:\Documents\Projects\Parking\Center\LPR_Manager\LPR_Manager\obj\ + <_TargetAssemblyProjectName>LPR_Manager + LPR_Manager + + + + WinExe + net8.0-windows + enable + enable + true + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LPR_Manager/MainWindow.xaml b/LPR_Manager/MainWindow.xaml new file mode 100644 index 0000000..6eb2822 --- /dev/null +++ b/LPR_Manager/MainWindow.xaml @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +