实现温度数据处理功能:添加温度数据模型类、温度接收功能和相关集成
This commit is contained in:
@@ -205,6 +205,7 @@ namespace JoyD.Windows.CS.Toprie
|
||||
if (_isReceivingImage)
|
||||
{
|
||||
_deviceManager.StopImageReceiving();
|
||||
_deviceManager.StopTemperatureDataReceiving();
|
||||
_isReceivingImage = false;
|
||||
}
|
||||
}
|
||||
@@ -224,7 +225,9 @@ namespace JoyD.Windows.CS.Toprie
|
||||
if (_deviceManager.ConnectionStatus == ConnectionStatus.Connected)
|
||||
{
|
||||
_deviceManager.StopImageReceiving();
|
||||
_deviceManager.StopTemperatureDataReceiving();
|
||||
_deviceManager.StartImageReceiving();
|
||||
_deviceManager.StartTemperatureDataReceiving();
|
||||
_isReceivingImage = true;
|
||||
|
||||
// 恢复检测后,启动连接检查以确保连接正常
|
||||
@@ -503,6 +506,7 @@ namespace JoyD.Windows.CS.Toprie
|
||||
Console.WriteLine("Camera开始使用HTTP方式接收图像");
|
||||
// 直接调用HTTP方式的图像接收
|
||||
_deviceManager.StartImageReceiving();
|
||||
_deviceManager.StartTemperatureDataReceiving();
|
||||
_isReceivingImage = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,25 @@ namespace JoyD.Windows.CS.Toprie
|
||||
Fusion5 // 融合5,对应SDK参数6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 温度模式枚举
|
||||
/// </summary>
|
||||
public enum TemperatureMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 摄氏度
|
||||
/// </summary>
|
||||
Celsius,
|
||||
/// <summary>
|
||||
/// 华氏度
|
||||
/// </summary>
|
||||
Fahrenheit,
|
||||
/// <summary>
|
||||
/// 开尔文
|
||||
/// </summary>
|
||||
Kelvin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接状态改变事件参数
|
||||
/// </summary>
|
||||
@@ -242,6 +261,14 @@ namespace JoyD.Windows.CS.Toprie
|
||||
private Thread _imageReconnectThread;
|
||||
private Stream _imageStream;
|
||||
|
||||
// 温度数据接收相关字段
|
||||
private Thread _temperatureReceiveThread;
|
||||
private TcpClient _temperatureTcpClient;
|
||||
private NetworkStream _temperatureStream;
|
||||
private bool _isReceivingTemperatureData = false;
|
||||
private ManualResetEvent _stopTemperatureEvent;
|
||||
private const int TEMPERATURE_TCP_PORT = 7682; // 温度数据TCP端口
|
||||
|
||||
/// <summary>
|
||||
/// 项目路径属性
|
||||
/// 用于设置控件存取数据文件的目录
|
||||
@@ -611,6 +638,10 @@ namespace JoyD.Windows.CS.Toprie
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 连接成功,启动图像接收");
|
||||
StartImageReceiving();
|
||||
|
||||
// 启动温度数据接收
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 启动温度数据接收");
|
||||
StartTemperatureDataReceiving();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -645,6 +676,8 @@ namespace JoyD.Windows.CS.Toprie
|
||||
StopAutoReconnect();
|
||||
StopHeartbeat();
|
||||
StopConnectionCheck();
|
||||
// 停止温度数据接收
|
||||
StopTemperatureDataReceiving();
|
||||
|
||||
// 安全释放SDK实例
|
||||
A8SDK oldSdk = Interlocked.Exchange(ref _a8Sdk, null);
|
||||
@@ -802,6 +835,377 @@ namespace JoyD.Windows.CS.Toprie
|
||||
|
||||
#endregion 私有方法
|
||||
|
||||
#region 温度数据处理方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取温度补偿值
|
||||
/// </summary>
|
||||
/// <returns>温度补偿值</returns>
|
||||
private float GetTemperatureCompensationValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_connectionStatus == ConnectionStatus.Connected && _a8Sdk != null)
|
||||
{
|
||||
float compensationValue = _a8Sdk.Comp_temp;
|
||||
Log($"获取温度补偿值: {compensationValue}");
|
||||
return compensationValue;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"获取温度补偿值异常: {ex.Message}");
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始接收温度数据
|
||||
/// </summary>
|
||||
public void StartTemperatureDataReceiving()
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 开始执行");
|
||||
|
||||
// 在设计模式下,跳过实际的温度数据接收
|
||||
if (IsDesignMode)
|
||||
{
|
||||
Log("设计模式下跳过实际的温度数据接收");
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
// 检查对象是否已被释放
|
||||
if (_isDisposed)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 对象已释放,忽略操作");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查连接状态
|
||||
if (_connectionStatus != ConnectionStatus.Connected)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 连接未建立,无法开始温度数据接收");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log("开始使用TCP方式接收温度数据");
|
||||
try
|
||||
{
|
||||
// 确保之前的连接已关闭
|
||||
StopTemperatureDataReceiving();
|
||||
|
||||
// 重置停止事件
|
||||
_stopTemperatureEvent = new ManualResetEvent(false);
|
||||
lock (_lockObject)
|
||||
{
|
||||
_isReceivingTemperatureData = true;
|
||||
}
|
||||
|
||||
// 创建并启动温度数据接收线程
|
||||
_temperatureReceiveThread = new Thread(ReceiveTemperatureDataWithTcp)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "TemperatureReceiveThread"
|
||||
};
|
||||
_temperatureReceiveThread.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 异常: {ex.Message}");
|
||||
lock (_lockObject)
|
||||
{
|
||||
_isReceivingTemperatureData = false;
|
||||
}
|
||||
|
||||
// 如果连接状态异常,触发异常事件
|
||||
OnConnectionException(new ConnectionExceptionEventArgs(ex, "启动温度数据接收失败"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 确保方法执行完成时记录日志
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 执行完成");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止接收温度数据
|
||||
/// </summary>
|
||||
public void StopTemperatureDataReceiving()
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 开始执行");
|
||||
|
||||
if (_isDisposed)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 对象已释放,跳过操作");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 线程安全地更新状态
|
||||
lock (_lockObject)
|
||||
{
|
||||
_isReceivingTemperatureData = false;
|
||||
}
|
||||
|
||||
// 通知线程停止
|
||||
ManualResetEvent stopEvent = null;
|
||||
lock (_lockObject)
|
||||
{
|
||||
stopEvent = _stopTemperatureEvent;
|
||||
}
|
||||
|
||||
if (stopEvent != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
stopEvent.Set();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// 忽略已释放的事件
|
||||
}
|
||||
}
|
||||
|
||||
// 等待线程结束
|
||||
Thread temperatureThread = null;
|
||||
lock (_lockObject)
|
||||
{
|
||||
temperatureThread = _temperatureReceiveThread;
|
||||
}
|
||||
|
||||
if (temperatureThread != null && temperatureThread.IsAlive)
|
||||
{
|
||||
temperatureThread.Join(1000); // 等待最多1秒
|
||||
Log("温度接收线程已停止");
|
||||
}
|
||||
|
||||
// 关闭TCP客户端和流
|
||||
NetworkStream stream = null;
|
||||
TcpClient client = null;
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
stream = _temperatureStream;
|
||||
client = _temperatureTcpClient;
|
||||
_temperatureStream = null;
|
||||
_temperatureTcpClient = null;
|
||||
}
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{}
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 异常: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 执行完成");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用TCP接收温度数据
|
||||
/// </summary>
|
||||
private void ReceiveTemperatureDataWithTcp()
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 开始执行");
|
||||
|
||||
try
|
||||
{
|
||||
// 创建TCP客户端并连接到设备的温度数据端口
|
||||
_temperatureTcpClient = new TcpClient();
|
||||
_temperatureTcpClient.ReceiveTimeout = 5000;
|
||||
_temperatureTcpClient.SendTimeout = 5000;
|
||||
|
||||
IAsyncResult result = _temperatureTcpClient.BeginConnect(_deviceIp, TEMPERATURE_TCP_PORT, null, null);
|
||||
bool connected = result.AsyncWaitHandle.WaitOne(3000, true);
|
||||
|
||||
if (!connected || !_temperatureTcpClient.Connected)
|
||||
{
|
||||
Log("温度数据TCP连接失败,超时");
|
||||
return;
|
||||
}
|
||||
|
||||
_temperatureTcpClient.EndConnect(result);
|
||||
Log("温度数据TCP连接成功");
|
||||
|
||||
// 获取网络流
|
||||
_temperatureStream = _temperatureTcpClient.GetStream();
|
||||
_temperatureStream.ReadTimeout = 5000;
|
||||
|
||||
byte[] buffer = new byte[8192]; // 温度数据缓冲区
|
||||
List<byte> temperatureDataAccumulator = new List<byte>();
|
||||
|
||||
// 发送开始温度数据传输的命令
|
||||
byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n");
|
||||
_temperatureStream.Write(startCommand, 0, startCommand.Length);
|
||||
_temperatureStream.Flush();
|
||||
|
||||
Log("已发送开始温度数据传输命令,开始接收温度数据");
|
||||
|
||||
while (!_stopTemperatureEvent.WaitOne(0))
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查连接状态
|
||||
if (!_temperatureTcpClient.Connected)
|
||||
{
|
||||
Log("温度数据TCP连接已断开");
|
||||
break;
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
int bytesRead = _temperatureStream.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
// 将读取的数据添加到累积器
|
||||
byte[] receivedBytes = new byte[bytesRead];
|
||||
Array.Copy(buffer, receivedBytes, bytesRead);
|
||||
temperatureDataAccumulator.AddRange(receivedBytes);
|
||||
|
||||
// 处理累积的数据
|
||||
ProcessReceivedTemperatureData(temperatureDataAccumulator);
|
||||
}
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// 超时异常,继续尝试读取
|
||||
Log("温度数据接收超时,继续尝试");
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Log($"温度数据接收IO异常: {ex.Message}");
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"温度数据接收异常: {ex.Message}");
|
||||
// 非致命异常,继续尝试
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 严重异常: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 执行完成");
|
||||
|
||||
// 确保状态正确更新
|
||||
lock (_lockObject)
|
||||
{
|
||||
_isReceivingTemperatureData = false;
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
StopTemperatureDataReceiving();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理接收到的温度数据
|
||||
/// </summary>
|
||||
/// <param name="dataAccumulator">累积的温度数据</param>
|
||||
private void ProcessReceivedTemperatureData(List<byte> dataAccumulator)
|
||||
{
|
||||
const int TEMPERATURE_DATA_FRAME_SIZE = 256 * 192 * 2; // 假设分辨率为256x192,每个温度值2字节
|
||||
|
||||
try
|
||||
{
|
||||
// 检查是否有足够的数据构成完整的温度数据帧
|
||||
while (dataAccumulator.Count >= TEMPERATURE_DATA_FRAME_SIZE)
|
||||
{
|
||||
// 提取一帧温度数据
|
||||
byte[] temperatureFrame = dataAccumulator.GetRange(0, TEMPERATURE_DATA_FRAME_SIZE).ToArray();
|
||||
dataAccumulator.RemoveRange(0, TEMPERATURE_DATA_FRAME_SIZE);
|
||||
|
||||
// 获取温度补偿值
|
||||
float compensationValue = GetTemperatureCompensationValue();
|
||||
|
||||
// 创建温度数据对象
|
||||
TemperatureData temperatureData = new TemperatureData(temperatureFrame, compensationValue);
|
||||
|
||||
// 触发温度数据接收事件
|
||||
OnTemperatureReceived(new TemperatureReceivedEventArgs(temperatureData, temperatureFrame, compensationValue));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ProcessReceivedTemperatureData() - 异常: {ex.Message}");
|
||||
// 清空累积器,重新开始
|
||||
dataAccumulator.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发温度数据接收事件
|
||||
/// </summary>
|
||||
/// <param name="e">事件参数</param>
|
||||
protected virtual void OnTemperatureReceived(TemperatureReceivedEventArgs e)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 开始执行");
|
||||
|
||||
// 检查参数有效性
|
||||
if (e == null)
|
||||
{
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 参数为空,跳过事件触发");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取事件处理程序的快照,避免在多线程环境中出现竞态条件
|
||||
EventHandler<TemperatureReceivedEventArgs> handler = TemperatureReceived;
|
||||
|
||||
// 检查是否有订阅者
|
||||
if (handler != null)
|
||||
{
|
||||
// 获取所有订阅的委托,单独处理每个处理器
|
||||
Delegate[] invocationList = handler.GetInvocationList();
|
||||
|
||||
foreach (Delegate d in invocationList)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 安全地转换并调用每个处理器
|
||||
EventHandler<TemperatureReceivedEventArgs> invoker = (EventHandler<TemperatureReceivedEventArgs>)d;
|
||||
invoker(this, e);
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 成功触发一个事件处理器: {d.Method.Name}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获单个事件处理器的异常,确保其他处理器仍能被调用
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 事件处理器异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 执行完成");
|
||||
}
|
||||
|
||||
#endregion 温度数据处理方法
|
||||
|
||||
#region 公共事件
|
||||
|
||||
/// <summary>
|
||||
@@ -819,6 +1223,11 @@ namespace JoyD.Windows.CS.Toprie
|
||||
/// </summary>
|
||||
public event EventHandler<ImageReceivedEventArgs> ImageReceived;
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据接收事件
|
||||
/// </summary>
|
||||
public event EventHandler<TemperatureReceivedEventArgs> TemperatureReceived;
|
||||
|
||||
#endregion 公共事件
|
||||
|
||||
/// <summary>
|
||||
@@ -1670,6 +2079,9 @@ namespace JoyD.Windows.CS.Toprie
|
||||
_isReceivingImages = false;
|
||||
}
|
||||
|
||||
// 同步停止温度数据接收
|
||||
StopTemperatureDataReceiving();
|
||||
|
||||
// 通知线程停止
|
||||
ManualResetEvent stopEvent = null;
|
||||
lock (_lockObject)
|
||||
@@ -2405,6 +2817,25 @@ namespace JoyD.Windows.CS.Toprie
|
||||
set { _currentPaletteType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前温度模式
|
||||
/// </summary>
|
||||
public TemperatureMode CurrentTemperatureMode { get; set; } = TemperatureMode.Celsius;
|
||||
|
||||
/// <summary>
|
||||
/// 是否正在接收温度数据
|
||||
/// </summary>
|
||||
public bool IsReceivingTemperatureData
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _isReceivingTemperatureData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前视频模式
|
||||
/// </summary>
|
||||
@@ -4663,5 +5094,295 @@ namespace JoyD.Windows.CS.Toprie
|
||||
}
|
||||
|
||||
#endregion IDisposable 实现
|
||||
|
||||
#region 温度相关辅助类
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据事件参数类
|
||||
/// </summary>
|
||||
public class TemperatureReceivedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据对象
|
||||
/// </summary>
|
||||
public TemperatureData TemperatureData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始温度数据字节数组
|
||||
/// </summary>
|
||||
public byte[] RawData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度补偿值
|
||||
/// </summary>
|
||||
public float CompensationValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="temperatureData">温度数据对象</param>
|
||||
/// <param name="rawData">原始温度数据</param>
|
||||
/// <param name="compensationValue">温度补偿值</param>
|
||||
public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
|
||||
{
|
||||
TemperatureData = temperatureData;
|
||||
RawData = rawData;
|
||||
CompensationValue = compensationValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据类,用于存储和处理温度数据
|
||||
/// </summary>
|
||||
public class TemperatureData
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据数组
|
||||
/// </summary>
|
||||
public float[,] Data { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据的宽度(像素)
|
||||
/// </summary>
|
||||
public int Width { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据的高度(像素)
|
||||
/// </summary>
|
||||
public int Height { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度补偿值
|
||||
/// </summary>
|
||||
public float CompensationValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大温度值
|
||||
/// </summary>
|
||||
public float MaxTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小温度值
|
||||
/// </summary>
|
||||
public float MinTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平均温度值
|
||||
/// </summary>
|
||||
public float AverageTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="rawData">原始温度数据字节数组</param>
|
||||
/// <param name="compensationValue">温度补偿值</param>
|
||||
public TemperatureData(byte[] rawData, float compensationValue)
|
||||
{
|
||||
// 假设分辨率为256x192
|
||||
Width = 256;
|
||||
Height = 192;
|
||||
CompensationValue = compensationValue;
|
||||
|
||||
// 初始化温度数据数组
|
||||
Data = new float[Height, Width];
|
||||
|
||||
// 解析原始数据
|
||||
ParseRawData(rawData);
|
||||
|
||||
// 计算温度统计信息
|
||||
CalculateStatistics();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析原始温度数据
|
||||
/// </summary>
|
||||
/// <param name="rawData">原始温度数据字节数组</param>
|
||||
private void ParseRawData(byte[] rawData)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 假设每个温度值由2字节表示
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
int index = (i * Width + j) * 2;
|
||||
if (index + 1 < rawData.Length)
|
||||
{
|
||||
// 读取2字节数据并转换为温度值
|
||||
short rawTempValue = (short)((rawData[index + 1] << 8) | rawData[index]);
|
||||
|
||||
// 转换为实际温度值(假设温度值为原始值除以某个系数)
|
||||
// 这里使用一个示例转换公式,实际转换方式需要根据设备的数据格式确定
|
||||
float temperature = rawTempValue / 100.0f + CompensationValue;
|
||||
|
||||
Data[i, j] = temperature;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常但不抛出,确保即使解析出错也能继续执行
|
||||
Console.WriteLine($"解析温度数据异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算温度统计信息
|
||||
/// </summary>
|
||||
private void CalculateStatistics()
|
||||
{
|
||||
if (Data == null || Data.Length == 0)
|
||||
{
|
||||
MaxTemperature = MinTemperature = AverageTemperature = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
MaxTemperature = float.MinValue;
|
||||
MinTemperature = float.MaxValue;
|
||||
int validCount = 0;
|
||||
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
float temp = Data[i, j];
|
||||
// 跳过无效温度值
|
||||
if (!float.IsNaN(temp) && !float.IsInfinity(temp))
|
||||
{
|
||||
sum += temp;
|
||||
MaxTemperature = Math.Max(MaxTemperature, temp);
|
||||
MinTemperature = Math.Min(MinTemperature, temp);
|
||||
validCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算平均温度
|
||||
AverageTemperature = validCount > 0 ? sum / validCount : 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定区域的温度数据
|
||||
/// </summary>
|
||||
/// <param name="x">区域左上角X坐标</param>
|
||||
/// <param name="y">区域左上角Y坐标</param>
|
||||
/// <param name="width">区域宽度</param>
|
||||
/// <param name="height">区域高度</param>
|
||||
/// <returns>区域温度数据,如果参数无效则返回null</returns>
|
||||
public TemperatureData GetRegionData(int x, int y, int width, int height)
|
||||
{
|
||||
// 验证参数
|
||||
if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
|
||||
x + width > Width || y + height > Height)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 创建区域温度数据数组
|
||||
float[,] regionData = new float[height, width];
|
||||
|
||||
// 复制区域数据
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
regionData[i, j] = Data[y + i, x + j];
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新的温度数据对象
|
||||
TemperatureData result = new TemperatureData();
|
||||
result.Width = width;
|
||||
result.Height = height;
|
||||
result.CompensationValue = CompensationValue;
|
||||
result.Data = regionData;
|
||||
result.CalculateStatistics();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定坐标的温度值(摄氏度)
|
||||
/// </summary>
|
||||
/// <param name="x">X坐标</param>
|
||||
/// <param name="y">Y坐标</param>
|
||||
/// <returns>温度值,如果坐标无效则返回NaN</returns>
|
||||
public float GetTemperatureAt(int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
{
|
||||
return float.NaN;
|
||||
}
|
||||
return Data[y, x];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将温度数据转换为指定的温度模式
|
||||
/// </summary>
|
||||
/// <param name="mode">目标温度模式</param>
|
||||
/// <returns>转换后的温度数据副本</returns>
|
||||
public TemperatureData ConvertTo(TemperatureMode mode)
|
||||
{
|
||||
// 创建新的温度数据对象
|
||||
TemperatureData result = new TemperatureData();
|
||||
result.Width = Width;
|
||||
result.Height = Height;
|
||||
result.CompensationValue = CompensationValue;
|
||||
result.Data = new float[Height, Width];
|
||||
|
||||
// 根据目标模式进行转换
|
||||
switch (mode)
|
||||
{
|
||||
case TemperatureMode.Celsius:
|
||||
// 如果当前已经是摄氏度,直接复制数据
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
result.Data[i, j] = Data[i, j];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TemperatureMode.Fahrenheit:
|
||||
// 摄氏度转华氏度: F = C * 9/5 + 32
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
result.Data[i, j] = Data[i, j] * 9.0f / 5.0f + 32.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TemperatureMode.Kelvin:
|
||||
// 摄氏度转开尔文: K = C + 273.15
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
result.Data[i, j] = Data[i, j] + 273.15f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 重新计算统计信息
|
||||
result.CalculateStatistics();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 私有构造函数,用于内部创建
|
||||
/// </summary>
|
||||
private TemperatureData()
|
||||
{}
|
||||
}
|
||||
|
||||
#endregion 温度相关辅助类
|
||||
}
|
||||
}
|
||||
319
Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs
Normal file
319
Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Toprie
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据模型类,用于存储和处理红外热像仪采集的温度数据
|
||||
/// </summary>
|
||||
public class TemperatureData
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据矩阵
|
||||
/// 格式: [行][列]
|
||||
/// </summary>
|
||||
public float[,] TemperatureMatrix { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据的宽度(列数)
|
||||
/// </summary>
|
||||
public int Width { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度数据的高度(行数)
|
||||
/// </summary>
|
||||
public int Height { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度采集时间戳
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最低温度值
|
||||
/// </summary>
|
||||
public float MinTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最高温度值
|
||||
/// </summary>
|
||||
public float MaxTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平均温度值
|
||||
/// </summary>
|
||||
public float AverageTemperature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据原始数据创建温度数据实例
|
||||
/// </summary>
|
||||
/// <param name="rawData">原始温度数据(每个温度点为2字节)</param>
|
||||
/// <param name="width">温度矩阵宽度</param>
|
||||
/// <param name="height">温度矩阵高度</param>
|
||||
/// <param name="compensationValue">温度补偿值(从sdk_get_comp_temp获取)</param>
|
||||
public TemperatureData(byte[] rawData, int width, int height, float compensationValue = 0)
|
||||
{
|
||||
if (rawData == null)
|
||||
throw new ArgumentNullException(nameof(rawData));
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
throw new ArgumentException("宽度和高度必须大于0");
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
TemperatureMatrix = new float[height, width];
|
||||
Timestamp = DateTime.Now;
|
||||
|
||||
ParseRawData(rawData, compensationValue);
|
||||
CalculateStatistics();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析原始温度数据
|
||||
/// </summary>
|
||||
/// <param name="rawData">原始温度数据</param>
|
||||
/// <param name="compensationValue">温度补偿值</param>
|
||||
private void ParseRawData(byte[] rawData, float compensationValue)
|
||||
{
|
||||
// 按照SDK文档,温度数据为每个点2字节,摄氏温度=(H*256+L)/10
|
||||
// 需要考虑数据分布逻辑:先发送第一行奇数列,再发送第一行偶数列,接着第二行奇数列,依此类推
|
||||
int dataIndex = 0;
|
||||
|
||||
// 处理奇数列
|
||||
for (int row = 0; row < Height; row++)
|
||||
{
|
||||
for (int col = 0; col < Width; col += 2)
|
||||
{
|
||||
if (dataIndex + 1 < rawData.Length)
|
||||
{
|
||||
// 按照SDK文档计算温度值:摄氏温度=(H*256+L)/10
|
||||
// 这里假设H是高位字节,L是低位字节
|
||||
int highByte = rawData[dataIndex];
|
||||
int lowByte = rawData[dataIndex + 1];
|
||||
float temperature = (highByte * 256 + lowByte) / 10.0f;
|
||||
|
||||
// 应用温度补偿值
|
||||
temperature += compensationValue;
|
||||
|
||||
TemperatureMatrix[row, col] = temperature;
|
||||
dataIndex += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理偶数列
|
||||
dataIndex = 0; // 重置索引,重新遍历
|
||||
for (int row = 0; row < Height; row++)
|
||||
{
|
||||
for (int col = 1; col < Width; col += 2)
|
||||
{
|
||||
if (dataIndex + 1 < rawData.Length)
|
||||
{
|
||||
int highByte = rawData[dataIndex];
|
||||
int lowByte = rawData[dataIndex + 1];
|
||||
float temperature = (highByte * 256 + lowByte) / 10.0f;
|
||||
|
||||
// 应用温度补偿值
|
||||
temperature += compensationValue;
|
||||
|
||||
TemperatureMatrix[row, col] = temperature;
|
||||
dataIndex += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算温度统计信息
|
||||
/// </summary>
|
||||
private void CalculateStatistics()
|
||||
{
|
||||
float sum = 0;
|
||||
float min = float.MaxValue;
|
||||
float max = float.MinValue;
|
||||
int count = 0;
|
||||
|
||||
for (int row = 0; row < Height; row++)
|
||||
{
|
||||
for (int col = 0; col < Width; col++)
|
||||
{
|
||||
float temp = TemperatureMatrix[row, col];
|
||||
sum += temp;
|
||||
min = Math.Min(min, temp);
|
||||
max = Math.Max(max, temp);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
MinTemperature = min;
|
||||
MaxTemperature = max;
|
||||
AverageTemperature = count > 0 ? sum / count : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定区域内的温度统计信息
|
||||
/// </summary>
|
||||
/// <param name="startRow">起始行</param>
|
||||
/// <param name="startCol">起始列</param>
|
||||
/// <param name="endRow">结束行</param>
|
||||
/// <param name="endCol">结束列</param>
|
||||
/// <returns>区域温度统计信息</returns>
|
||||
public RegionTemperatureStats GetRegionStatistics(int startRow, int startCol, int endRow, int endCol)
|
||||
{
|
||||
// 参数验证和边界检查
|
||||
startRow = Math.Max(0, startRow);
|
||||
startCol = Math.Max(0, startCol);
|
||||
endRow = Math.Min(Height - 1, endRow);
|
||||
endCol = Math.Min(Width - 1, endCol);
|
||||
|
||||
if (startRow > endRow || startCol > endCol)
|
||||
return new RegionTemperatureStats(0, 0, 0, 0);
|
||||
|
||||
float sum = 0;
|
||||
float min = float.MaxValue;
|
||||
float max = float.MinValue;
|
||||
int count = 0;
|
||||
|
||||
for (int row = startRow; row <= endRow; row++)
|
||||
{
|
||||
for (int col = startCol; col <= endCol; col++)
|
||||
{
|
||||
float temp = TemperatureMatrix[row, col];
|
||||
sum += temp;
|
||||
min = Math.Min(min, temp);
|
||||
max = Math.Max(max, temp);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
float avg = count > 0 ? sum / count : 0;
|
||||
return new RegionTemperatureStats(min, max, avg, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将温度矩阵转换为字节数组(用于保存或传输)
|
||||
/// </summary>
|
||||
/// <returns>温度数据的字节数组表示</returns>
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
// 创建一个包含所有必要信息的字节数组
|
||||
// 包括宽度、高度、时间戳和温度数据
|
||||
int headerSize = 4 + 4 + 8; // width(4) + height(4) + timestamp(8)
|
||||
int dataSize = Width * Height * 4; // 每个温度值使用4字节float
|
||||
byte[] result = new byte[headerSize + dataSize];
|
||||
|
||||
// 写入头信息
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Width), 0, result, 0, 4);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Height), 0, result, 4, 4);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Timestamp.Ticks), 0, result, 8, 8);
|
||||
|
||||
// 写入温度数据
|
||||
int dataIndex = headerSize;
|
||||
for (int row = 0; row < Height; row++)
|
||||
{
|
||||
for (int col = 0; col < Width; col++)
|
||||
{
|
||||
byte[] tempBytes = BitConverter.GetBytes(TemperatureMatrix[row, col]);
|
||||
Buffer.BlockCopy(tempBytes, 0, result, dataIndex, 4);
|
||||
dataIndex += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从字节数组创建TemperatureData实例
|
||||
/// </summary>
|
||||
/// <param name="data">包含温度数据的字节数组</param>
|
||||
/// <returns>TemperatureData实例</returns>
|
||||
public static TemperatureData FromByteArray(byte[] data)
|
||||
{
|
||||
if (data == null || data.Length < 16) // 至少需要头信息的长度
|
||||
throw new ArgumentException("无效的数据格式");
|
||||
|
||||
int width = BitConverter.ToInt32(data, 0);
|
||||
int height = BitConverter.ToInt32(data, 4);
|
||||
long ticks = BitConverter.ToInt64(data, 8);
|
||||
DateTime timestamp = new DateTime(ticks);
|
||||
|
||||
// 验证数据完整性
|
||||
int expectedSize = 16 + width * height * 4;
|
||||
if (data.Length != expectedSize)
|
||||
throw new ArgumentException("数据长度不匹配");
|
||||
|
||||
// 创建温度矩阵
|
||||
float[,] matrix = new float[height, width];
|
||||
int dataIndex = 16;
|
||||
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
for (int col = 0; col < width; col++)
|
||||
{
|
||||
matrix[row, col] = BitConverter.ToSingle(data, dataIndex);
|
||||
dataIndex += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建TemperatureData实例
|
||||
TemperatureData tempData = new TemperatureData();
|
||||
tempData.Width = width;
|
||||
tempData.Height = height;
|
||||
tempData.TemperatureMatrix = matrix;
|
||||
tempData.Timestamp = timestamp;
|
||||
tempData.CalculateStatistics();
|
||||
|
||||
return tempData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 私有构造函数,用于FromByteArray方法
|
||||
/// </summary>
|
||||
private TemperatureData()
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 区域温度统计信息
|
||||
/// </summary>
|
||||
public struct RegionTemperatureStats
|
||||
{
|
||||
/// <summary>
|
||||
/// 区域最低温度
|
||||
/// </summary>
|
||||
public float MinTemperature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区域最高温度
|
||||
/// </summary>
|
||||
public float MaxTemperature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区域平均温度
|
||||
/// </summary>
|
||||
public float AverageTemperature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 统计的温度点数量
|
||||
/// </summary>
|
||||
public int PointCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="minTemp">最低温度</param>
|
||||
/// <param name="maxTemp">最高温度</param>
|
||||
/// <param name="avgTemp">平均温度</param>
|
||||
/// <param name="count">温度点数量</param>
|
||||
public RegionTemperatureStats(float minTemp, float maxTemp, float avgTemp, int count)
|
||||
{
|
||||
MinTemperature = minTemp;
|
||||
MaxTemperature = maxTemp;
|
||||
AverageTemperature = avgTemp;
|
||||
PointCount = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Toprie
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据接收事件参数类
|
||||
/// 用于在接收到温度数据时传递相关信息
|
||||
/// </summary>
|
||||
public class TemperatureReceivedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 温度数据对象
|
||||
/// </summary>
|
||||
public TemperatureData TemperatureData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始温度数据(可选,用于调试或特殊处理)
|
||||
/// </summary>
|
||||
public byte[] RawData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 温度补偿值
|
||||
/// </summary>
|
||||
public float CompensationValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="temperatureData">解析后的温度数据对象</param>
|
||||
public TemperatureReceivedEventArgs(TemperatureData temperatureData)
|
||||
{
|
||||
TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
|
||||
RawData = null;
|
||||
CompensationValue = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数(包含原始数据和补偿值)
|
||||
/// </summary>
|
||||
/// <param name="temperatureData">解析后的温度数据对象</param>
|
||||
/// <param name="rawData">原始温度数据</param>
|
||||
/// <param name="compensationValue">温度补偿值</param>
|
||||
public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
|
||||
{
|
||||
TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
|
||||
RawData = rawData;
|
||||
CompensationValue = compensationValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取温度统计摘要信息
|
||||
/// </summary>
|
||||
public string GetStatisticsSummary()
|
||||
{
|
||||
return $"温度统计 - 最低: {TemperatureData.MinTemperature:F2}°C, " +
|
||||
$"最高: {TemperatureData.MaxTemperature:F2}°C, " +
|
||||
$"平均: {TemperatureData.AverageTemperature:F2}°C, " +
|
||||
$"数据点: {TemperatureData.Width}x{TemperatureData.Height} ({TemperatureData.Width * TemperatureData.Height}), " +
|
||||
$"采集时间: {TemperatureData.Timestamp:yyyy-MM-dd HH:mm:ss.fff}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@
|
||||
<Compile Include="DeviceManager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SharedStructures.cs" />
|
||||
<Compile Include="TemperatureData.cs" />
|
||||
<Compile Include="TemperatureReceivedEventArgs.cs" />
|
||||
<Compile Include="UdpCommunicationManager.cs" />
|
||||
<Compile Include="V8.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user