diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs
index aa822b0..8e925b3 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs
@@ -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;
}
}
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs
index 830af27..cf6c206 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs
@@ -69,6 +69,25 @@ namespace JoyD.Windows.CS.Toprie
Fusion5 // 融合5,对应SDK参数6
}
+ ///
+ /// 温度模式枚举
+ ///
+ public enum TemperatureMode
+ {
+ ///
+ /// 摄氏度
+ ///
+ Celsius,
+ ///
+ /// 华氏度
+ ///
+ Fahrenheit,
+ ///
+ /// 开尔文
+ ///
+ Kelvin
+ }
+
///
/// 连接状态改变事件参数
///
@@ -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端口
+
///
/// 项目路径属性
/// 用于设置控件存取数据文件的目录
@@ -610,6 +637,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;
}
@@ -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 温度数据处理方法
+
+ ///
+ /// 获取温度补偿值
+ ///
+ /// 温度补偿值
+ 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;
+ }
+
+ ///
+ /// 开始接收温度数据
+ ///
+ 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() - 执行完成");
+ }
+ }
+
+ ///
+ /// 停止接收温度数据
+ ///
+ 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() - 执行完成");
+ }
+ }
+
+ ///
+ /// 使用TCP接收温度数据
+ ///
+ 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 temperatureDataAccumulator = new List();
+
+ // 发送开始温度数据传输的命令
+ 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();
+ }
+ }
+
+ ///
+ /// 处理接收到的温度数据
+ ///
+ /// 累积的温度数据
+ private void ProcessReceivedTemperatureData(List 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();
+ }
+ }
+
+ ///
+ /// 触发温度数据接收事件
+ ///
+ /// 事件参数
+ 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 handler = TemperatureReceived;
+
+ // 检查是否有订阅者
+ if (handler != null)
+ {
+ // 获取所有订阅的委托,单独处理每个处理器
+ Delegate[] invocationList = handler.GetInvocationList();
+
+ foreach (Delegate d in invocationList)
+ {
+ try
+ {
+ // 安全地转换并调用每个处理器
+ EventHandler invoker = (EventHandler)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 公共事件
///
@@ -818,6 +1222,11 @@ namespace JoyD.Windows.CS.Toprie
/// 图像数据接收事件
///
public event EventHandler ImageReceived;
+
+ ///
+ /// 温度数据接收事件
+ ///
+ public event EventHandler TemperatureReceived;
#endregion 公共事件
@@ -1669,6 +2078,9 @@ namespace JoyD.Windows.CS.Toprie
{
_isReceivingImages = false;
}
+
+ // 同步停止温度数据接收
+ StopTemperatureDataReceiving();
// 通知线程停止
ManualResetEvent stopEvent = null;
@@ -2405,6 +2817,25 @@ namespace JoyD.Windows.CS.Toprie
set { _currentPaletteType = value; }
}
+ ///
+ /// 当前温度模式
+ ///
+ public TemperatureMode CurrentTemperatureMode { get; set; } = TemperatureMode.Celsius;
+
+ ///
+ /// 是否正在接收温度数据
+ ///
+ public bool IsReceivingTemperatureData
+ {
+ get
+ {
+ lock (_lockObject)
+ {
+ return _isReceivingTemperatureData;
+ }
+ }
+ }
+
///
/// 获取或设置当前视频模式
///
@@ -4663,5 +5094,295 @@ namespace JoyD.Windows.CS.Toprie
}
#endregion IDisposable 实现
+
+ #region 温度相关辅助类
+
+ ///
+ /// 温度数据事件参数类
+ ///
+ public class TemperatureReceivedEventArgs : EventArgs
+ {
+ ///
+ /// 温度数据对象
+ ///
+ public TemperatureData TemperatureData { get; private set; }
+
+ ///
+ /// 原始温度数据字节数组
+ ///
+ public byte[] RawData { get; private set; }
+
+ ///
+ /// 温度补偿值
+ ///
+ public float CompensationValue { get; private set; }
+
+ ///
+ /// 构造函数
+ ///
+ /// 温度数据对象
+ /// 原始温度数据
+ /// 温度补偿值
+ public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
+ {
+ TemperatureData = temperatureData;
+ RawData = rawData;
+ CompensationValue = compensationValue;
+ }
+ }
+
+ ///
+ /// 温度数据类,用于存储和处理温度数据
+ ///
+ public class TemperatureData
+ {
+ ///
+ /// 温度数据数组
+ ///
+ public float[,] Data { get; private set; }
+
+ ///
+ /// 温度数据的宽度(像素)
+ ///
+ public int Width { get; private set; }
+
+ ///
+ /// 温度数据的高度(像素)
+ ///
+ public int Height { get; private set; }
+
+ ///
+ /// 温度补偿值
+ ///
+ public float CompensationValue { get; private set; }
+
+ ///
+ /// 最大温度值
+ ///
+ public float MaxTemperature { get; private set; }
+
+ ///
+ /// 最小温度值
+ ///
+ public float MinTemperature { get; private set; }
+
+ ///
+ /// 平均温度值
+ ///
+ public float AverageTemperature { get; private set; }
+
+ ///
+ /// 构造函数
+ ///
+ /// 原始温度数据字节数组
+ /// 温度补偿值
+ public TemperatureData(byte[] rawData, float compensationValue)
+ {
+ // 假设分辨率为256x192
+ Width = 256;
+ Height = 192;
+ CompensationValue = compensationValue;
+
+ // 初始化温度数据数组
+ Data = new float[Height, Width];
+
+ // 解析原始数据
+ ParseRawData(rawData);
+
+ // 计算温度统计信息
+ CalculateStatistics();
+ }
+
+ ///
+ /// 解析原始温度数据
+ ///
+ /// 原始温度数据字节数组
+ 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}");
+ }
+ }
+
+ ///
+ /// 计算温度统计信息
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取指定区域的温度数据
+ ///
+ /// 区域左上角X坐标
+ /// 区域左上角Y坐标
+ /// 区域宽度
+ /// 区域高度
+ /// 区域温度数据,如果参数无效则返回null
+ 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;
+ }
+
+ ///
+ /// 获取指定坐标的温度值(摄氏度)
+ ///
+ /// X坐标
+ /// Y坐标
+ /// 温度值,如果坐标无效则返回NaN
+ public float GetTemperatureAt(int x, int y)
+ {
+ if (x < 0 || x >= Width || y < 0 || y >= Height)
+ {
+ return float.NaN;
+ }
+ return Data[y, x];
+ }
+
+ ///
+ /// 将温度数据转换为指定的温度模式
+ ///
+ /// 目标温度模式
+ /// 转换后的温度数据副本
+ 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;
+ }
+
+ ///
+ /// 私有构造函数,用于内部创建
+ ///
+ private TemperatureData()
+ {}
+ }
+
+ #endregion 温度相关辅助类
}
}
\ No newline at end of file
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs
new file mode 100644
index 0000000..e60b3bd
--- /dev/null
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Toprie
+{
+ ///
+ /// 温度数据模型类,用于存储和处理红外热像仪采集的温度数据
+ ///
+ public class TemperatureData
+ {
+ ///
+ /// 温度数据矩阵
+ /// 格式: [行][列]
+ ///
+ public float[,] TemperatureMatrix { get; private set; }
+
+ ///
+ /// 温度数据的宽度(列数)
+ ///
+ public int Width { get; private set; }
+
+ ///
+ /// 温度数据的高度(行数)
+ ///
+ public int Height { get; private set; }
+
+ ///
+ /// 温度采集时间戳
+ ///
+ public DateTime Timestamp { get; set; }
+
+ ///
+ /// 最低温度值
+ ///
+ public float MinTemperature { get; private set; }
+
+ ///
+ /// 最高温度值
+ ///
+ public float MaxTemperature { get; private set; }
+
+ ///
+ /// 平均温度值
+ ///
+ public float AverageTemperature { get; private set; }
+
+ ///
+ /// 根据原始数据创建温度数据实例
+ ///
+ /// 原始温度数据(每个温度点为2字节)
+ /// 温度矩阵宽度
+ /// 温度矩阵高度
+ /// 温度补偿值(从sdk_get_comp_temp获取)
+ 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();
+ }
+
+ ///
+ /// 解析原始温度数据
+ ///
+ /// 原始温度数据
+ /// 温度补偿值
+ 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;
+ }
+ }
+ }
+ }
+
+ ///
+ /// 计算温度统计信息
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取指定区域内的温度统计信息
+ ///
+ /// 起始行
+ /// 起始列
+ /// 结束行
+ /// 结束列
+ /// 区域温度统计信息
+ 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);
+ }
+
+ ///
+ /// 将温度矩阵转换为字节数组(用于保存或传输)
+ ///
+ /// 温度数据的字节数组表示
+ 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;
+ }
+
+ ///
+ /// 从字节数组创建TemperatureData实例
+ ///
+ /// 包含温度数据的字节数组
+ /// TemperatureData实例
+ 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;
+ }
+
+ ///
+ /// 私有构造函数,用于FromByteArray方法
+ ///
+ private TemperatureData()
+ { }
+ }
+
+ ///
+ /// 区域温度统计信息
+ ///
+ public struct RegionTemperatureStats
+ {
+ ///
+ /// 区域最低温度
+ ///
+ public float MinTemperature { get; }
+
+ ///
+ /// 区域最高温度
+ ///
+ public float MaxTemperature { get; }
+
+ ///
+ /// 区域平均温度
+ ///
+ public float AverageTemperature { get; }
+
+ ///
+ /// 统计的温度点数量
+ ///
+ public int PointCount { get; }
+
+ ///
+ /// 构造函数
+ ///
+ /// 最低温度
+ /// 最高温度
+ /// 平均温度
+ /// 温度点数量
+ public RegionTemperatureStats(float minTemp, float maxTemp, float avgTemp, int count)
+ {
+ MinTemperature = minTemp;
+ MaxTemperature = maxTemp;
+ AverageTemperature = avgTemp;
+ PointCount = count;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs
new file mode 100644
index 0000000..849d4f5
--- /dev/null
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureReceivedEventArgs.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Toprie
+{
+ ///
+ /// 温度数据接收事件参数类
+ /// 用于在接收到温度数据时传递相关信息
+ ///
+ public class TemperatureReceivedEventArgs : EventArgs
+ {
+ ///
+ /// 温度数据对象
+ ///
+ public TemperatureData TemperatureData { get; private set; }
+
+ ///
+ /// 原始温度数据(可选,用于调试或特殊处理)
+ ///
+ public byte[] RawData { get; private set; }
+
+ ///
+ /// 温度补偿值
+ ///
+ public float CompensationValue { get; private set; }
+
+ ///
+ /// 构造函数
+ ///
+ /// 解析后的温度数据对象
+ public TemperatureReceivedEventArgs(TemperatureData temperatureData)
+ {
+ TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
+ RawData = null;
+ CompensationValue = 0;
+ }
+
+ ///
+ /// 构造函数(包含原始数据和补偿值)
+ ///
+ /// 解析后的温度数据对象
+ /// 原始温度数据
+ /// 温度补偿值
+ public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
+ {
+ TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
+ RawData = rawData;
+ CompensationValue = compensationValue;
+ }
+
+ ///
+ /// 获取温度统计摘要信息
+ ///
+ 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}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj
index 817a1a5..b4eb9e6 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/Toprie.csproj
@@ -73,6 +73,8 @@
+
+