保存时自动裁切

This commit is contained in:
zqm
2026-01-09 16:27:42 +08:00
parent 62fcc91d73
commit c1efddde74

View File

@@ -4101,13 +4101,13 @@ namespace JoyD.Windows.CS
// 写入CSV文件头部使用中文标题
writer.WriteLine("索引,X坐标,Y坐标,宽度,高度,颜色");
// 遍历所有测温区将信息写入CSV文件
foreach (RegionInfo region in _drawnRectangles)
// 遍历所有原始测温区,将相对坐标信息写入CSV文件
foreach (RegionInfo region in _originalTemperatureZones)
{
// 获取颜色的十六进制表示
string colorHex = ColorTranslator.ToHtml(region.Color);
// 写入一行数据,格式:索引,X坐标,Y坐标,宽度,高度,颜色
// 写入一行数据,格式:索引,X坐标,Y坐标,宽度,高度,颜色(相对坐标)
writer.WriteLine($"{region.Index},{region.ImageRectangle.X},{region.ImageRectangle.Y},{region.ImageRectangle.Width},{region.ImageRectangle.Height},{colorHex}");
}
}
@@ -4185,11 +4185,212 @@ namespace JoyD.Windows.CS
/// <summary>
/// 窗口关闭时停止定时器并释放资源
/// </summary>
/// <summary>
/// 检查所有测温区是否在检测区内
/// </summary>
/// <returns>所有测温区都在检测区内返回true否则返回false</returns>
private bool CheckTemperatureZonesInDetectionZone()
{
// 创建检测区矩形
Rectangle detectionRect = new Rectangle(
_detectionZone.X,
_detectionZone.Y,
_detectionZone.Width,
_detectionZone.Height
);
// 遍历所有测温区
foreach (RegionInfo region in _drawnRectangles)
{
// 检查测温区是否完全包含在检测区内
if (!detectionRect.Contains(region.ImageRectangle))
{
return false;
}
}
return true;
}
/// <summary>
/// 检查温差图是否在检测区内
/// </summary>
/// <returns>温差图完全在检测区内返回true否则返回false</returns>
private bool CheckTempDiffInDetectionZone()
{
// 如果没有温差图直接返回true
if (_tempDiffOverlayImage == null || !(_tempDiffOverlayImage is Bitmap))
{
return true;
}
Bitmap bitmap = (Bitmap)_tempDiffOverlayImage;
// 创建检测区矩形
Rectangle detectionRect = new Rectangle(
_detectionZone.X,
_detectionZone.Y,
_detectionZone.Width,
_detectionZone.Height
);
// 检查温差图中是否有超出检测区的像素
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
Color pixelColor = bitmap.GetPixel(x, y);
if (pixelColor.A > 0) // 只检查非透明像素
{
Point pixelPoint = new Point(x, y);
if (!detectionRect.Contains(pixelPoint))
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 裁切测温区到检测区内
/// </summary>
private void CropTemperatureZonesToDetectionZone()
{
// 创建检测区矩形
Rectangle detectionRect = new Rectangle(
_detectionZone.X,
_detectionZone.Y,
_detectionZone.Width,
_detectionZone.Height
);
// 遍历所有测温区
for (int i = _drawnRectangles.Count - 1; i >= 0; i--)
{
RegionInfo region = _drawnRectangles[i];
// 如果测温区完全在检测区内,跳过
if (detectionRect.Contains(region.ImageRectangle))
{
continue;
}
// 计算两个矩形的交集,确保结果完全在检测区内
Rectangle newRect = Rectangle.Intersect(region.ImageRectangle, detectionRect);
// 如果裁切后矩形仍然有大小最小2x2像素更新测温区
if (newRect.Width > 2 && newRect.Height > 2)
{
region.ImageRectangle = newRect;
}
else
{
// 如果裁切后矩形太小,移除该测温区
_drawnRectangles.RemoveAt(i);
}
}
// 同步列表
SyncTemperatureZonesFromDrawnRectangles();
// 更新叠加层
CreateRectangleOverlayImage();
}
/// <summary>
/// 裁切温差图到检测区内
/// </summary>
private void CropTempDiffToDetectionZone()
{
// 如果没有温差图,直接返回
if (_tempDiffOverlayImage == null || !(_tempDiffOverlayImage is Bitmap))
{
return;
}
Bitmap bitmap = (Bitmap)_tempDiffOverlayImage;
// 创建检测区矩形
Rectangle detectionRect = new Rectangle(
_detectionZone.X,
_detectionZone.Y,
_detectionZone.Width,
_detectionZone.Height
);
// 创建新的位图用于保存裁切后的温差图
Bitmap croppedBitmap = new Bitmap(bitmap.Width, bitmap.Height);
// 将超出检测区的像素设置为透明
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
Color pixelColor = bitmap.GetPixel(x, y);
if (pixelColor.A > 0) // 只处理非透明像素
{
Point pixelPoint = new Point(x, y);
if (!detectionRect.Contains(pixelPoint))
{
// 设置为透明
croppedBitmap.SetPixel(x, y, Color.Transparent);
}
else
{
// 保留原颜色
croppedBitmap.SetPixel(x, y, pixelColor);
}
}
}
}
// 释放旧的温差图并替换为裁切后的
_tempDiffOverlayImage.Dispose();
_tempDiffOverlayImage = croppedBitmap;
}
private void Setting_FormClosing(object sender, FormClosingEventArgs e)
{
// 当自动配置为true时保存回加载时的文件
if (_autoConfig && !string.IsNullOrEmpty(_projectPath))
{
bool hasOutOfBounds = false;
string message = "";
// 检查测温区
if (!CheckTemperatureZonesInDetectionZone())
{
hasOutOfBounds = true;
message += "部分测温区超出检测区范围,";
}
// 检查温差图
if (!CheckTempDiffInDetectionZone())
{
hasOutOfBounds = true;
message += "部分温差图超出检测区范围,";
}
// 如果有超出部分,提示用户
if (hasOutOfBounds)
{
message += "是否自动裁切并保存?";
DialogResult result = MessageBox.Show(message, "保存确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (result == DialogResult.Cancel)
{
e.Cancel = true; // 取消关闭窗口
return;
}
else
{
// 裁切超出部分
CropTemperatureZonesToDetectionZone();
CropTempDiffToDetectionZone();
}
}
// 自动保存测温区配置
SaveTempRegionToDefaultPath();
// 自动保存温差图配置
@@ -5367,8 +5568,8 @@ namespace JoyD.Windows.CS
writer.WriteLine("像素温度数据");
writer.WriteLine("X坐标,Y坐标,温度值(°C)");
// 从_tempDiffOverlayImage中获取真实温度数据
if (_tempDiffOverlayImage != null && _tempDiffOverlayImage is Bitmap)
// 使用原始温差图数据(相对坐标)保存
if (_originalTempDiffData.Count > 0)
{
Bitmap bitmap = (Bitmap)_tempDiffOverlayImage;
@@ -5480,59 +5681,15 @@ namespace JoyD.Windows.CS
writer.WriteLine("像素温度数据");
writer.WriteLine("X坐标,Y坐标,温度值(°C)");
// 从_tempDiffOverlayImage中获取真实温度数据
if (_tempDiffOverlayImage != null && _tempDiffOverlayImage is Bitmap)
// 使用_originalTempDiffData保存相对坐标的温差数据
if (_originalTempDiffData.Count > 0)
{
Bitmap bitmap = (Bitmap)_tempDiffOverlayImage;
// 锁定位图以提高性能
BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
try
// 遍历原始温差数据字典,保存相对坐标的温差数据
foreach (KeyValuePair<Point, double> pair in _originalTempDiffData)
{
int bytesPerPixel = 4; // 32bppArgb格式每像素4字节
int byteCount = bitmapData.Stride * bitmapData.Height;
byte[] pixels = new byte[byteCount];
// 将图像数据复制到数组
Marshal.Copy(bitmapData.Scan0, pixels, 0, byteCount);
// 保存所有非透明像素
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
// 计算当前像素在数组中的位置
int pixelIndex = y * bitmapData.Stride + x * bytesPerPixel;
// 获取像素颜色
byte b = pixels[pixelIndex];
byte g = pixels[pixelIndex + 1];
byte r = pixels[pixelIndex + 2];
byte a = pixels[pixelIndex + 3];
// 只处理非透明的像素
if (a > 0)
{
Color pixelColor = Color.FromArgb(a, r, g, b);
double? temperature = GetTemperatureByColor(pixelColor);
// 如果找到对应的温度值,则写入文件
if (temperature.HasValue)
{
writer.WriteLine($"{x},{y},{temperature.Value:F1}");
}
}
}
}
}
finally
{
// 解锁位图
bitmap.UnlockBits(bitmapData);
Point relativePoint = pair.Key;
double temperature = pair.Value;
writer.WriteLine($"{relativePoint.X},{relativePoint.Y},{temperature:F1}");
}
}
else