diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/README.md b/Windows/CS/Framework4.0/Toprie/Toprie/README.md
index a6fdd51..de0a751 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/README.md
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/README.md
@@ -146,4 +146,5 @@
#### 区域绘制逻辑
1. 创建独立的叠加层图像 :专门维护一个与显示图像同尺寸的Image对象作为矩形框的叠加层
2. 分离绘制逻辑 :将临时绘制和最终绘制分离,临时矩形仍通过Paint事件显示,完成的矩形绘制到叠加层
-3. 图像合并机制 :在Paint事件中先绘制叠加层,再绘制临时矩形。
\ No newline at end of file
+3. 图像合并机制 :在Paint事件中先绘制叠加层,再绘制临时矩形。
+4. 保存的矩形框位置和大小信息应该是相对于图像的,而不是相对于控件的。
\ No newline at end of file
diff --git a/Windows/CS/Framework4.0/Toprie/Toprie/Setting.cs b/Windows/CS/Framework4.0/Toprie/Toprie/Setting.cs
index c0b8c81..8db1326 100644
--- a/Windows/CS/Framework4.0/Toprie/Toprie/Setting.cs
+++ b/Windows/CS/Framework4.0/Toprie/Toprie/Setting.cs
@@ -36,6 +36,9 @@ namespace JoyD.Windows.CS
{
InitializeComponent();
+ // 订阅SizeChanged事件,确保控件大小变化时矩形框正确缩放
+ this.picBoxTemp.SizeChanged += new EventHandler(PicBoxTemp_SizeChanged);
+
// 设置按钮图标
SetButtonIcon();
@@ -82,6 +85,65 @@ namespace JoyD.Windows.CS
}
}
+ ///
+ /// 将控件坐标转换为图像坐标
+ ///
+ private Point ControlPointToImagePoint(Point controlPoint)
+ {
+ if (picBoxTemp.Image == null)
+ return controlPoint;
+
+ // 计算图像在控件中的缩放比例
+ float scaleX = (float)picBoxTemp.Image.Width / picBoxTemp.ClientSize.Width;
+ float scaleY = (float)picBoxTemp.Image.Height / picBoxTemp.ClientSize.Height;
+
+ // 计算图像坐标
+ return new Point(
+ (int)(controlPoint.X * scaleX),
+ (int)(controlPoint.Y * scaleY)
+ );
+ }
+
+ ///
+ /// 将图像坐标转换为控件坐标
+ ///
+ private Point ImagePointToControlPoint(Point imagePoint)
+ {
+ if (picBoxTemp.Image == null)
+ return imagePoint;
+
+ // 计算图像在控件中的缩放比例
+ float scaleX = (float)picBoxTemp.ClientSize.Width / picBoxTemp.Image.Width;
+ float scaleY = (float)picBoxTemp.ClientSize.Height / picBoxTemp.Image.Height;
+
+ // 计算控件坐标
+ return new Point(
+ (int)(imagePoint.X * scaleX),
+ (int)(imagePoint.Y * scaleY)
+ );
+ }
+
+ ///
+ /// 将图像矩形转换为控件矩形
+ ///
+ private Rectangle ImageRectangleToControlRectangle(Rectangle imageRectangle)
+ {
+ if (picBoxTemp.Image == null)
+ return imageRectangle;
+
+ // 计算图像在控件中的缩放比例
+ float scaleX = (float)picBoxTemp.ClientSize.Width / picBoxTemp.Image.Width;
+ float scaleY = (float)picBoxTemp.ClientSize.Height / picBoxTemp.Image.Height;
+
+ // 计算控件矩形
+ return new Rectangle(
+ (int)(imageRectangle.X * scaleX),
+ (int)(imageRectangle.Y * scaleY),
+ (int)(imageRectangle.Width * scaleX),
+ (int)(imageRectangle.Height * scaleY)
+ );
+ }
+
///
/// 鼠标按下事件 - 开始绘制矩形
///
@@ -116,11 +178,12 @@ namespace JoyD.Windows.CS
}
///
- /// 存储区域信息的类,包含矩形框、颜色和序号
+ /// 存储区域信息的类,包含矩形框(图像坐标)、颜色和序号
///
private class RegionInfo
{
- public Rectangle Rectangle { get; set; }
+ // 存储相对于图像的矩形坐标
+ public Rectangle ImageRectangle { get; set; }
public Color Color { get; set; }
public int Index { get; set; }
}
@@ -128,6 +191,7 @@ namespace JoyD.Windows.CS
///
/// 创建或更新叠加层图像(完全重绘)
/// 仅在必要时调用,如图像尺寸改变或需要完全重绘
+ /// 使用图像坐标绘制矩形
///
private void CreateRectangleOverlayImage()
{
@@ -182,6 +246,7 @@ namespace JoyD.Windows.CS
///
/// 将单个区域绘制到叠加层图像
/// 用于增量绘制,避免每次都重绘所有矩形
+ /// 使用图像坐标绘制矩形
///
/// 要绘制的区域信息
private void DrawRegionToOverlay(RegionInfo region)
@@ -191,16 +256,19 @@ namespace JoyD.Windows.CS
using (Graphics g = Graphics.FromImage(_rectangleOverlayImage))
{
+ // 设置高质量绘图
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+
// 使用每个区域自己的颜色绘制矩形
- g.DrawRectangle(new Pen(region.Color, 2), region.Rectangle);
+ g.DrawRectangle(new Pen(region.Color, 2), region.ImageRectangle);
// 绘制区域序号
using (Font font = new Font("Arial", 12, FontStyle.Bold))
using (SolidBrush brush = new SolidBrush(region.Color))
{
// 在矩形左上角绘制序号
- Point textPosition = new Point(region.Rectangle.X + 5, region.Rectangle.Y - 15);
- // 确保文本不超出控件边界
+ Point textPosition = new Point(region.ImageRectangle.X + 5, region.ImageRectangle.Y - 15);
+ // 确保文本不超出图像边界
if (textPosition.Y < 0)
textPosition.Y = 5;
@@ -212,21 +280,33 @@ namespace JoyD.Windows.CS
///
/// 鼠标释放事件 - 完成矩形绘制(优化版)
/// 使用增量绘制,避免每次都重绘所有矩形
+ /// 确保矩形坐标相对于图像而非控件
///
private void PicBoxTemp_MouseUp(object sender, MouseEventArgs e)
{
- if (_isDrawing && _isDrawingMode && e.Button == MouseButtons.Left)
+ if (_isDrawing && _isDrawingMode && e.Button == MouseButtons.Left && picBoxTemp.Image != null)
{
_isDrawing = false;
- // 确保矩形有一定大小才添加
- if (_currentRectangle.Width > 10 && _currentRectangle.Height > 10)
+ // 获取相对于图像的矩形坐标
+ Point imageStartPoint = ControlPointToImagePoint(new Point(_currentRectangle.X, _currentRectangle.Y));
+ Point imageEndPoint = ControlPointToImagePoint(new Point(_currentRectangle.Right, _currentRectangle.Bottom));
+
+ // 确保矩形有一定大小才添加(转换为图像坐标后检查)
+ int imageWidth = Math.Abs(imageEndPoint.X - imageStartPoint.X);
+ int imageHeight = Math.Abs(imageEndPoint.Y - imageStartPoint.Y);
+
+ if (imageWidth > 5 && imageHeight > 5)
{
- // 增加计数器并创建新的区域信息
+ // 计算图像坐标的矩形(确保左上角为起始点)
+ int imageX = Math.Min(imageStartPoint.X, imageEndPoint.X);
+ int imageY = Math.Min(imageStartPoint.Y, imageEndPoint.Y);
+
+ // 增加计数器并创建新的区域信息(存储图像坐标)
_regionCounter++;
RegionInfo regionInfo = new RegionInfo
{
- Rectangle = _currentRectangle,
+ ImageRectangle = new Rectangle(imageX, imageY, imageWidth, imageHeight),
Color = _selectedColor,
Index = _regionCounter
};
@@ -238,9 +318,8 @@ namespace JoyD.Windows.CS
// 如果叠加层不存在或尺寸不匹配,需要完全重建
if (_rectangleOverlayImage == null ||
- (picBoxTemp.Image != null && (
- _rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
- _rectangleOverlayImage.Height != picBoxTemp.Image.Height)))
+ _rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
+ _rectangleOverlayImage.Height != picBoxTemp.Image.Height)
{
needFullRebuild = true;
}
@@ -259,9 +338,9 @@ namespace JoyD.Windows.CS
// 显示绘制完成的提示
ToolStripStatusLabel statusLabel = new ToolStripStatusLabel
{
- Text = string.Format("已添加检测区域{0}: X={1}, Y={2}, 宽={3}, 高={4}",
+ Text = string.Format("已添加检测区域{0}: 图像坐标 - X={1}, Y={2}, 宽={3}, 高={4}",
_regionCounter,
- _currentRectangle.X, _currentRectangle.Y, _currentRectangle.Width, _currentRectangle.Height)
+ imageX, imageY, imageWidth, imageHeight)
};
// 如果有状态栏,可以添加到状态栏显示
}
@@ -273,17 +352,25 @@ namespace JoyD.Windows.CS
///
/// 绘制事件 - 显示矩形框(实现图像合并机制)
+ /// 处理叠加层图像的缩放,确保与控件尺寸匹配
///
private void PicBoxTemp_Paint(object sender, PaintEventArgs e)
{
- // 图像合并机制:先绘制叠加层
- if (_rectangleOverlayImage != null)
+ // 设置高质量绘图
+ e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
+ e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+
+ // 图像合并机制:先绘制叠加层(根据控件尺寸进行缩放)
+ if (_rectangleOverlayImage != null && picBoxTemp.Image != null)
{
- e.Graphics.DrawImage(_rectangleOverlayImage, Point.Empty);
+ // 计算缩放后的目标矩形
+ Rectangle destRect = new Rectangle(0, 0, picBoxTemp.ClientSize.Width, picBoxTemp.ClientSize.Height);
+ // 绘制缩放后的叠加层
+ e.Graphics.DrawImage(_rectangleOverlayImage, destRect, 0, 0, _rectangleOverlayImage.Width, _rectangleOverlayImage.Height, GraphicsUnit.Pixel);
}
- // 再绘制临时矩形(当前正在绘制的矩形)
- if (!_currentRectangle.IsEmpty)
+ // 再绘制临时矩形(当前正在绘制的矩形,使用控件坐标)
+ if (!_currentRectangle.IsEmpty && _isDrawingMode && _isDrawing)
{
using (Pen dashedPen = new Pen(Color.Blue, 2))
{
@@ -434,6 +521,27 @@ namespace JoyD.Windows.CS
///
/// 定时器每秒触发的事件处理方法
///
+ ///
+ /// 当图像更新或控件大小变化时,重新创建叠加层图像
+ /// 确保矩形框正确显示在新的尺寸下
+ ///
+ private void UpdateOverlayForSizeChange()
+ {
+ if (picBoxTemp.Image != null && _drawnRectangles.Count > 0)
+ {
+ CreateRectangleOverlayImage();
+ picBoxTemp.Invalidate();
+ }
+ }
+
+ ///
+ /// 当控件大小改变时,更新叠加层以确保矩形框正确缩放
+ ///
+ private void PicBoxTemp_SizeChanged(object sender, EventArgs e)
+ {
+ UpdateOverlayForSizeChange();
+ }
+
private void Timer_Tick(object sender, EventArgs e)
{
// 这里可以添加每秒需要执行的代码