实现矩形框坐标相对于图像而非控件的功能
This commit is contained in:
@@ -146,4 +146,5 @@
|
|||||||
#### 区域绘制逻辑
|
#### 区域绘制逻辑
|
||||||
1. 创建独立的叠加层图像 :专门维护一个与显示图像同尺寸的Image对象作为矩形框的叠加层
|
1. 创建独立的叠加层图像 :专门维护一个与显示图像同尺寸的Image对象作为矩形框的叠加层
|
||||||
2. 分离绘制逻辑 :将临时绘制和最终绘制分离,临时矩形仍通过Paint事件显示,完成的矩形绘制到叠加层
|
2. 分离绘制逻辑 :将临时绘制和最终绘制分离,临时矩形仍通过Paint事件显示,完成的矩形绘制到叠加层
|
||||||
3. 图像合并机制 :在Paint事件中先绘制叠加层,再绘制临时矩形。
|
3. 图像合并机制 :在Paint事件中先绘制叠加层,再绘制临时矩形。
|
||||||
|
4. 保存的矩形框位置和大小信息应该是相对于图像的,而不是相对于控件的。
|
||||||
@@ -36,6 +36,9 @@ namespace JoyD.Windows.CS
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// 订阅SizeChanged事件,确保控件大小变化时矩形框正确缩放
|
||||||
|
this.picBoxTemp.SizeChanged += new EventHandler(PicBoxTemp_SizeChanged);
|
||||||
|
|
||||||
// 设置按钮图标
|
// 设置按钮图标
|
||||||
SetButtonIcon();
|
SetButtonIcon();
|
||||||
|
|
||||||
@@ -82,6 +85,65 @@ namespace JoyD.Windows.CS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将控件坐标转换为图像坐标
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将图像坐标转换为控件坐标
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将图像矩形转换为控件矩形
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 鼠标按下事件 - 开始绘制矩形
|
/// 鼠标按下事件 - 开始绘制矩形
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -116,11 +178,12 @@ namespace JoyD.Windows.CS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储区域信息的类,包含矩形框、颜色和序号
|
/// 存储区域信息的类,包含矩形框(图像坐标)、颜色和序号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class RegionInfo
|
private class RegionInfo
|
||||||
{
|
{
|
||||||
public Rectangle Rectangle { get; set; }
|
// 存储相对于图像的矩形坐标
|
||||||
|
public Rectangle ImageRectangle { get; set; }
|
||||||
public Color Color { get; set; }
|
public Color Color { get; set; }
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
@@ -128,6 +191,7 @@ namespace JoyD.Windows.CS
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建或更新叠加层图像(完全重绘)
|
/// 创建或更新叠加层图像(完全重绘)
|
||||||
/// 仅在必要时调用,如图像尺寸改变或需要完全重绘
|
/// 仅在必要时调用,如图像尺寸改变或需要完全重绘
|
||||||
|
/// 使用图像坐标绘制矩形
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CreateRectangleOverlayImage()
|
private void CreateRectangleOverlayImage()
|
||||||
{
|
{
|
||||||
@@ -182,6 +246,7 @@ namespace JoyD.Windows.CS
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将单个区域绘制到叠加层图像
|
/// 将单个区域绘制到叠加层图像
|
||||||
/// 用于增量绘制,避免每次都重绘所有矩形
|
/// 用于增量绘制,避免每次都重绘所有矩形
|
||||||
|
/// 使用图像坐标绘制矩形
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="region">要绘制的区域信息</param>
|
/// <param name="region">要绘制的区域信息</param>
|
||||||
private void DrawRegionToOverlay(RegionInfo region)
|
private void DrawRegionToOverlay(RegionInfo region)
|
||||||
@@ -191,16 +256,19 @@ namespace JoyD.Windows.CS
|
|||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(_rectangleOverlayImage))
|
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 (Font font = new Font("Arial", 12, FontStyle.Bold))
|
||||||
using (SolidBrush brush = new SolidBrush(region.Color))
|
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)
|
if (textPosition.Y < 0)
|
||||||
textPosition.Y = 5;
|
textPosition.Y = 5;
|
||||||
|
|
||||||
@@ -212,21 +280,33 @@ namespace JoyD.Windows.CS
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 鼠标释放事件 - 完成矩形绘制(优化版)
|
/// 鼠标释放事件 - 完成矩形绘制(优化版)
|
||||||
/// 使用增量绘制,避免每次都重绘所有矩形
|
/// 使用增量绘制,避免每次都重绘所有矩形
|
||||||
|
/// 确保矩形坐标相对于图像而非控件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void PicBoxTemp_MouseUp(object sender, MouseEventArgs e)
|
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;
|
_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++;
|
_regionCounter++;
|
||||||
RegionInfo regionInfo = new RegionInfo
|
RegionInfo regionInfo = new RegionInfo
|
||||||
{
|
{
|
||||||
Rectangle = _currentRectangle,
|
ImageRectangle = new Rectangle(imageX, imageY, imageWidth, imageHeight),
|
||||||
Color = _selectedColor,
|
Color = _selectedColor,
|
||||||
Index = _regionCounter
|
Index = _regionCounter
|
||||||
};
|
};
|
||||||
@@ -238,9 +318,8 @@ namespace JoyD.Windows.CS
|
|||||||
|
|
||||||
// 如果叠加层不存在或尺寸不匹配,需要完全重建
|
// 如果叠加层不存在或尺寸不匹配,需要完全重建
|
||||||
if (_rectangleOverlayImage == null ||
|
if (_rectangleOverlayImage == null ||
|
||||||
(picBoxTemp.Image != null && (
|
_rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
|
||||||
_rectangleOverlayImage.Width != picBoxTemp.Image.Width ||
|
_rectangleOverlayImage.Height != picBoxTemp.Image.Height)
|
||||||
_rectangleOverlayImage.Height != picBoxTemp.Image.Height)))
|
|
||||||
{
|
{
|
||||||
needFullRebuild = true;
|
needFullRebuild = true;
|
||||||
}
|
}
|
||||||
@@ -259,9 +338,9 @@ namespace JoyD.Windows.CS
|
|||||||
// 显示绘制完成的提示
|
// 显示绘制完成的提示
|
||||||
ToolStripStatusLabel statusLabel = new ToolStripStatusLabel
|
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,
|
_regionCounter,
|
||||||
_currentRectangle.X, _currentRectangle.Y, _currentRectangle.Width, _currentRectangle.Height)
|
imageX, imageY, imageWidth, imageHeight)
|
||||||
};
|
};
|
||||||
// 如果有状态栏,可以添加到状态栏显示
|
// 如果有状态栏,可以添加到状态栏显示
|
||||||
}
|
}
|
||||||
@@ -273,17 +352,25 @@ namespace JoyD.Windows.CS
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 绘制事件 - 显示矩形框(实现图像合并机制)
|
/// 绘制事件 - 显示矩形框(实现图像合并机制)
|
||||||
|
/// 处理叠加层图像的缩放,确保与控件尺寸匹配
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void PicBoxTemp_Paint(object sender, PaintEventArgs e)
|
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))
|
using (Pen dashedPen = new Pen(Color.Blue, 2))
|
||||||
{
|
{
|
||||||
@@ -434,6 +521,27 @@ namespace JoyD.Windows.CS
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定时器每秒触发的事件处理方法
|
/// 定时器每秒触发的事件处理方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// 当图像更新或控件大小变化时,重新创建叠加层图像
|
||||||
|
/// 确保矩形框正确显示在新的尺寸下
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateOverlayForSizeChange()
|
||||||
|
{
|
||||||
|
if (picBoxTemp.Image != null && _drawnRectangles.Count > 0)
|
||||||
|
{
|
||||||
|
CreateRectangleOverlayImage();
|
||||||
|
picBoxTemp.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当控件大小改变时,更新叠加层以确保矩形框正确缩放
|
||||||
|
/// </summary>
|
||||||
|
private void PicBoxTemp_SizeChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
UpdateOverlayForSizeChange();
|
||||||
|
}
|
||||||
|
|
||||||
private void Timer_Tick(object sender, EventArgs e)
|
private void Timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// 这里可以添加每秒需要执行的代码
|
// 这里可以添加每秒需要执行的代码
|
||||||
|
|||||||
Reference in New Issue
Block a user