From e4502c338a8bc06ca97aab1fa8bcac769d832ca0 Mon Sep 17 00:00:00 2001 From: zqm Date: Mon, 16 Mar 2026 17:05:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=9F=BA=E7=A1=80=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XCamera/Test/Form1.Designer.cs | 261 ++++++++ Windows/CS/Framework4.0/XCamera/Test/Form1.cs | 567 ++++++++++++++++++ .../CS/Framework4.0/XCamera/Test/Form1.resx | 120 ++++ .../CS/Framework4.0/XCamera/Test/Program.cs | 21 + .../XCamera/Test/Properties/AssemblyInfo.cs | 36 ++ .../Test/Properties/Resources.Designer.cs | 71 +++ .../XCamera/Test/Properties/Resources.resx | 117 ++++ .../Test/Properties/Settings.Designer.cs | 30 + .../XCamera/Test/Properties/Settings.settings | 7 + .../CS/Framework4.0/XCamera/Test/Test.csproj | 78 +++ .../Framework4.0/XCamera/TestApp/Program.cs | 136 +++++ .../TestApp/Properties/AssemblyInfo.cs | 36 ++ .../XCamera/TestApp/TestApp.csproj | 65 ++ Windows/CS/Framework4.0/XCamera/XCamera.sln | 6 + .../XCamera/XCamera/XCamera.csproj | 2 +- .../src/Core/CameraConnectionManager.cs | 24 +- .../XCamera/src/Core/ConfigurationManager.cs | 186 +++++- .../XCamera/XCamera/src/Models/EventArgs.cs | 80 +++ .../XCamera/src/UI/RegionEditorForm.cs | 56 +- .../XCamera/src/Vision/ImageProcessor.cs | 62 +- .../XCamera/XCamera/src/Vision/LedDetector.cs | 2 +- .../XCamera/XCamera/src/XCamera.cs | 19 +- .../XCamera/XCamera/src/XCameraManager.cs | 90 +-- 23 files changed, 1930 insertions(+), 142 deletions(-) create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Form1.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Form1.resx create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Program.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Properties/AssemblyInfo.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.Designer.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.resx create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.Designer.cs create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.settings create mode 100644 Windows/CS/Framework4.0/XCamera/Test/Test.csproj create mode 100644 Windows/CS/Framework4.0/XCamera/TestApp/Program.cs create mode 100644 Windows/CS/Framework4.0/XCamera/TestApp/Properties/AssemblyInfo.cs create mode 100644 Windows/CS/Framework4.0/XCamera/TestApp/TestApp.csproj create mode 100644 Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs new file mode 100644 index 0000000..2099df9 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.Designer.cs @@ -0,0 +1,261 @@ +namespace Test +{ + partial class Form1 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.LedImage = new System.Windows.Forms.PictureBox(); + this.btnInitialize = new System.Windows.Forms.Button(); + this.btnSetConfigFile = new System.Windows.Forms.Button(); + this.btnStartCamera = new System.Windows.Forms.Button(); + this.btnStartCapture = new System.Windows.Forms.Button(); + this.btnDetectLeds = new System.Windows.Forms.Button(); + this.btnGetLedStatuses = new System.Windows.Forms.Button(); + this.btnShowRegionEditor = new System.Windows.Forms.Button(); + this.btnShutdown = new System.Windows.Forms.Button(); + this.btnStopCapture = new System.Windows.Forms.Button(); + this.btnStopCamera = new System.Windows.Forms.Button(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.txtLog = new System.Windows.Forms.TextBox(); + this.lblStatus = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.LedImage)).BeginInit(); + this.statusStrip1.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // LedImage + // + this.LedImage.BackColor = System.Drawing.SystemColors.ControlDark; + this.LedImage.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.LedImage.Location = new System.Drawing.Point(12, 12); + this.LedImage.Name = "LedImage"; + this.LedImage.Size = new System.Drawing.Size(557, 426); + this.LedImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.LedImage.TabIndex = 0; + this.LedImage.TabStop = false; + // + // btnInitialize + // + this.btnInitialize.Location = new System.Drawing.Point(608, 38); + this.btnInitialize.Name = "btnInitialize"; + this.btnInitialize.Size = new System.Drawing.Size(111, 31); + this.btnInitialize.TabIndex = 1; + this.btnInitialize.Text = "1. 初始化"; + this.btnInitialize.UseVisualStyleBackColor = true; + this.btnInitialize.Click += new System.EventHandler(this.btnInitialize_Click); + // + // btnSetConfigFile + // + this.btnSetConfigFile.Location = new System.Drawing.Point(608, 89); + this.btnSetConfigFile.Name = "btnSetConfigFile"; + this.btnSetConfigFile.Size = new System.Drawing.Size(111, 31); + this.btnSetConfigFile.TabIndex = 2; + this.btnSetConfigFile.Text = "2. 设置配置文件"; + this.btnSetConfigFile.UseVisualStyleBackColor = true; + this.btnSetConfigFile.Click += new System.EventHandler(this.btnSetConfigFile_Click); + // + // btnStartCamera + // + this.btnStartCamera.Location = new System.Drawing.Point(608, 140); + this.btnStartCamera.Name = "btnStartCamera"; + this.btnStartCamera.Size = new System.Drawing.Size(111, 31); + this.btnStartCamera.TabIndex = 3; + this.btnStartCamera.Text = "3. 启动摄像头"; + this.btnStartCamera.UseVisualStyleBackColor = true; + this.btnStartCamera.Click += new System.EventHandler(this.btnStartCamera_Click); + // + // btnStartCapture + // + this.btnStartCapture.Location = new System.Drawing.Point(608, 191); + this.btnStartCapture.Name = "btnStartCapture"; + this.btnStartCapture.Size = new System.Drawing.Size(111, 31); + this.btnStartCapture.TabIndex = 4; + this.btnStartCapture.Text = "4. 开始捕获"; + this.btnStartCapture.UseVisualStyleBackColor = true; + this.btnStartCapture.Click += new System.EventHandler(this.btnStartCapture_Click); + // + // btnDetectLeds + // + this.btnDetectLeds.Location = new System.Drawing.Point(608, 242); + this.btnDetectLeds.Name = "btnDetectLeds"; + this.btnDetectLeds.Size = new System.Drawing.Size(111, 31); + this.btnDetectLeds.TabIndex = 5; + this.btnDetectLeds.Text = "5. LED识别"; + this.btnDetectLeds.UseVisualStyleBackColor = true; + this.btnDetectLeds.Click += new System.EventHandler(this.btnDetectLeds_Click); + // + // btnGetLedStatuses + // + this.btnGetLedStatuses.Location = new System.Drawing.Point(608, 293); + this.btnGetLedStatuses.Name = "btnGetLedStatuses"; + this.btnGetLedStatuses.Size = new System.Drawing.Size(111, 31); + this.btnGetLedStatuses.TabIndex = 6; + this.btnGetLedStatuses.Text = "6. 状态查询"; + this.btnGetLedStatuses.UseVisualStyleBackColor = true; + this.btnGetLedStatuses.Click += new System.EventHandler(this.btnGetLedStatuses_Click); + // + // btnShowRegionEditor + // + this.btnShowRegionEditor.Location = new System.Drawing.Point(608, 344); + this.btnShowRegionEditor.Name = "btnShowRegionEditor"; + this.btnShowRegionEditor.Size = new System.Drawing.Size(111, 31); + this.btnShowRegionEditor.TabIndex = 7; + this.btnShowRegionEditor.Text = "7. 区域编辑器"; + this.btnShowRegionEditor.UseVisualStyleBackColor = true; + this.btnShowRegionEditor.Click += new System.EventHandler(this.btnShowRegionEditor_Click); + // + // btnShutdown + // + this.btnShutdown.Location = new System.Drawing.Point(608, 395); + this.btnShutdown.Name = "btnShutdown"; + this.btnShutdown.Size = new System.Drawing.Size(111, 31); + this.btnShutdown.TabIndex = 8; + this.btnShutdown.Text = "8. 关闭"; + this.btnShutdown.UseVisualStyleBackColor = true; + this.btnShutdown.Click += new System.EventHandler(this.btnShutdown_Click); + // + // btnStopCapture + // + this.btnStopCapture.Location = new System.Drawing.Point(725, 191); + this.btnStopCapture.Name = "btnStopCapture"; + this.btnStopCapture.Size = new System.Drawing.Size(63, 31); + this.btnStopCapture.TabIndex = 9; + this.btnStopCapture.Text = "停止"; + this.btnStopCapture.UseVisualStyleBackColor = true; + this.btnStopCapture.Click += new System.EventHandler(this.btnStopCapture_Click); + // + // btnStopCamera + // + this.btnStopCamera.Location = new System.Drawing.Point(725, 140); + this.btnStopCamera.Name = "btnStopCamera"; + this.btnStopCamera.Size = new System.Drawing.Size(63, 31); + this.btnStopCamera.TabIndex = 10; + this.btnStopCamera.Text = "停止"; + this.btnStopCamera.UseVisualStyleBackColor = true; + this.btnStopCamera.Click += new System.EventHandler(this.btnStopCamera_Click); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 451); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(800, 22); + this.statusStrip1.TabIndex = 11; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(44, 17); + this.toolStripStatusLabel1.Text = "状态栏"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.txtLog); + this.groupBox1.Location = new System.Drawing.Point(12, 444); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(557, 100); + this.groupBox1.TabIndex = 12; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "日志"; + // + // txtLog + // + this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtLog.Location = new System.Drawing.Point(3, 17); + this.txtLog.Multiline = true; + this.txtLog.Name = "txtLog"; + this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtLog.Size = new System.Drawing.Size(551, 80); + this.txtLog.TabIndex = 0; + // + // lblStatus + // + this.lblStatus.AutoSize = true; + this.lblStatus.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblStatus.ForeColor = System.Drawing.Color.Red; + this.lblStatus.Location = new System.Drawing.Point(12, 550); + this.lblStatus.Name = "lblStatus"; + this.lblStatus.Size = new System.Drawing.Size(96, 12); + this.lblStatus.TabIndex = 13; + this.lblStatus.Text = "状态: 未初始化"; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 574); + this.Controls.Add(this.lblStatus); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.btnStopCamera); + this.Controls.Add(this.btnStopCapture); + this.Controls.Add(this.btnShutdown); + this.Controls.Add(this.btnShowRegionEditor); + this.Controls.Add(this.btnGetLedStatuses); + this.Controls.Add(this.btnDetectLeds); + this.Controls.Add(this.btnStartCapture); + this.Controls.Add(this.btnStartCamera); + this.Controls.Add(this.btnSetConfigFile); + this.Controls.Add(this.btnInitialize); + this.Controls.Add(this.LedImage); + this.Name = "Form1"; + this.Text = "XCamera LED灯识别测试程序"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.LedImage)).EndInit(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox LedImage; + private System.Windows.Forms.Button btnInitialize; + private System.Windows.Forms.Button btnSetConfigFile; + private System.Windows.Forms.Button btnStartCamera; + private System.Windows.Forms.Button btnStartCapture; + private System.Windows.Forms.Button btnDetectLeds; + private System.Windows.Forms.Button btnGetLedStatuses; + private System.Windows.Forms.Button btnShowRegionEditor; + private System.Windows.Forms.Button btnShutdown; + private System.Windows.Forms.Button btnStopCapture; + private System.Windows.Forms.Button btnStopCamera; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox txtLog; + private System.Windows.Forms.Label lblStatus; + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.cs b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs new file mode 100644 index 0000000..1341bb7 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.cs @@ -0,0 +1,567 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using XCamera; +using XCamera.Models; + +namespace Test +{ + public partial class Form1 : Form + { + private bool _isInitialized = false; + private bool _isConnected = false; + private bool _isCapturing = false; + private Thread _captureThread; + private bool _shouldStopCapture = false; + + public Form1() + { + InitializeComponent(); + InitializeEvents(); + UpdateUI(); + } + + /// + /// 初始化事件处理 + /// + private void InitializeEvents() + { + // 订阅XCamera事件 + XCamera.LedStatusUpdated += OnLedStatusUpdated; + XCamera.ConnectionStateChanged += OnConnectionStateChanged; + XCamera.CaptureStateChanged += OnCaptureStateChanged; + XCamera.ErrorOccurred += OnErrorOccurred; + } + + /// + /// 1. 初始化 + /// + private void btnInitialize_Click(object sender, EventArgs e) + { + try + { + LogMessage("正在初始化..."); + + // 使用默认配置文件路径 + string configPath = System.IO.Path.Combine(Application.StartupPath, "config", "sample_config.json"); + + if (XCamera.Initialize(configPath)) + { + _isInitialized = true; + LogMessage("初始化成功!"); + + // 显示配置信息 + var config = XCamera.GetCurrentConfig(); + if (config != null) + { + LogMessage($"摄像头IP: {config.IpAddress}"); + LogMessage($"TCP端口: {config.TcpPort}"); + LogMessage($"LED区域数: {config.LedRegions.Count}"); + } + } + else + { + LogMessage("初始化失败!"); + } + } + catch (Exception ex) + { + LogMessage($"初始化错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// 2. 设置配置文件路径 + /// + private void btnSetConfigFile_Click(object sender, EventArgs e) + { + try + { + using (OpenFileDialog openFileDialog = new OpenFileDialog()) + { + openFileDialog.Filter = "JSON文件|*.json|所有文件|*.*"; + openFileDialog.Title = "选择配置文件"; + + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + LogMessage($"正在加载配置文件: {openFileDialog.FileName}"); + + if (XCamera.SetConfigFile(openFileDialog.FileName)) + { + LogMessage("配置文件加载成功!"); + + // 显示配置信息 + var config = XCamera.GetCurrentConfig(); + if (config != null) + { + LogMessage($"摄像头IP: {config.IpAddress}"); + LogMessage($"LED区域数: {config.LedRegions.Count}"); + } + } + else + { + LogMessage("配置文件加载失败!"); + } + } + } + } + catch (Exception ex) + { + LogMessage($"配置文件加载错误: {ex.Message}"); + } + } + + /// + /// 3. 启动摄像头 + /// + private void btnStartCamera_Click(object sender, EventArgs e) + { + try + { + if (!_isInitialized) + { + LogMessage("请先初始化!"); + return; + } + + LogMessage("正在启动摄像头..."); + + if (XCamera.StartCamera()) + { + LogMessage("摄像头启动成功!"); + } + else + { + LogMessage("摄像头启动失败!"); + } + } + catch (Exception ex) + { + LogMessage($"启动摄像头错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// 4. 开始捕获图像 + /// + private void btnStartCapture_Click(object sender, EventArgs e) + { + try + { + if (!_isConnected) + { + LogMessage("请先连接摄像头!"); + return; + } + + if (_isCapturing) + { + LogMessage("已经在捕获中!"); + return; + } + + LogMessage("正在开始捕获图像..."); + + if (XCamera.StartCapture(1000)) // 1秒间隔 + { + LogMessage("开始捕获图像成功!"); + } + else + { + LogMessage("开始捕获图像失败!"); + } + } + catch (Exception ex) + { + LogMessage($"开始捕获错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// 5. LED灯识别 + /// + private void btnDetectLeds_Click(object sender, EventArgs e) + { + try + { + if (!_isConnected) + { + LogMessage("请先连接摄像头!"); + return; + } + + LogMessage("正在识别LED灯..."); + + var statuses = XCamera.DetectLeds(); + LogMessage($"检测到 {statuses.Count} 个LED灯:"); + + foreach (var status in statuses) + { + LogMessage($" {status.GetStatusDescription()}"); + } + + // 显示图像(如果有的话) + DisplayLedImage(statuses); + } + catch (Exception ex) + { + LogMessage($"LED识别错误: {ex.Message}"); + } + } + + /// + /// 6. 状态查询 + /// + private void btnGetLedStatuses_Click(object sender, EventArgs e) + { + try + { + if (!_isConnected) + { + LogMessage("请先连接摄像头!"); + return; + } + + LogMessage("正在查询LED状态..."); + + var statuses = XCamera.GetLedStatuses(); + LogMessage($"当前LED状态 ({statuses.Count} 个):"); + + foreach (var status in statuses) + { + LogMessage($" {status.GetStatusDescription()}"); + } + } + catch (Exception ex) + { + LogMessage($"状态查询错误: {ex.Message}"); + } + } + + /// + /// 7. 区域设置窗口 + /// + private void btnShowRegionEditor_Click(object sender, EventArgs e) + { + try + { + LogMessage("正在打开区域编辑器..."); + XCamera.ShowRegionEditor(); + LogMessage("区域编辑器已关闭"); + } + catch (Exception ex) + { + LogMessage($"区域编辑器错误: {ex.Message}"); + } + } + + /// + /// 8. 资源释放 + /// + private void btnShutdown_Click(object sender, EventArgs e) + { + try + { + LogMessage("正在释放资源..."); + + if (_isCapturing) + { + XCamera.StopCapture(); + } + + if (_isConnected) + { + XCamera.StopCamera(); + } + + XCamera.Shutdown(); + + _isInitialized = false; + _isConnected = false; + _isCapturing = false; + + LogMessage("资源已释放"); + } + catch (Exception ex) + { + LogMessage($"资源释放错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// 停止捕获 + /// + private void btnStopCapture_Click(object sender, EventArgs e) + { + try + { + if (!_isCapturing) + { + LogMessage("当前未在捕获中!"); + return; + } + + LogMessage("正在停止捕获..."); + XCamera.StopCapture(); + LogMessage("捕获已停止"); + } + catch (Exception ex) + { + LogMessage($"停止捕获错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// 停止摄像头 + /// + private void btnStopCamera_Click(object sender, EventArgs e) + { + try + { + if (!_isConnected) + { + LogMessage("摄像头未连接!"); + return; + } + + LogMessage("正在停止摄像头..."); + + if (_isCapturing) + { + XCamera.StopCapture(); + } + + XCamera.StopCamera(); + LogMessage("摄像头已停止"); + } + catch (Exception ex) + { + LogMessage($"停止摄像头错误: {ex.Message}"); + } + + UpdateUI(); + } + + /// + /// LED状态更新事件处理 + /// + private void OnLedStatusUpdated(object sender, LedStatusEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new Action(OnLedStatusUpdated), sender, e); + return; + } + + LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] LED状态更新:"); + foreach (var status in e.Statuses) + { + LogMessage($" {status.GetStatusDescription()}"); + } + } + + /// + /// 连接状态变更事件处理 + /// + private void OnConnectionStateChanged(object sender, ConnectionStateEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new Action(OnConnectionStateChanged), sender, e); + return; + } + + _isConnected = e.IsConnected; + LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 摄像头连接状态: {(e.IsConnected ? "已连接" : "已断开")}"); + UpdateUI(); + } + + /// + /// 捕获状态变更事件处理 + /// + private void OnCaptureStateChanged(object sender, CaptureStateEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new Action(OnCaptureStateChanged), sender, e); + return; + } + + _isCapturing = e.IsCapturing; + LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 图像捕获状态: {(e.IsCapturing ? "开始捕获" : "停止捕获")}"); + UpdateUI(); + } + + /// + /// 错误事件处理 + /// + private void OnErrorOccurred(object sender, ErrorEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new Action(OnErrorOccurred), sender, e); + return; + } + + LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 错误: {e.ErrorMessage}"); + } + + /// + /// 日志消息 + /// + private void LogMessage(string message) + { + if (InvokeRequired) + { + BeginInvoke(new Action(LogMessage), message); + return; + } + + string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); + txtLog.AppendText($"[{timestamp}] {message}" + Environment.NewLine); + txtLog.ScrollToCaret(); + } + + /// + /// 显示LED图像 + /// + private void DisplayLedImage(List statuses) + { + // 这里可以添加显示LED图像的逻辑 + // 例如:在PictureBox中绘制LED状态的可视化表示 + + if (statuses.Count > 0) + { + // 创建简单的可视化表示 + Bitmap bitmap = new Bitmap(LedImage.Width, LedImage.Height); + using (Graphics g = Graphics.FromImage(bitmap)) + { + g.Clear(Color.Black); + + int ledCount = statuses.Count; + int ledWidth = LedImage.Width / Math.Max(ledCount, 1); + int ledHeight = LedImage.Height / 2; + + for (int i = 0; i < statuses.Count; i++) + { + var status = statuses[i]; + Rectangle ledRect = new Rectangle(i * ledWidth + 10, LedImage.Height / 4, ledWidth - 20, ledHeight); + + // 根据状态设置颜色 + Color ledColor = GetLedColor(status); + using (Brush brush = new SolidBrush(ledColor)) + { + g.FillEllipse(brush, ledRect); + } + + // 绘制标签 + using (Font font = new Font("Arial", 8)) + using (Brush textBrush = new SolidBrush(Color.White)) + { + string label = $"{status.RegionName}\n{status.State}"; + g.DrawString(label, font, textBrush, ledRect.X, ledRect.Bottom + 5); + } + } + } + + LedImage.Image = bitmap; + } + } + + /// + /// 获取LED颜色 + /// + private Color GetLedColor(LedStatus status) + { + if (status.State == LedState.Off) + return Color.Gray; + + switch (status.DetectedColor) + { + case LedColor.Red: + return status.IsBlinking ? Color.Pink : Color.Red; + case LedColor.Yellow: + return status.IsBlinking ? Color.LightYellow : Color.Yellow; + case LedColor.Blue: + return status.IsBlinking ? Color.LightBlue : Color.Blue; + case LedColor.Green: + return status.IsBlinking ? Color.LightGreen : Color.Green; + default: + return Color.DarkGray; + } + } + + /// + /// 更新UI状态 + /// + private void UpdateUI() + { + btnInitialize.Enabled = !_isInitialized; + btnSetConfigFile.Enabled = _isInitialized; + btnStartCamera.Enabled = _isInitialized && !_isConnected; + btnStopCamera.Enabled = _isConnected; + btnStartCapture.Enabled = _isConnected && !_isCapturing; + btnStopCapture.Enabled = _isCapturing; + btnDetectLeds.Enabled = _isConnected; + btnGetLedStatuses.Enabled = _isConnected; + btnShowRegionEditor.Enabled = _isInitialized; + btnShutdown.Enabled = _isInitialized; + + // 更新状态标签 + if (_isCapturing) + lblStatus.Text = "状态: 正在捕获"; + else if (_isConnected) + lblStatus.Text = "状态: 已连接"; + else if (_isInitialized) + lblStatus.Text = "状态: 已初始化"; + else + lblStatus.Text = "状态: 未初始化"; + + lblStatus.ForeColor = _isConnected ? Color.Green : Color.Red; + } + + /// + /// 窗体关闭事件 + /// + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + try + { + // 确保释放资源 + if (_isCapturing) + { + XCamera.StopCapture(); + } + + if (_isConnected) + { + XCamera.StopCamera(); + } + + if (_isInitialized) + { + XCamera.Shutdown(); + } + } + catch + { + // 忽略关闭时的错误 + } + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Form1.resx b/Windows/CS/Framework4.0/XCamera/Test/Form1.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Program.cs b/Windows/CS/Framework4.0/XCamera/Test/Program.cs new file mode 100644 index 0000000..8f48897 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Test +{ + static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/Windows/CS/Framework4.0/XCamera/Test/Properties/AssemblyInfo.cs b/Windows/CS/Framework4.0/XCamera/Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..01590ef --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Test")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("8d4ae4b2-086d-476f-8434-949361bda8d8")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.Designer.cs b/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.Designer.cs new file mode 100644 index 0000000..cfde990 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本: 4.0.30319.42000 +// +// 对此文件的更改可能导致不正确的行为,如果 +// 重新生成代码,则所做更改将丢失。 +// +//------------------------------------------------------------------------------ + +namespace Test.Properties +{ + + + /// + /// 强类型资源类,用于查找本地化字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// 返回此类使用的缓存 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Test.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 覆盖当前线程的 CurrentUICulture 属性 + /// 使用此强类型的资源类的资源查找。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.resx b/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.Designer.cs b/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.Designer.cs new file mode 100644 index 0000000..a8cf573 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Test.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.settings b/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Windows/CS/Framework4.0/XCamera/Test/Test.csproj b/Windows/CS/Framework4.0/XCamera/Test/Test.csproj new file mode 100644 index 0000000..033e437 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/Test/Test.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {8D4AE4B2-086D-476F-8434-949361BDA8D8} + WinExe + Test + Test + v4.0 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/TestApp/Program.cs b/Windows/CS/Framework4.0/XCamera/TestApp/Program.cs new file mode 100644 index 0000000..5a858de --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/TestApp/Program.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using XCamera; +using XCamera.Models; + +namespace XCamera.TestApp +{ + /// + /// XCamera库简单测试程序 + /// + class Program + { + static void Main(string[] args) + { + Console.WriteLine("XCamera LED灯识别库测试程序"); + Console.WriteLine("=========================================="); + + try + { + // 订阅事件 + XCamera.LedStatusUpdated += OnLedStatusUpdated; + XCamera.ConnectionStateChanged += OnConnectionStateChanged; + XCamera.ErrorOccurred += OnErrorOccurred; + + // 1. 初始化 + Console.WriteLine("正在初始化..."); + if (!XCamera.Initialize("config\\sample_config.json")) + { + Console.WriteLine("初始化失败!"); + return; + } + Console.WriteLine("初始化成功!"); + + // 显示当前配置 + var config = XCamera.GetCurrentConfig(); + if (config != null) + { + Console.WriteLine($"摄像头IP: {config.IpAddress}"); + Console.WriteLine($"TCP端口: {config.TcpPort}"); + Console.WriteLine($"LED区域数: {config.LedRegions.Count}"); + } + + // 2. 启动摄像头 + Console.WriteLine("正在启动摄像头..."); + if (!XCamera.StartCamera()) + { + Console.WriteLine("启动摄像头失败!"); + return; + } + Console.WriteLine("摄像头启动成功!"); + + // 3. 手动检测一次LED状态 + Console.WriteLine("正在检测LED状态..."); + var statuses = XCamera.DetectLeds(); + Console.WriteLine($"检测到 {statuses.Count} 个LED灯:"); + foreach (var status in statuses) + { + Console.WriteLine($" {status.GetStatusDescription()}"); + } + + // 4. 开始循环捕获(可选) + Console.WriteLine("\n是否开始循环捕获? (y/n)"); + string response = Console.ReadLine(); + + if (response.ToLower() == "y") + { + Console.WriteLine("开始循环捕获,按任意键停止..."); + XCamera.StartCapture(2000); // 2秒间隔 + + // 等待用户输入 + Console.ReadKey(); + + XCamera.StopCapture(); + Console.WriteLine("停止捕获"); + } + + // 5. 显示区域编辑器(可选) + Console.WriteLine("\n是否显示区域编辑器? (y/n)"); + response = Console.ReadLine(); + + if (response.ToLower() == "y") + { + Console.WriteLine("显示区域编辑器..."); + XCamera.ShowRegionEditor(); + } + + // 6. 关闭资源 + Console.WriteLine("正在关闭资源..."); + XCamera.Shutdown(); + Console.WriteLine("资源已释放"); + + } + catch (Exception ex) + { + Console.WriteLine($"程序异常: {ex.Message}"); + Console.WriteLine($"堆栈跟踪: {ex.StackTrace}"); + } + finally + { + XCamera.Shutdown(); + } + + Console.WriteLine("\n测试程序结束,按任意键退出..."); + Console.ReadKey(); + } + + /// + /// LED状态更新事件处理 + /// + private static void OnLedStatusUpdated(object sender, LedStatusEventArgs e) + { + Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] LED状态更新:"); + foreach (var status in e.Statuses) + { + Console.WriteLine($" {status.GetStatusDescription()}"); + } + } + + /// + /// 连接状态变更事件处理 + /// + private static void OnConnectionStateChanged(object sender, ConnectionStateEventArgs e) + { + Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 摄像头连接状态: {(e.IsConnected ? "已连接" : "已断开")}"); + } + + /// + /// 错误事件处理 + /// + private static void OnErrorOccurred(object sender, ErrorEventArgs e) + { + Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 错误: {e.ErrorMessage}"); + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/TestApp/Properties/AssemblyInfo.cs b/Windows/CS/Framework4.0/XCamera/TestApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..79c883c --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/TestApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("XCamera.TestApp")] +[assembly: AssemblyDescription("XCamera库测试程序")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("JoyD")] +[assembly: AssemblyProduct("XCamera.TestApp")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("c9d8e7f6-5b4a-4c3d-8e2f-1a0b9c8d7e6f")] + +// 程序集的版本信息由下列四个值组成: 1.0.0.0 +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用"生成号"和"修订号"的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/TestApp/TestApp.csproj b/Windows/CS/Framework4.0/XCamera/TestApp/TestApp.csproj new file mode 100644 index 0000000..d8e6112 --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/TestApp/TestApp.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {C9D8E7F6-5B4A-4C3D-8E2F-1A0B9C8D7E6F} + Exe + Properties + XCamera.TestApp + XCamera.TestApp + v4.0 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + {B8E762E5-4A3B-4F7D-9C2E-8F3A7B9C5D1E} + XCamera + + + + + config\sample_config.json + PreserveNewest + + + XCloudSDK.dll + PreserveNewest + + + + \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera.sln b/Windows/CS/Framework4.0/XCamera/XCamera.sln index f725b44..c3352c6 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera.sln +++ b/Windows/CS/Framework4.0/XCamera/XCamera.sln @@ -4,6 +4,8 @@ VisualStudioVersion = 15.0.36617.4 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XCamera", "XCamera\XCamera.csproj", "{B8E762E5-4A3B-4F7D-9C2E-8F3A7B9C5D1E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8D4AE4B2-086D-476F-8434-949361BDA8D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -14,6 +16,10 @@ Global {B8E762E5-4A3B-4F7D-9C2E-8F3A7B9C5D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {B8E762E5-4A3B-4F7D-9C2E-8F3A7B9C5D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B8E762E5-4A3B-4F7D-9C2E-8F3A7B9C5D1E}.Release|Any CPU.Build.0 = Release|Any CPU + {8D4AE4B2-086D-476F-8434-949361BDA8D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D4AE4B2-086D-476F-8434-949361BDA8D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D4AE4B2-086D-476F-8434-949361BDA8D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D4AE4B2-086D-476F-8434-949361BDA8D8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/XCamera.csproj b/Windows/CS/Framework4.0/XCamera/XCamera/XCamera.csproj index c135220..bd3ef4d 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/XCamera.csproj +++ b/Windows/CS/Framework4.0/XCamera/XCamera/XCamera.csproj @@ -39,7 +39,6 @@ - @@ -54,6 +53,7 @@ + diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs index c56f460..8ad8c0a 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/CameraConnectionManager.cs @@ -24,12 +24,12 @@ namespace XCamera.Core /// /// 连接状态变更事件 /// - public event EventHandler ConnectionStateChanged; + public event EventHandler ConnectionStateChanged; /// /// 播放状态变更事件 /// - public event EventHandler PlayStateChanged; + public event EventHandler PlayStateChanged; /// /// 是否已连接 @@ -141,12 +141,12 @@ namespace XCamera.Core _isConnected = true; } - OnConnectionStateChanged(true); + OnConnectionStateChanged(); return true; } catch (Exception ex) { - OnConnectionStateChanged(false); + OnConnectionStateChanged(); throw new Exception($"连接摄像头失败: {ex.Message}", ex); } } @@ -183,7 +183,7 @@ namespace XCamera.Core _isConnected = false; } - OnConnectionStateChanged(false); + OnConnectionStateChanged(); } catch (Exception ex) { @@ -228,12 +228,12 @@ namespace XCamera.Core _isPlaying = true; } - OnPlayStateChanged(true); + OnPlayStateChanged(); return true; } catch (Exception ex) { - OnPlayStateChanged(false); + OnPlayStateChanged(); throw new Exception($"开始实时预览失败: {ex.Message}", ex); } } @@ -261,7 +261,7 @@ namespace XCamera.Core _playHandle = -1; } - OnPlayStateChanged(false); + OnPlayStateChanged(); } catch (Exception ex) { @@ -431,17 +431,17 @@ namespace XCamera.Core /// /// 触发连接状态变更事件 /// - private void OnConnectionStateChanged(bool connected) + private void OnConnectionStateChanged() { - ConnectionStateChanged?.Invoke(this, connected); + ConnectionStateChanged?.Invoke(this, EventArgs.Empty); } /// /// 触发播放状态变更事件 /// - private void OnPlayStateChanged(bool playing) + private void OnPlayStateChanged() { - PlayStateChanged?.Invoke(this, playing); + PlayStateChanged?.Invoke(this, EventArgs.Empty); } /// diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs index 4a06724..114a412 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Core/ConfigurationManager.cs @@ -2,7 +2,6 @@ using System; using System.IO; using System.Text; using System.Collections.Generic; -using Newtonsoft.Json; using XCamera.Models; namespace XCamera.Core @@ -19,7 +18,7 @@ namespace XCamera.Core /// /// 配置变更事件 /// - public event EventHandler ConfigChanged; + public event EventHandler ConfigChanged; /// /// 当前配置 @@ -77,7 +76,9 @@ namespace XCamera.Core } string jsonContent = File.ReadAllText(configFilePath, Encoding.UTF8); - var config = JsonConvert.DeserializeObject(jsonContent); + + // 简单的JSON解析(不使用Newtonsoft.Json) + var config = ParseJsonConfig(jsonContent); if (config == null || !config.IsValid) { @@ -90,7 +91,7 @@ namespace XCamera.Core _configFilePath = configFilePath; } - OnConfigChanged(config); + OnConfigChanged(); return true; } catch (Exception ex) @@ -124,7 +125,7 @@ namespace XCamera.Core configToSave = _config; } - string jsonContent = JsonConvert.SerializeObject(configToSave, Formatting.Indented); + string jsonContent = SerializeConfig(configToSave); // 确保目录存在 string directory = Path.GetDirectoryName(targetPath); @@ -164,7 +165,7 @@ namespace XCamera.Core _config = newConfig; } - OnConfigChanged(newConfig); + OnConfigChanged(); } /// @@ -186,7 +187,7 @@ namespace XCamera.Core } } - OnConfigChanged(_config); + OnConfigChanged(); } /// @@ -215,7 +216,7 @@ namespace XCamera.Core } } - OnConfigChanged(_config); + OnConfigChanged(); } /// @@ -236,7 +237,7 @@ namespace XCamera.Core if (removed) { - OnConfigChanged(_config); + OnConfigChanged(); } return removed; @@ -269,7 +270,7 @@ namespace XCamera.Core } } - OnConfigChanged(_config); + OnConfigChanged(); } /// @@ -296,6 +297,163 @@ namespace XCamera.Core } } + /// + /// 简单的JSON解析(兼容.NET Framework 4.0) + /// + private CameraConfig ParseJsonConfig(string jsonContent) + { + try + { + var config = new CameraConfig(); + + // 简单的JSON解析实现 + // 这里使用基本的字符串解析,实际项目中建议使用Newtonsoft.Json + + // 提取IP地址 + var ipMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""IpAddress""\s*:\s*""([^""]+)"""); + if (ipMatch.Success) config.IpAddress = ipMatch.Groups[1].Value; + + // 提取端口 + var tcpPortMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""TcpPort""\s*:\s*(\d+)"); + if (tcpPortMatch.Success) config.TcpPort = int.Parse(tcpPortMatch.Groups[1].Value); + + var httpPortMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""HttpPort""\s*:\s*(\d+)"); + if (httpPortMatch.Success) config.HttpPort = int.Parse(httpPortMatch.Groups[1].Value); + + var onvifPortMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""OnvifPort""\s*:\s*(\d+)"); + if (onvifPortMatch.Success) config.OnvifPort = int.Parse(onvifPortMatch.Groups[1].Value); + + // 提取用户名和密码 + var usernameMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""Username""\s*:\s*""([^""]+)"""); + if (usernameMatch.Success) config.Username = usernameMatch.Groups[1].Value; + + var passwordMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""Password""\s*:\s*""([^""]*)"""); + if (passwordMatch.Success) config.Password = passwordMatch.Groups[1].Value; + + // 提取通道 + var channelMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""Channel""\s*:\s*(\d+)"); + if (channelMatch.Success) config.Channel = int.Parse(channelMatch.Groups[1].Value); + + // 提取LED区域 + var ledRegionsMatch = System.Text.RegularExpressions.Regex.Match(jsonContent, @"""LedRegions""\s*:\s*\[([^\]]+)\]"); + if (ledRegionsMatch.Success) + { + var regionsContent = ledRegionsMatch.Groups[1].Value; + var regionMatches = System.Text.RegularExpressions.Regex.Matches(regionsContent, @"\{([^}]+)\}"); + + foreach (System.Text.RegularExpressions.Match regionMatch in regionMatches) + { + var region = ParseLedRegion(regionMatch.Groups[1].Value); + if (region != null) + { + config.LedRegions.Add(region); + } + } + } + + return config; + } + catch (Exception ex) + { + throw new Exception($"JSON解析失败: {ex.Message}", ex); + } + } + + /// + /// 解析LED区域 + /// + private LedRegion ParseLedRegion(string regionContent) + { + try + { + var region = new LedRegion(); + + // 提取ID + var idMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""Id""\s*:\s*""([^""]+)"""); + if (idMatch.Success) region.Id = idMatch.Groups[1].Value; + + // 提取名称 + var nameMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""Name""\s*:\s*""([^""]+)"""); + if (nameMatch.Success) region.Name = nameMatch.Groups[1].Value; + + // 提取坐标和尺寸 + var xMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""X""\s*:\s*(\d+)"); + if (xMatch.Success) region.X = int.Parse(xMatch.Groups[1].Value); + + var yMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""Y""\s*:\s*(\d+)"); + if (yMatch.Success) region.Y = int.Parse(yMatch.Groups[1].Value); + + var widthMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""Width""\s*:\s*(\d+)"); + if (widthMatch.Success) region.Width = int.Parse(widthMatch.Groups[1].Value); + + var heightMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""Height""\s*:\s*(\d+)"); + if (heightMatch.Success) region.Height = int.Parse(heightMatch.Groups[1].Value); + + // 提取期望颜色 + var colorMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""ExpectedColor""\s*:\s*""([^""]+)"""); + if (colorMatch.Success) + { + if (Enum.TryParse(colorMatch.Groups[1].Value, out var color)) + { + region.ExpectedColor = color; + } + } + + // 提取容差和亮度阈值 + var toleranceMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""ColorTolerance""\s*:\s*(\d+)"); + if (toleranceMatch.Success) region.ColorTolerance = int.Parse(toleranceMatch.Groups[1].Value); + + var brightnessMatch = System.Text.RegularExpressions.Regex.Match(regionContent, @"""MinBrightness""\s*:\s*(\d+)"); + if (brightnessMatch.Success) region.MinBrightness = int.Parse(brightnessMatch.Groups[1].Value); + + return region.IsValid ? region : null; + } + catch + { + return null; + } + } + + /// + /// 序列化配置为JSON + /// + private string SerializeConfig(CameraConfig config) + { + var sb = new StringBuilder(); + sb.AppendLine("{"); + sb.AppendLine($" \"IpAddress\": \"{config.IpAddress}\","); + sb.AppendLine($" \"TcpPort\": {config.TcpPort},"); + sb.AppendLine($" \"HttpPort\": {config.HttpPort},"); + sb.AppendLine($" \"OnvifPort\": {config.OnvifPort},"); + sb.AppendLine($" \"Username\": \"{config.Username}\","); + sb.AppendLine($" \"Password\": \"{config.Password}\","); + sb.AppendLine($" \"Channel\": {config.Channel},"); + sb.AppendLine(" \"LedRegions\": ["); + + for (int i = 0; i < config.LedRegions.Count; i++) + { + var region = config.LedRegions[i]; + sb.AppendLine(" {"); + sb.AppendLine($" \"Id\": \"{region.Id}\","); + sb.AppendLine($" \"Name\": \"{region.Name}\","); + sb.AppendLine($" \"X\": {region.X},"); + sb.AppendLine($" \"Y\": {region.Y},"); + sb.AppendLine($" \"Width\": {region.Width},"); + sb.AppendLine($" \"Height\": {region.Height},"); + sb.AppendLine($" \"ExpectedColor\": \"{region.ExpectedColor}\","); + sb.AppendLine($" \"ColorTolerance\": {region.ColorTolerance},"); + sb.AppendLine($" \"MinBrightness\": {region.MinBrightness}"); + sb.Append(" }"); + if (i < config.LedRegions.Count - 1) sb.Append(","); + sb.AppendLine(); + } + + sb.AppendLine(" ]"); + sb.AppendLine("}"); + + return sb.ToString(); + } + /// /// 创建默认配置 /// @@ -315,7 +473,7 @@ namespace XCamera.Core LedRegions = new List() }; - string jsonContent = JsonConvert.SerializeObject(defaultConfig, Formatting.Indented); + string jsonContent = SerializeConfig(defaultConfig); // 确保目录存在 string directory = Path.GetDirectoryName(configFilePath); @@ -332,7 +490,7 @@ namespace XCamera.Core _configFilePath = configFilePath; } - OnConfigChanged(defaultConfig); + OnConfigChanged(); return true; } catch @@ -344,9 +502,9 @@ namespace XCamera.Core /// /// 触发配置变更事件 /// - private void OnConfigChanged(CameraConfig config) + private void OnConfigChanged() { - ConfigChanged?.Invoke(this, config); + ConfigChanged?.Invoke(this, EventArgs.Empty); } } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs new file mode 100644 index 0000000..64a807a --- /dev/null +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Models/EventArgs.cs @@ -0,0 +1,80 @@ +using System; + +namespace XCamera.Models +{ + /// + /// LED状态更新事件参数 + /// + public class LedStatusEventArgs : EventArgs + { + /// + /// LED状态列表 + /// + public System.Collections.Generic.List Statuses { get; set; } + + /// + /// 构造函数 + /// + public LedStatusEventArgs(System.Collections.Generic.List statuses) + { + Statuses = statuses; + } + } + + /// + /// 连接状态事件参数 + /// + public class ConnectionStateEventArgs : EventArgs + { + /// + /// 连接状态 + /// + public bool IsConnected { get; set; } + + /// + /// 构造函数 + /// + public ConnectionStateEventArgs(bool isConnected) + { + IsConnected = isConnected; + } + } + + /// + /// 捕获状态事件参数 + /// + public class CaptureStateEventArgs : EventArgs + { + /// + /// 捕获状态 + /// + public bool IsCapturing { get; set; } + + /// + /// 构造函数 + /// + public CaptureStateEventArgs(bool isCapturing) + { + IsCapturing = isCapturing; + } + } + + /// + /// 错误事件参数 + /// + public class ErrorEventArgs : EventArgs + { + /// + /// 错误消息 + /// + public string ErrorMessage { get; set; } + + /// + /// 构造函数 + /// + public ErrorEventArgs(string errorMessage) + { + ErrorMessage = errorMessage; + } + } +} \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/UI/RegionEditorForm.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/UI/RegionEditorForm.cs index fac6c4e..b6853d4 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/UI/RegionEditorForm.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/UI/RegionEditorForm.cs @@ -12,7 +12,7 @@ namespace XCamera.UI /// /// 区域编辑器窗体 /// - public partial class RegionEditorForm : Form + public class RegionEditorForm : Form { private ConfigurationManager _configManager; private ImageProcessor _imageProcessor; @@ -22,6 +22,16 @@ namespace XCamera.UI private Point _startPoint; private Rectangle _currentRect; + // 控件引用 + private PictureBox pictureBox; + private SplitContainer splitContainer; + private ListBox regionsListBox; + private TextBox idTextBox; + private TextBox nameTextBox; + private ComboBox colorComboBox; + private NumericUpDown brightnessNumeric; + private NumericUpDown toleranceNumeric; + /// /// 构造函数 /// @@ -30,23 +40,21 @@ namespace XCamera.UI _configManager = configManager ?? throw new ArgumentNullException(nameof(configManager)); _imageProcessor = imageProcessor ?? throw new ArgumentNullException(nameof(imageProcessor)); - InitializeComponent(); - InitializeCustomComponents(); - + InitializeComponents(); LoadRegions(); } /// /// 初始化自定义组件 /// - private void InitializeCustomComponents() + private void InitializeComponents() { this.Text = "LED区域编辑器"; this.Size = new Size(800, 600); this.StartPosition = FormStartPosition.CenterScreen; // 创建主分割容器 - var splitContainer = new SplitContainer + splitContainer = new SplitContainer { Dock = DockStyle.Fill, Orientation = Orientation.Vertical, @@ -68,7 +76,7 @@ namespace XCamera.UI }; // 创建图像显示控件 - var pictureBox = new PictureBox + pictureBox = new PictureBox { Dock = DockStyle.Fill, SizeMode = PictureBoxSizeMode.Zoom, @@ -90,10 +98,6 @@ namespace XCamera.UI splitContainer.Panel2.Controls.Add(rightPanel); this.Controls.Add(splitContainer); - - // 保存控件引用 - this.pictureBox = pictureBox; - this.splitContainer = splitContainer; } /// @@ -132,7 +136,7 @@ namespace XCamera.UI Dock = DockStyle.Fill }; - var regionsListBox = new ListBox + regionsListBox = new ListBox { Dock = DockStyle.Fill, SelectionMode = SelectionMode.One @@ -187,28 +191,28 @@ namespace XCamera.UI // ID propertiesPanel.Controls.Add(new Label { Text = "ID:", TextAlign = ContentAlignment.MiddleRight }, 0, 0); - var idTextBox = new TextBox { Dock = DockStyle.Fill }; + idTextBox = new TextBox { Dock = DockStyle.Fill }; propertiesPanel.Controls.Add(idTextBox, 1, 0); // 名称 propertiesPanel.Controls.Add(new Label { Text = "名称:", TextAlign = ContentAlignment.MiddleRight }, 0, 1); - var nameTextBox = new TextBox { Dock = DockStyle.Fill }; + nameTextBox = new TextBox { Dock = DockStyle.Fill }; propertiesPanel.Controls.Add(nameTextBox, 1, 1); // 期望颜色 propertiesPanel.Controls.Add(new Label { Text = "颜色:", TextAlign = ContentAlignment.MiddleRight }, 0, 2); - var colorComboBox = new ComboBox { Dock = DockStyle.Fill, DropDownStyle = ComboBoxStyle.DropDownList }; + colorComboBox = new ComboBox { Dock = DockStyle.Fill, DropDownStyle = ComboBoxStyle.DropDownList }; colorComboBox.Items.AddRange(new object[] { LedColor.Red, LedColor.Yellow, LedColor.Blue, LedColor.Green }); propertiesPanel.Controls.Add(colorComboBox, 1, 2); // 亮度阈值 propertiesPanel.Controls.Add(new Label { Text = "亮度:", TextAlign = ContentAlignment.MiddleRight }, 0, 3); - var brightnessNumeric = new NumericUpDown { Dock = DockStyle.Fill, Minimum = 0, Maximum = 255, Value = 100 }; + brightnessNumeric = new NumericUpDown { Dock = DockStyle.Fill, Minimum = 0, Maximum = 255, Value = 100 }; propertiesPanel.Controls.Add(brightnessNumeric, 1, 3); // 颜色容差 propertiesPanel.Controls.Add(new Label { Text = "容差:", TextAlign = ContentAlignment.MiddleRight }, 0, 4); - var toleranceNumeric = new NumericUpDown { Dock = DockStyle.Fill, Minimum = 0, Maximum = 255, Value = 30 }; + toleranceNumeric = new NumericUpDown { Dock = DockStyle.Fill, Minimum = 0, Maximum = 255, Value = 30 }; propertiesPanel.Controls.Add(toleranceNumeric, 1, 4); propertiesGroup.Controls.Add(propertiesPanel); @@ -221,14 +225,6 @@ namespace XCamera.UI brightnessNumeric.ValueChanged += (s, e) => UpdateSelectedRegion(); toleranceNumeric.ValueChanged += (s, e) => UpdateSelectedRegion(); - // 保存控件引用 - this.regionsListBox = regionsListBox; - this.idTextBox = idTextBox; - this.nameTextBox = nameTextBox; - this.colorComboBox = colorComboBox; - this.brightnessNumeric = brightnessNumeric; - this.toleranceNumeric = toleranceNumeric; - // 操作按钮 var actionButtonsPanel = new FlowLayoutPanel { @@ -552,15 +548,5 @@ namespace XCamera.UI } } } - - // 控件引用 - private PictureBox pictureBox; - private SplitContainer splitContainer; - private ListBox regionsListBox; - private TextBox idTextBox; - private TextBox nameTextBox; - private ComboBox colorComboBox; - private NumericUpDown brightnessNumeric; - private NumericUpDown toleranceNumeric; } } \ No newline at end of file diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/ImageProcessor.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/ImageProcessor.cs index 0a60855..cd35a23 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/ImageProcessor.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/ImageProcessor.cs @@ -4,6 +4,23 @@ using System.Drawing.Imaging; namespace XCamera.Vision { + /// + /// HSV颜色结构 + /// + public struct HsvColor + { + public double H; // 色相 (0-360) + public double S; // 饱和度 (0-1) + public double V; // 明度 (0-1) + + public HsvColor(double h, double s, double v) + { + H = h; + S = s; + V = v; + } + } + /// /// 图像处理器,提供图像处理相关功能 /// @@ -184,43 +201,18 @@ namespace XCamera.Vision long redSum = 0, greenSum = 0, blueSum = 0; long pixelCount = 0; - // 使用锁定位图数据以提高性能 - var rect = new System.Drawing.Rectangle(0, 0, targetImage.Width, targetImage.Height); - var bitmapData = targetImage.LockBits(rect, ImageLockMode.ReadOnly, targetImage.PixelFormat); - - try + // 使用GetPixel方法(安全但较慢) + for (int y = 0; y < targetImage.Height; y++) { - int bytesPerPixel = Image.GetPixelFormatSize(targetImage.PixelFormat) / 8; - int height = bitmapData.Height; - int width = bitmapData.Width; - int stride = bitmapData.Stride; - IntPtr scan0 = bitmapData.Scan0; - - unsafe + for (int x = 0; x < targetImage.Width; x++) { - byte* p = (byte*)scan0.ToPointer(); - - for (int y = 0; y < height; y++) - { - byte* row = p + y * stride; - - for (int x = 0; x < width; x++) - { - int offset = x * bytesPerPixel; - - // 假设是32位ARGB格式 - blueSum += row[offset]; - greenSum += row[offset + 1]; - redSum += row[offset + 2]; - pixelCount++; - } - } + Color pixelColor = targetImage.GetPixel(x, y); + redSum += pixelColor.R; + greenSum += pixelColor.G; + blueSum += pixelColor.B; + pixelCount++; } } - finally - { - targetImage.UnlockBits(bitmapData); - } if (pixelCount == 0) { @@ -259,7 +251,7 @@ namespace XCamera.Vision /// /// RGB颜色 /// HSV值(H: 0-360, S: 0-1, V: 0-1) - public static (double H, double S, double V) RgbToHsv(Color color) + public static HsvColor RgbToHsv(Color color) { double r = color.R / 255.0; double g = color.G / 255.0; @@ -285,7 +277,7 @@ namespace XCamera.Vision h *= 60; } - return (h, s, v); + return new HsvColor(h, s, v); } /// diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/LedDetector.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/LedDetector.cs index af0779d..d8a6a7a 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/LedDetector.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/Vision/LedDetector.cs @@ -73,7 +73,7 @@ namespace XCamera.Vision var status = DetectLedState(region); results.Add(status); } - catch (Exception ex) + catch { // 单个区域检测失败不影响其他区域 var errorStatus = new LedStatus(region.Id, region.Name) diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs index 9e86aa7..9af7e5c 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCamera.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; +using XCamera.Models; namespace XCamera { @@ -35,7 +36,7 @@ namespace XCamera /// /// LED状态更新事件 /// - public static event EventHandler> LedStatusUpdated + public static event EventHandler LedStatusUpdated { add { Manager.LedStatusUpdated += value; } remove { Manager.LedStatusUpdated -= value; } @@ -44,7 +45,7 @@ namespace XCamera /// /// 连接状态变更事件 /// - public static event EventHandler ConnectionStateChanged + public static event EventHandler ConnectionStateChanged { add { Manager.ConnectionStateChanged += value; } remove { Manager.ConnectionStateChanged -= value; } @@ -53,7 +54,7 @@ namespace XCamera /// /// 捕获状态变更事件 /// - public static event EventHandler CaptureStateChanged + public static event EventHandler CaptureStateChanged { add { Manager.CaptureStateChanged += value; } remove { Manager.CaptureStateChanged -= value; } @@ -62,7 +63,7 @@ namespace XCamera /// /// 错误事件 /// - public static event EventHandler ErrorOccurred + public static event EventHandler ErrorOccurred { add { Manager.ErrorOccurred += value; } remove { Manager.ErrorOccurred -= value; } @@ -135,7 +136,7 @@ namespace XCamera /// 5. 识别配置文件内的每个区域中(这些区域是led灯),led灯的颜色(红,黄,蓝,绿),亮灭,是否闪烁 /// /// LED状态列表 - public static List DetectLeds() + public static List DetectLeds() { return Manager.DetectLeds(); } @@ -144,7 +145,7 @@ namespace XCamera /// 6. 提供函数查询灯的状态 /// /// LED状态列表 - public static List GetLedStatuses() + public static List GetLedStatuses() { return Manager.GetLedStatuses(); } @@ -154,7 +155,7 @@ namespace XCamera /// /// 区域ID /// LED状态 - public static Models.LedStatus GetLedStatus(string regionId) + public static LedStatus GetLedStatus(string regionId) { return Manager.GetLedStatus(regionId); } @@ -211,7 +212,7 @@ namespace XCamera /// /// LED区域 /// 是否成功添加 - public static bool AddLedRegion(Models.LedRegion region) + public static bool AddLedRegion(LedRegion region) { return Manager.AddLedRegion(region); } @@ -239,7 +240,7 @@ namespace XCamera /// /// 获取当前配置 /// - public static Models.CameraConfig GetCurrentConfig() + public static CameraConfig GetCurrentConfig() { return Manager.CurrentConfig; } diff --git a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs index a10b196..a06b77e 100644 --- a/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs +++ b/Windows/CS/Framework4.0/XCamera/XCamera/src/XCameraManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; using XCamera.Models; using XCamera.Core; @@ -18,31 +17,32 @@ namespace XCamera private CameraConnectionManager _connectionManager; private ImageProcessor _imageProcessor; private LedDetector _ledDetector; - private CancellationTokenSource _captureCancellation; - private Task _captureTask; + private Thread _captureThread; private bool _isInitialized = false; private bool _isCapturing = false; + private bool _shouldStopCapture = false; private readonly object _lockObject = new object(); + private int _captureInterval = 1000; /// /// LED状态更新事件 /// - public event EventHandler> LedStatusUpdated; + public event EventHandler LedStatusUpdated; /// /// 连接状态变更事件 /// - public event EventHandler ConnectionStateChanged; + public event EventHandler ConnectionStateChanged; /// /// 捕获状态变更事件 /// - public event EventHandler CaptureStateChanged; + public event EventHandler CaptureStateChanged; /// /// 错误事件 /// - public event EventHandler ErrorOccurred; + public event EventHandler ErrorOccurred; /// /// 是否已初始化 @@ -234,11 +234,18 @@ namespace XCamera { lock (_lockObject) { - _captureCancellation = new CancellationTokenSource(); + _captureInterval = intervalMs; + _shouldStopCapture = false; _isCapturing = true; } - _captureTask = Task.Run(() => CaptureLoop(intervalMs, _captureCancellation.Token)); + // 创建捕获线程 + _captureThread = new Thread(CaptureLoop) + { + IsBackground = true, + Name = "XCameraCaptureThread" + }; + _captureThread.Start(); OnCaptureStateChanged(true); return true; @@ -248,8 +255,7 @@ namespace XCamera lock (_lockObject) { _isCapturing = false; - _captureCancellation?.Dispose(); - _captureCancellation = null; + _shouldStopCapture = false; } OnErrorOccurred($"开始捕获失败: {ex.Message}"); @@ -368,16 +374,25 @@ namespace XCamera { lock (_lockObject) { - _captureCancellation?.Cancel(); - _isCapturing = false; + _shouldStopCapture = true; } - _captureTask?.Wait(5000); // 等待最多5秒 - _captureTask?.Dispose(); + // 等待线程结束(最多5秒) + if (_captureThread != null && _captureThread.IsAlive) + { + if (!_captureThread.Join(5000)) + { + _captureThread.Abort(); // 强制终止 + } + } - _captureCancellation?.Dispose(); - _captureCancellation = null; - _captureTask = null; + lock (_lockObject) + { + _isCapturing = false; + _shouldStopCapture = false; + } + + _captureThread = null; OnCaptureStateChanged(false); } @@ -502,33 +517,40 @@ namespace XCamera _ledDetector = new LedDetector(_imageProcessor); // 订阅事件 - _connectionManager.ConnectionStateChanged += (s, e) => OnConnectionStateChanged(e); + _connectionManager.ConnectionStateChanged += (s, e) => OnConnectionStateChanged(IsConnected); } /// /// 捕获循环 /// - /// 间隔时间 - /// 取消令牌 - private async Task CaptureLoop(int intervalMs, CancellationToken cancellationToken) + private void CaptureLoop() { - while (!cancellationToken.IsCancellationRequested) + while (!_shouldStopCapture) { try { var ledStatuses = DetectLeds(); OnLedStatusUpdated(ledStatuses); - await Task.Delay(intervalMs, cancellationToken); - } - catch (OperationCanceledException) - { - break; + // 等待指定间隔 + int waited = 0; + while (waited < _captureInterval && !_shouldStopCapture) + { + Thread.Sleep(100); + waited += 100; + } } catch (Exception ex) { OnErrorOccurred($"捕获循环错误: {ex.Message}"); - await Task.Delay(1000, cancellationToken); // 出错后等待1秒 + + // 出错后等待1秒 + int waited = 0; + while (waited < 1000 && !_shouldStopCapture) + { + Thread.Sleep(100); + waited += 100; + } } } } @@ -595,7 +617,7 @@ namespace XCamera /// private void OnLedStatusUpdated(List statuses) { - LedStatusUpdated?.Invoke(this, statuses); + LedStatusUpdated?.Invoke(this, new LedStatusEventArgs(statuses)); } /// @@ -603,7 +625,7 @@ namespace XCamera /// private void OnConnectionStateChanged(bool connected) { - ConnectionStateChanged?.Invoke(this, connected); + ConnectionStateChanged?.Invoke(this, new ConnectionStateEventArgs(connected)); } /// @@ -611,7 +633,7 @@ namespace XCamera /// private void OnCaptureStateChanged(bool capturing) { - CaptureStateChanged?.Invoke(this, capturing); + CaptureStateChanged?.Invoke(this, new CaptureStateEventArgs(capturing)); } /// @@ -619,7 +641,7 @@ namespace XCamera /// private void OnErrorOccurred(string error) { - ErrorOccurred?.Invoke(this, error); + ErrorOccurred?.Invoke(this, new ErrorEventArgs(error)); } /// @@ -633,8 +655,6 @@ namespace XCamera _connectionManager = null; _imageProcessor = null; _ledDetector = null; - _captureCancellation = null; - _captureTask = null; } } } \ No newline at end of file