2026-03-16 17:05:54 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.Data;
|
|
|
|
|
|
using System.Drawing;
|
2026-03-17 14:28:07 +08:00
|
|
|
|
using System.IO;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2026-03-17 09:21:09 +08:00
|
|
|
|
using System.Threading;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
using System.Windows.Forms;
|
2026-03-17 14:28:07 +08:00
|
|
|
|
using ErrorEventArgs = XCamera.Models.ErrorEventArgs;
|
|
|
|
|
|
using InfoEventArgs = XCamera.Models.InfoEventArgs;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
using XCamera.Models;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Test
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class Form1 : Form
|
|
|
|
|
|
{
|
|
|
|
|
|
private bool _isInitialized = false;
|
|
|
|
|
|
private bool _isConnected = false;
|
|
|
|
|
|
private bool _isCapturing = false;
|
2026-03-17 14:28:07 +08:00
|
|
|
|
private string _cameraIpAddress = "192.168.100.10"; // 默认IP地址
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
|
|
|
|
|
public Form1()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
2026-03-17 09:21:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查是否处于设计模式
|
|
|
|
|
|
if (!DesignMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-16 17:05:54 +08:00
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void InitializeEvents()
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
// 避免在设计模式下订阅事件
|
|
|
|
|
|
if (DesignMode)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2026-03-16 17:05:54 +08:00
|
|
|
|
// 订阅XCamera事件
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.LedStatusUpdated += OnLedStatusUpdated;
|
|
|
|
|
|
global::XCamera.XCamera.ConnectionStateChanged += OnConnectionStateChanged;
|
|
|
|
|
|
global::XCamera.XCamera.CaptureStateChanged += OnCaptureStateChanged;
|
|
|
|
|
|
global::XCamera.XCamera.ErrorOccurred += OnErrorOccurred;
|
2026-03-17 14:28:07 +08:00
|
|
|
|
global::XCamera.XCamera.InfoOccurred += OnInfoOccurred;
|
|
|
|
|
|
global::XCamera.XCamera.ImageCaptured += OnImageCaptured;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 1. 初始化
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnInitialize_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("正在初始化SDK...");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 初始化SDK(不加载配置文件)
|
|
|
|
|
|
if (global::XCamera.XCamera.Initialize())
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
_isInitialized = true;
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("SDK初始化成功!");
|
|
|
|
|
|
LogMessage("现在可以设置配置文件或启动摄像头");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("SDK初始化失败!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"初始化错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 2. 设置配置文件路径
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnSetConfigFile_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 设置默认路径为程序目录下的config文件夹
|
|
|
|
|
|
string defaultConfigPath = Path.Combine(Application.StartupPath, "config");
|
|
|
|
|
|
if (Directory.Exists(defaultConfigPath))
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
folderDialog.SelectedPath = defaultConfigPath;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
folderDialog.SelectedPath = Application.StartupPath;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
folderDialog.Description = "选择配置目录";
|
|
|
|
|
|
folderDialog.ShowNewFolderButton = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (folderDialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"正在设置配置目录: {folderDialog.SelectedPath}");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
if (global::XCamera.XCamera.SetConfigPath(folderDialog.SelectedPath))
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("配置目录设置成功!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示配置信息
|
2026-03-17 09:21:09 +08:00
|
|
|
|
var config = global::XCamera.XCamera.GetCurrentConfig();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
if (config != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"LED区域数: {config.LedRegions.Count}");
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage($"TCP端口: {config.TcpPort}");
|
|
|
|
|
|
LogMessage($"用户名: {config.Username}");
|
|
|
|
|
|
LogMessage($"通道: {config.Channel}");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("配置目录设置失败!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage($"配置目录设置错误: {ex.Message}");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 3. 设置IP地址
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnSetIP_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("请先初始化!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string ipAddress = txtIpAddress.Text.Trim();
|
|
|
|
|
|
if (string.IsNullOrEmpty(ipAddress))
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("IP地址不能为空!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (global::XCamera.XCamera.SetIP(ipAddress))
|
|
|
|
|
|
{
|
|
|
|
|
|
_cameraIpAddress = ipAddress;
|
|
|
|
|
|
LogMessage($"IP地址设置成功: {ipAddress}");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"IP地址设置失败: {ipAddress}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"设置IP地址错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 5. 启动摄像头
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnStartCamera_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("请先初始化!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在启动摄像头...");
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
if (global::XCamera.XCamera.StartCamera())
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
LogMessage("摄像头启动成功!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("摄像头启动失败!");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"启动摄像头错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 6. 开始捕获图像
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnStartCapture_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("请先连接摄像头!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_isCapturing)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("已经在捕获中!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在开始捕获图像...");
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
if (global::XCamera.XCamera.StartCapture(1000)) // 1秒间隔
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
LogMessage("开始捕获图像成功!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("开始捕获图像失败!");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"开始捕获错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 7. LED灯识别
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnDetectLeds_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("请先连接摄像头!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在识别LED灯...");
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
var statuses = global::XCamera.XCamera.DetectLeds();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
LogMessage($"检测到 {statuses.Count} 个LED灯:");
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var status in statuses)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($" {status.GetStatusDescription()}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示图像(如果有的话)
|
|
|
|
|
|
DisplayLedImage(statuses);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"LED识别错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 8. 状态查询
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnGetLedStatuses_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("请先连接摄像头!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在查询LED状态...");
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
var statuses = global::XCamera.XCamera.GetLedStatuses();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
LogMessage($"当前LED状态 ({statuses.Count} 个):");
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var status in statuses)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($" {status.GetStatusDescription()}");
|
|
|
|
|
|
}
|
2026-03-17 14:28:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示图像
|
|
|
|
|
|
DisplayLedImage(statuses);
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"状态查询错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 9. 区域编辑器
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnShowRegionEditor_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("正在打开区域编辑器...");
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.ShowRegionEditor();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
LogMessage("区域编辑器已关闭");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"区域编辑器错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 9. 关闭
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnShutdown_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("正在关闭...");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 停止捕获
|
2026-03-16 17:05:54 +08:00
|
|
|
|
if (_isCapturing)
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCapture();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("捕获已停止");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 停止摄像头
|
2026-03-16 17:05:54 +08:00
|
|
|
|
if (_isConnected)
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCamera();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("摄像头已停止");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 关闭SDK
|
|
|
|
|
|
if (_isInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
global::XCamera.XCamera.Shutdown();
|
|
|
|
|
|
LogMessage("SDK已关闭");
|
|
|
|
|
|
}
|
2026-03-16 17:05:54 +08:00
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("关闭完成!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage($"关闭错误: {ex.Message}");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 重置状态
|
|
|
|
|
|
_isInitialized = false;
|
|
|
|
|
|
_isConnected = false;
|
|
|
|
|
|
_isCapturing = false;
|
|
|
|
|
|
|
2026-03-16 17:05:54 +08:00
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 停止捕获
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnStopCapture_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isCapturing)
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("当前未在捕获状态!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在停止捕获...");
|
2026-03-17 14:28:07 +08:00
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCapture();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("停止捕获成功!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"停止捕获错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 停止摄像头
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void btnStopCamera_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isConnected)
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("当前未连接摄像头!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage("正在停止摄像头...");
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCamera();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage("停止摄像头成功!");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"停止摄像头错误: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// LED状态更新事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void OnLedStatusUpdated(object sender, LedStatusEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<object, LedStatusEventArgs>(OnLedStatusUpdated), sender, e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 更新状态
|
|
|
|
|
|
_isConnected = global::XCamera.XCamera.IsConnected;
|
|
|
|
|
|
_isCapturing = global::XCamera.XCamera.IsCapturing;
|
|
|
|
|
|
|
|
|
|
|
|
UpdateUI();
|
|
|
|
|
|
|
|
|
|
|
|
// 显示LED状态
|
|
|
|
|
|
if (e.Statuses.Count > 0)
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage($"LED状态更新 ({e.Statuses.Count} 个):");
|
|
|
|
|
|
foreach (var status in e.Statuses)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($" {status.GetStatusDescription()}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示图像
|
|
|
|
|
|
DisplayLedImage(e.Statuses);
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 连接状态变更事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void OnConnectionStateChanged(object sender, ConnectionStateEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<object, ConnectionStateEventArgs>(OnConnectionStateChanged), sender, e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_isConnected = e.IsConnected;
|
|
|
|
|
|
UpdateUI();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
|
|
|
|
|
|
if (e.IsConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("摄像头已连接");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("摄像头已断开");
|
|
|
|
|
|
}
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 捕获状态变更事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void OnCaptureStateChanged(object sender, CaptureStateEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<object, CaptureStateEventArgs>(OnCaptureStateChanged), sender, e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_isCapturing = e.IsCapturing;
|
|
|
|
|
|
UpdateUI();
|
2026-03-17 14:28:07 +08:00
|
|
|
|
|
|
|
|
|
|
if (e.IsCapturing)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("开始捕获图像");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage("停止捕获图像");
|
|
|
|
|
|
}
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 错误事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void OnErrorOccurred(object sender, ErrorEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<object, ErrorEventArgs>(OnErrorOccurred), sender, e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] 错误: {e.ErrorMessage}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
/// 信息事件处理
|
2026-03-16 17:05:54 +08:00
|
|
|
|
/// </summary>
|
2026-03-17 14:28:07 +08:00
|
|
|
|
private void OnInfoOccurred(object sender, InfoEventArgs e)
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
BeginInvoke(new Action<object, InfoEventArgs>(OnInfoOccurred), sender, e);
|
2026-03-16 17:05:54 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 14:28:07 +08:00
|
|
|
|
LogMessage($"[{DateTime.Now:HH:mm:ss.fff}] {e.InfoMessage}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 图像捕获事件处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void OnImageCaptured(object sender, ImageCapturedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<object, ImageCapturedEventArgs>(OnImageCaptured), sender, e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 显示捕获的图像
|
|
|
|
|
|
if (e.Image != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清理之前的图像
|
|
|
|
|
|
if (LedImage.Image != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var oldImage = LedImage.Image;
|
|
|
|
|
|
LedImage.Image = null;
|
|
|
|
|
|
oldImage.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果LED状态为空,直接显示原图
|
|
|
|
|
|
if (e.LedStatuses == null || e.LedStatuses.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
LedImage.Image = (System.Drawing.Image)e.Image.Clone();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建带LED区域标注的图像
|
|
|
|
|
|
var annotatedImage = CreateAnnotatedImage(e.Image, e.LedStatuses);
|
|
|
|
|
|
LedImage.Image = annotatedImage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调整显示模式
|
|
|
|
|
|
LedImage.SizeMode = PictureBoxSizeMode.Zoom;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
LogMessage($"显示图像失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建带LED区域标注的图像
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private System.Drawing.Image CreateAnnotatedImage(System.Drawing.Image originalImage, List<LedStatus> ledStatuses)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建位图副本
|
|
|
|
|
|
var bitmap = new Bitmap(originalImage.Width, originalImage.Height);
|
|
|
|
|
|
using (var g = Graphics.FromImage(bitmap))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 绘制原始图像
|
|
|
|
|
|
g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制LED状态信息
|
|
|
|
|
|
for (int i = 0; i < ledStatuses.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var status = ledStatuses[i];
|
|
|
|
|
|
|
|
|
|
|
|
// 根据状态设置颜色
|
|
|
|
|
|
Color ledColor = GetLedColor(status);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算LED显示位置
|
|
|
|
|
|
int ledSize = 40;
|
|
|
|
|
|
int spacing = 60;
|
|
|
|
|
|
int startX = 20;
|
|
|
|
|
|
int startY = 20;
|
|
|
|
|
|
|
|
|
|
|
|
int x = startX + (i % 5) * spacing;
|
|
|
|
|
|
int y = startY + (i / 5) * spacing;
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制LED圆形
|
|
|
|
|
|
Rectangle ledRect = new Rectangle(x, y, ledSize, ledSize);
|
|
|
|
|
|
using (var ledBrush = new SolidBrush(ledColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
g.FillEllipse(ledBrush, ledRect);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制LED边框
|
|
|
|
|
|
using (var borderPen = new Pen(Color.Black, 2))
|
|
|
|
|
|
{
|
|
|
|
|
|
g.DrawEllipse(borderPen, ledRect);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制标签
|
|
|
|
|
|
using (var font = new Font("Arial", 8))
|
|
|
|
|
|
using (var textBrush = new SolidBrush(Color.White))
|
|
|
|
|
|
{
|
|
|
|
|
|
string label = status.RegionName;
|
|
|
|
|
|
g.DrawString(label, font, textBrush, x, y + ledSize + 2);
|
|
|
|
|
|
|
|
|
|
|
|
string stateText = status.State.ToString();
|
|
|
|
|
|
if (status.IsBlinking)
|
|
|
|
|
|
stateText = "Blinking";
|
|
|
|
|
|
g.DrawString(stateText, font, textBrush, x, y + ledSize + 15);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bitmap;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 显示LED图像
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void DisplayLedImage(List<LedStatus> 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取LED颜色
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新UI状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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 = "状态: 未初始化";
|
|
|
|
|
|
|
2026-03-17 09:21:09 +08:00
|
|
|
|
// ToolStripStatusLabel没有ForeColor属性,我们可以使用BackColor或者保持默认样式
|
|
|
|
|
|
// 如果需要颜色变化,可以考虑使用BackColor
|
|
|
|
|
|
// lblStatus.BackColor = _isConnected ? Color.LightGreen : Color.LightPink;
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 窗体关闭事件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-17 14:28:07 +08:00
|
|
|
|
// 确保在关闭时清理资源
|
2026-03-16 17:05:54 +08:00
|
|
|
|
if (_isCapturing)
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCapture();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_isConnected)
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.StopCamera();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_isInitialized)
|
|
|
|
|
|
{
|
2026-03-17 09:21:09 +08:00
|
|
|
|
global::XCamera.XCamera.Shutdown();
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-17 14:28:07 +08:00
|
|
|
|
catch (Exception ex)
|
2026-03-16 17:05:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 忽略关闭时的错误
|
2026-03-17 14:28:07 +08:00
|
|
|
|
System.Diagnostics.Debug.WriteLine($"关闭错误: {ex.Message}");
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-17 14:28:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 日志消息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void LogMessage(string message)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
BeginInvoke(new Action<string>(LogMessage), message);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] {message}" + Environment.NewLine);
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
}
|
2026-03-16 17:05:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|