diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs index e530f26..dbdf5a6 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/Camera.cs @@ -2173,54 +2173,27 @@ namespace JoyD.Windows.CS.Toprie // 如果用户选择了文件路径 if (saveFileDialog.ShowDialog() == DialogResult.OK) { - // 现在直接从设备管理器获取温度数据,不再使用缓存的温度数据 - // 调用设备管理器的方法获取最新的温度数据 + // 获取已有的温度数据(从DeviceManager缓存中获取) TemperatureData temperatureData = _deviceManager.LastTemperature; - if (temperatureData == null) - { - MessageBox.Show("获取温度数据失败,请确保设备已连接且正在接收数据。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - // 保存温度数据到CSV文件 - using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName)) - { - // 写入文件头部信息(以#开头的注释行不会被CSV解析器当作数据) - writer.WriteLine("# 温度数据文件 - CSV格式(逗号分隔值)"); - writer.WriteLine($"# 生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); - writer.WriteLine($"# 分辨率: {temperatureData.Width} x {temperatureData.Height}"); - writer.WriteLine($"# 最高温度: {temperatureData.MaxTemperature:F2} °C"); - writer.WriteLine($"# 最低温度: {temperatureData.MinTemperature:F2} °C"); - writer.WriteLine($"# 平均温度: {temperatureData.AverageTemperature:F2} °C"); - writer.WriteLine(); - - // 写入温度数据矩阵(CSV格式) - for (int i = 0; i < temperatureData.Height; i++) - { - StringBuilder lineBuilder = new StringBuilder(); - for (int j = 0; j < temperatureData.Width; j++) - { - // 获取温度值 - string tempValue = $"{temperatureData.TemperatureMatrix[i, j]:F2}"; - - // CSV标准格式:如果值包含逗号、引号或换行符,需要用引号包围并转义内部引号 - if (tempValue.Contains(',') || tempValue.Contains('"') || tempValue.Contains('\n')) - { - tempValue = $"\"{tempValue.Replace("\"", "\"\"")}\""; - } - - lineBuilder.Append(tempValue); - if (j < temperatureData.Width - 1) - { - lineBuilder.Append(","); - } - } - writer.WriteLine(lineBuilder.ToString()); - } + if (temperatureData == null) + { + MessageBox.Show("获取温度数据失败,请确保设备已连接且正在接收数据。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; } - // 显示保存成功消息 - MessageBox.Show($"温度数据已成功保存到:\n{saveFileDialog.FileName}", "保存成功", MessageBoxButtons.OK, MessageBoxIcon.Information); + // 使用DeviceManager的新重载方法,直接传入已获取的温度数据 + bool saveResult = _deviceManager.SaveTemperatureDataToCsv(saveFileDialog.FileName, temperatureData); + + if (saveResult) + { + // 显示保存成功消息 + MessageBox.Show($"温度数据已成功保存到:\n{saveFileDialog.FileName}", "保存成功", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + // 显示保存失败消息 + MessageBox.Show("保存温度数据失败,请检查文件路径是否有效且有写入权限。", "保存失败", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } catch (Exception ex) diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs index 9f0b328..72713bc 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/DeviceManager.cs @@ -257,8 +257,6 @@ namespace JoyD.Windows.CS.Toprie private bool _isAutoReconnectEnabled = true; // 最大重连次数 private int _maxReconnectAttempts = 5; - // 是否已连接 - private bool _isConnected = false; // 连接超时设置 private readonly int _connectTimeout = 5000; // 当前重连尝试次数 @@ -1599,6 +1597,8 @@ namespace JoyD.Windows.CS.Toprie private const int HEADER_SIZE = 24; // 24字节头部结构体 private const int WIDTH = 256; private const int HEIGHT = 192; + private const int FixedWidth = 512; + private const int FixedHeight = 384; /// 累积的温度数据包列表 // 重入保护标志 @@ -4181,7 +4181,6 @@ namespace JoyD.Windows.CS.Toprie Log("设计模式下跳过实际设备连接"); // 不设置真实的连接状态,避免触发图像接收 _currentDeviceId = deviceId; - _isConnected = false; _connectionStatus = ConnectionStatus.Disconnected; UpdateConnectionStatus(ConnectionStatus.Disconnected, "设计模式:跳过设备连接"); return; @@ -4374,9 +4373,7 @@ namespace JoyD.Windows.CS.Toprie } if (result) - { - _isConnected = true; - + { // 启动心跳检测和连接检查 StartHeartbeat(); StartConnectionCheck(); @@ -5440,17 +5437,16 @@ namespace JoyD.Windows.CS.Toprie /// /// CSV文件路径 /// 是否保存成功 - public bool SaveTemperatureDataToCsv(string filePath) + /// + /// 保存温度数据到CSV文件(接受已有的温度数据) + /// + /// CSV文件路径 + /// 温度数据对象 + /// 是否保存成功 + public bool SaveTemperatureDataToCsv(string filePath, TemperatureData temperatureData) { try { - // 检查设备是否连接 - if (!_isConnected || _a8Sdk == null) - { - Console.WriteLine("设备未连接,无法保存温度数据"); - return false; - } - // 检查文件路径是否有效 if (string.IsNullOrEmpty(filePath)) { @@ -5475,91 +5471,13 @@ namespace JoyD.Windows.CS.Toprie } } - // 尝试从设备获取温度数据 - List temperatureData = new List(); - - try - { - // 使用A8SDK的Get_all_temp方法获取所有温度数据 - Console.WriteLine("正在获取设备温度数据..."); - - SharedStructures.ImageTemp imageTemp = _a8Sdk.Get_all_temp(); - - // 检查是否获取到温度数据 - bool hasTemperatureData = false; - - // 处理全局温度数据 - if (imageTemp.globa.max_temp > -273.0f) // 检查是否有有效温度值(高于绝对零度) - { - Console.WriteLine($"全局温度数据: 最高={imageTemp.globa.max_temp}°C, 最低={imageTemp.globa.min_temp}°C"); - - // 添加全局温度点 - temperatureData.Add(new TemperatureDataPoint(0, 0, imageTemp.globa.max_temp)); - temperatureData.Add(new TemperatureDataPoint(0, 1, imageTemp.globa.min_temp)); - - // 添加最高温度点的坐标 - temperatureData.Add(new TemperatureDataPoint( - imageTemp.globa.max_temp_x, - imageTemp.globa.max_temp_y, - imageTemp.globa.max_temp)); - - // 添加最低温度点的坐标 - temperatureData.Add(new TemperatureDataPoint( - imageTemp.globa.min_temp_x, - imageTemp.globa.min_temp_y, - imageTemp.globa.min_temp)); - - hasTemperatureData = true; - } - - // 处理区域温度数据 - for (int i = 0; i < imageTemp.area.Length; i++) - { - if (imageTemp.area[i].enable == 1 && imageTemp.area[i].ave_temp > -273.0f) - { - Console.WriteLine($"区域 {i+1} 温度: {imageTemp.area[i].ave_temp}°C"); - temperatureData.Add(new TemperatureDataPoint(i + 1, 0, imageTemp.area[i].ave_temp)); - hasTemperatureData = true; - } - } - - // 处理点温度数据 - for (int i = 0; i < imageTemp.spot.Length; i++) - { - if (imageTemp.spot[i].enable == 1 && imageTemp.spot[i].temp > -273.0f) - { - Console.WriteLine($"点 {i+1} 温度: {imageTemp.spot[i].temp}°C"); - temperatureData.Add(new TemperatureDataPoint(i + 1, 1, imageTemp.spot[i].temp)); - hasTemperatureData = true; - } - } - - if (!hasTemperatureData) - { - Console.WriteLine("未获取到有效温度数据,使用模拟数据"); - // 如果无法获取真实数据,使用模拟数据 - GenerateMockTemperatureData(temperatureData); - } - else - { - Console.WriteLine($"成功获取到 {temperatureData.Count} 个温度数据点"); - } - } - catch (Exception ex) - { - Console.WriteLine($"获取温度数据失败: {ex.Message}"); - // 如果获取真实数据失败,使用模拟数据 - Console.WriteLine("使用模拟温度数据作为备选"); - GenerateMockTemperatureData(temperatureData); - } - // 写入CSV文件 try { // 确保有温度数据 - if (temperatureData.Count == 0) + if (temperatureData == null || temperatureData.TemperatureMatrix == null || temperatureData.Width == 0 || temperatureData.Height == 0) { - Console.WriteLine("没有温度数据可保存"); + Console.WriteLine("没有有效的温度数据可保存"); return false; } @@ -5568,31 +5486,30 @@ namespace JoyD.Windows.CS.Toprie // 写入CSV头部和元信息 writer.WriteLine("# 温度数据导出"); writer.WriteLine($"# 导出时间: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); - writer.WriteLine($"# 设备IP: {_deviceIp}"); - writer.WriteLine($"# 数据点数: {temperatureData.Count}"); + writer.WriteLine($"# 采样分辨率: {temperatureData.Width}x{temperatureData.Height}"); + writer.WriteLine($"# 修正分辨率: {FixedWidth}x{FixedHeight}"); + writer.WriteLine($"# 最高温度: {temperatureData.MaxTemperature:F2}°C"); + writer.WriteLine($"# 最低温度: {temperatureData.MinTemperature:F2}°C"); + writer.WriteLine($"# 平均温度: {temperatureData.AverageTemperature:F2}°C"); writer.WriteLine("#"); // 写入数据列头 - writer.WriteLine("数据类型,X坐标,Y坐标,温度值(°C)"); + writer.WriteLine("X坐标,Y坐标,温度值(°C)"); - // 写入温度数据 - foreach (var dataPoint in temperatureData) + // 写入温度矩阵数据 + for (int y = 0; y < FixedHeight; y++) { - // 根据X坐标判断数据类型 - string dataType = "未知"; - if (dataPoint.X == 0 && dataPoint.Y == 0) dataType = "全局最高"; - else if (dataPoint.X == 0 && dataPoint.Y == 1) dataType = "全局最低"; - else if (dataPoint.X == 0 && dataPoint.Y == 2) dataType = "全局平均"; - else if (dataPoint.Y == 0 && dataPoint.X > 0 && dataPoint.X <= 6) dataType = $"区域{dataPoint.X}"; - else if (dataPoint.Y == 1 && dataPoint.X > 0 && dataPoint.X <= 6) dataType = $"点{dataPoint.X}"; - else dataType = "温度点"; - - writer.WriteLine($"{dataType},{dataPoint.X},{dataPoint.Y},{dataPoint.Temperature:F2}"); + for (int x = 0; x < FixedWidth; x++) + { + // 获取温度值 + float temperature = temperatureData.RealTemperatureMatrix[y, x]; + writer.WriteLine($"{x},{y},{temperature:F2}"); + } } } Console.WriteLine($"温度数据已成功保存到: {filePath}"); - Console.WriteLine($"共保存 {temperatureData.Count} 个温度数据点"); + Console.WriteLine($"采样分辨率: {temperatureData.Width}x{temperatureData.Height}"); return true; } catch (IOException ioEx) @@ -5641,190 +5558,6 @@ namespace JoyD.Windows.CS.Toprie } } } - - /// - /// 获取当前温度数据 - /// - /// 当前温度数据对象,如果获取失败则返回null - public TemperatureData GetCurrentTemperatureData() - { - try - { - // 检查设备是否连接 - if (!_isConnected || _a8Sdk == null) - { - Log("设备未连接,无法获取温度数据"); - return null; - } - - // 尝试从设备获取温度数据 - try - { - // 使用A8SDK的Get_all_temp方法获取所有温度数据 - Log("正在获取设备温度数据..."); - - SharedStructures.ImageTemp imageTemp = _a8Sdk.Get_all_temp(); - - // 检查是否获取到温度数据(使用默认值比较而不是null比较) - if (imageTemp.Equals(default(SharedStructures.ImageTemp))) - { - Log("未获取到温度数据,返回null"); - return null; - } - - // 获取温度补偿值 - float compensationValue = _a8Sdk.Comp_temp; - Log($"获取到的温度补偿值: {compensationValue}"); - - // 创建温度数据对象 - // 这里使用模拟的温度矩阵,实际项目中应该使用真实的温度数据 - // 根据设备实际分辨率创建温度矩阵 - const int width = 640; // 假设设备分辨率为640x480 - const int height = 480; - - // 生成模拟的温度数据矩阵 - float[,] temperatureMatrix = new float[height, width]; - - // 填充温度矩阵,使用获取到的最大和最小温度作为参考 - float maxTemp = imageTemp.globa.max_temp > -273.0f ? imageTemp.globa.max_temp : 30.0f; - float minTemp = imageTemp.globa.min_temp > -273.0f ? imageTemp.globa.min_temp : 20.0f; - - // 生成温度矩阵,在最大和最小温度之间变化 - Random rand = new Random(); - for (int i = 0; i < height; i++) - { - for (int j = 0; j < width; j++) - { - // 生成在最小和最大温度之间的随机值 - temperatureMatrix[i, j] = minTemp + (float)rand.NextDouble() * (maxTemp - minTemp); - // 添加一些变化模式,使温度分布更自然 - temperatureMatrix[i, j] += (float)Math.Sin(i * 0.02) * 2.0f + (float)Math.Cos(j * 0.02) * 2.0f; - } - } - - // 确保最大和最小温度点存在 - if (imageTemp.globa.max_temp_x >= 0 && imageTemp.globa.max_temp_y >= 0) - { - int x = Math.Min(imageTemp.globa.max_temp_x, width - 1); - int y = Math.Min(imageTemp.globa.max_temp_y, height - 1); - temperatureMatrix[y, x] = maxTemp; - } - - if (imageTemp.globa.min_temp_x >= 0 && imageTemp.globa.min_temp_y >= 0) - { - int x = Math.Min(imageTemp.globa.min_temp_x, width - 1); - int y = Math.Min(imageTemp.globa.min_temp_y, height - 1); - temperatureMatrix[y, x] = minTemp; - } - - // 创建TemperatureData对象 - // 使用Toprie.TemperatureData类的构造函数 - // 首先创建符合构造函数要求的rawData格式 - List rawDataList = new List(); - for (int i = 0; i < height; i++) - { - for (int j = 0; j < width; j++) - { - // 将温度值转换回原始格式(不包含补偿值) - float tempValue = temperatureMatrix[i, j] - compensationValue; - int tempInt = (int)(tempValue * 10.0f); - rawDataList.Add((byte)((tempInt >> 8) & 0xFF)); // 高字节 - rawDataList.Add((byte)(tempInt & 0xFF)); // 低字节 - } - } - - // 使用全局TemperatureData类的构造函数 - TemperatureData temperatureData = new TemperatureData( - rawDataList.ToArray(), - width, - height, - compensationValue - ); - - Log($"成功创建温度数据对象,分辨率: {width}x{height}, 最大温度: {temperatureData.MaxTemperature:F2}°C, 最小温度: {temperatureData.MinTemperature:F2}°C"); - return temperatureData; - } - catch (Exception ex) - { - Log($"获取温度数据失败: {ex.Message}"); - // 如果获取真实数据失败,尝试生成模拟数据 - return GenerateMockTemperatureData(); - } - } - catch (Exception ex) - { - Log($"GetCurrentTemperatureData方法异常: {ex.Message}"); - return null; - } - } - - /// - /// 生成完整的模拟温度数据对象 - /// - /// 模拟的温度数据对象 - private TemperatureData GenerateMockTemperatureData() - { - try - { - Log("生成模拟温度数据..."); - - // 假设分辨率为640x480 - const int width = 640; - const int height = 480; - - // 创建温度矩阵 - float[,] temperatureMatrix = new float[height, width]; - Random rand = new Random(); - - // 生成有一定模式的模拟温度数据 - for (int i = 0; i < height; i++) - { - for (int j = 0; j < width; j++) - { - // 基础温度25度,加上一些变化模式 - float baseTemp = 25.0f; - // 添加波浪形变化 - float waveVariation = (float)(Math.Sin(i * 0.05) * Math.Cos(j * 0.05)) * 10.0f; - // 添加随机噪声 - float noise = (float)(rand.NextDouble() - 0.5) * 2.0f; - // 组合生成最终温度 - temperatureMatrix[i, j] = baseTemp + waveVariation + noise; - } - } - - // 创建并返回模拟温度数据对象 - // 首先创建符合构造函数要求的rawData格式 - List rawDataList = new List(); - for (int i = 0; i < height; i++) - { - for (int j = 0; j < width; j++) - { - // 将温度值转换回原始格式 - float tempValue = temperatureMatrix[i, j]; - int tempInt = (int)(tempValue * 10.0f); - rawDataList.Add((byte)((tempInt >> 8) & 0xFF)); // 高字节 - rawDataList.Add((byte)(tempInt & 0xFF)); // 低字节 - } - } - - // 使用全局TemperatureData类的构造函数 - TemperatureData temperatureData = new TemperatureData( - rawDataList.ToArray(), - width, - height, - 0 // 模拟数据不需要补偿值 - ); - - Log($"模拟温度数据生成完成,最大温度: {temperatureData.MaxTemperature:F2}°C, 最小温度: {temperatureData.MinTemperature:F2}°C"); - return temperatureData; - } - catch (Exception ex) - { - Log($"生成模拟温度数据失败: {ex.Message}"); - return null; - } - } - #region IDisposable 实现 private bool _disposed = false; diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs index 713588c..94a717b 100644 --- a/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs +++ b/Windows/CS/Framework4.0/Toprie/Toprie/TemperatureData.cs @@ -80,69 +80,69 @@ namespace JoyD.Windows.CS.Toprie } /// - /// 解析原始温度数据 - /// - /// 原始温度数据 - /// 温度补偿值 - private void ParseRawData(byte[] rawData, float compensationValue) - { - // 检查数据是否有效 - if (rawData == null || rawData.Length == 0) + /// 解析原始温度数据 + /// + /// 原始温度数据 + /// 温度补偿值 + private void ParseRawData(byte[] rawData, float compensationValue) { - throw new ArgumentNullException(nameof(rawData), "原始温度数据为空"); - } - - // 根据SDK文档要求,使用24字节头部 - const int HEADER_SIZE = 24; - - // 确保数据长度足够(至少包含头部) - if (rawData.Length < HEADER_SIZE) - { - throw new ArgumentException("数据长度不足,无法解析"); - } - - // 计算温度数据长度和像素总数 - int dataLength = rawData.Length - HEADER_SIZE; - int pixelCount = dataLength / 2; // 每个像素2字节 - - // 计算最大可处理的像素数 - int maxPixels = Math.Min(pixelCount, Width * Height); - - // 跳过24字节头部,按照行优先顺序解析温度数据 - for (int i = 0; i < maxPixels; i++) - { - // 计算行列索引 - int row = i / Width; - int col = i % Width; - - if (row < Height && col < Width) + // 检查数据是否有效 + if (rawData == null || rawData.Length == 0) { - // 计算数据偏移量(跳过24字节头部) - int offset = HEADER_SIZE + i * 2; - - if (offset + 1 < rawData.Length) + throw new ArgumentNullException(nameof(rawData), "原始温度数据为空"); + } + + // 根据SDK文档要求,使用24字节头部 + const int HEADER_SIZE = 24; + + // 确保数据长度足够(至少包含头部) + if (rawData.Length < HEADER_SIZE) + { + throw new ArgumentException("数据长度不足,无法解析"); + } + + // 计算温度数据长度和像素总数 + int dataLength = rawData.Length - HEADER_SIZE; + int pixelCount = dataLength / 2; // 每个像素2字节 + + // 计算最大可处理的像素数 + int maxPixels = Math.Min(pixelCount, Width * Height); + + // 跳过24字节头部,按照行优先顺序解析温度数据 + for (int i = 0; i < maxPixels; i++) + { + // 计算行列索引 + int row = i / Width; + int col = i % Width; + + if (row < Height && col < Width) { - // 根据SDK文档要求,温度值计算方法:(H×256+L)/10,单位为摄氏度 - // H为高8位,L为低8位 - int highByte = rawData[offset + 1]; // 高8位 - int lowByte = rawData[offset]; // 低8位 - int tempValue = (highByte << 8) | lowByte; + // 计算数据偏移量(跳过24字节头部) + int offset = HEADER_SIZE + i * 2; + + if (offset + 1 < rawData.Length) + { + // 根据SDK文档要求,温度值计算方法:(H×256+L)/10,单位为摄氏度 + // H为高8位,L为低8位 + int highByte = rawData[offset + 1]; // 高8位 + int lowByte = rawData[offset]; // 低8位 + int tempValue = (highByte << 8) | lowByte; - // 计算实际温度值:(H×256+L)/10 - float rawTemperature = tempValue / 10.0f; + // 计算实际温度值:(H×256+L)/10 + float rawTemperature = tempValue / 10.0f; - // 应用温度补偿值 - float compensatedTemperature = rawTemperature + compensationValue; + // 应用温度补偿值 + float compensatedTemperature = rawTemperature + compensationValue; - // 原始温度存入TemperatureMatrix(未温补) - TemperatureMatrix[row, col] = rawTemperature; + // 原始温度存入TemperatureMatrix(未温补) + TemperatureMatrix[row, col] = rawTemperature; - // 温补后的温度存入RealTemperatureMatrix(映射到512×384矩阵) - MapToRealTemperatureMatrix(row, col, compensatedTemperature); + // 温补后的温度存入RealTemperatureMatrix(映射到512×384矩阵) + MapToRealTemperatureMatrix(row, col, compensatedTemperature); + } } } } - } /// /// 将原始温度数据映射到512×384的实际温度矩阵