C# Windows 窗体 PictureBox:控件坐标和图像中像素位置之间的转换
C# WindowsForms PictureBox: Transformation between control coordinates and pixel position in image
我有一个带有 PictureBox 的控件。 PictureBox 显示图像(在缩放模式下,至少在这种特殊情况下)。我需要做两种事情:
- 用鼠标点击,找出我点击了图像的哪个像素
- 在图像中给定列的 PictureBox 上画一条垂直线。
显然,我需要在控制坐标和图像中像素的(行,列)之间进行某种坐标转换。我可能找到了第一个 (www.codeproject.com/Articles/20923/Mouse-Position-over-Image-in-a-PictureBox),但反之则不然。有什么想法吗?
我可以建议 "workaround":您不要在 PictureBox 上绘制线条等,而是使用其 Graphics 在位图本身上绘制。那么就可以只使用图像坐标(行,列),不需要从控件转换为图像。反过来(从鼠标点击到行和列),如你所说,已解决,可以使用。
在尝试在位图上绘制图形元素而不是在包含 PictureBox 上绘制图形元素后,我发现这种方法很笨拙:它带来的问题多于它解决的问题。我回到了 TaW 的提议( 函数 SetImageScale(PictureBox pbox, out RectangleF rectImage, out float zoom)
。)
如果您知道 rectImage
矩形(TaW 代码中的 ImgArea
),那么两种转换(到控件的坐标以及图像的列和行)都非常简单:
/// <summary>
/// Converts coordinates of a point from the picture box grid into column and row of its image.
/// </summary>
/// <param name="pb">The PictureBox.</param>
/// <param name="ptControl">The point in picture box coordinates (X, Y).</param>
/// <returns>Point in image coordinates (column, row).</returns>
private Point ToImageCoordinates(PictureBox pb, Point ptControl)
{
if (pb.Image == null)
{
return new Point(Int32.MinValue, Int32.MinValue);
}
float deltaX = ptControl.X - rectImage.Left;
float deltaY = ptControl.Y - rectImage.Top;
int column = (int)(deltaX * (pb.Image.Width / rectImage.Width) + 0.5);
int row = (int)(deltaY * (pb.Image.Height / rectImage.Height) + 0.5);
return new Point(column, row);
}
/// <summary>
/// Converts coordinates of a point from the grid (column, row) into the coordinate system of the picture box.
/// </summary>
/// <param name="pb">The PictureBox.</param>
/// <param name="ptImage">The point in image coordinates (column, row).</param>
/// <returns>Point in control coordinates (X, Y).</returns>
private PointF ToControlCoordinates(PictureBox pb, Point ptImage)
{
if (pb.Image == null)
{
return new Point(Int32.MinValue, Int32.MinValue);
}
float deltaX = ptImage.X * (rectImage.Width / pb.Image.Width);
float deltaY = ptImage.Y * (rectImage.Height / pb.Image.Height);
return new PointF(deltaX + rectImage.Left, deltaY + rectImage.Top);
}
这些功能已经过测试,似乎可以正常工作。
记住:这些转换仅在 PictureBox 处于 Zoom
模式时有效。
我有一个带有 PictureBox 的控件。 PictureBox 显示图像(在缩放模式下,至少在这种特殊情况下)。我需要做两种事情:
- 用鼠标点击,找出我点击了图像的哪个像素
- 在图像中给定列的 PictureBox 上画一条垂直线。
显然,我需要在控制坐标和图像中像素的(行,列)之间进行某种坐标转换。我可能找到了第一个 (www.codeproject.com/Articles/20923/Mouse-Position-over-Image-in-a-PictureBox),但反之则不然。有什么想法吗?
我可以建议 "workaround":您不要在 PictureBox 上绘制线条等,而是使用其 Graphics 在位图本身上绘制。那么就可以只使用图像坐标(行,列),不需要从控件转换为图像。反过来(从鼠标点击到行和列),如你所说,已解决,可以使用。
在尝试在位图上绘制图形元素而不是在包含 PictureBox 上绘制图形元素后,我发现这种方法很笨拙:它带来的问题多于它解决的问题。我回到了 TaW 的提议(SetImageScale(PictureBox pbox, out RectangleF rectImage, out float zoom)
。)
如果您知道 rectImage
矩形(TaW 代码中的 ImgArea
),那么两种转换(到控件的坐标以及图像的列和行)都非常简单:
/// <summary>
/// Converts coordinates of a point from the picture box grid into column and row of its image.
/// </summary>
/// <param name="pb">The PictureBox.</param>
/// <param name="ptControl">The point in picture box coordinates (X, Y).</param>
/// <returns>Point in image coordinates (column, row).</returns>
private Point ToImageCoordinates(PictureBox pb, Point ptControl)
{
if (pb.Image == null)
{
return new Point(Int32.MinValue, Int32.MinValue);
}
float deltaX = ptControl.X - rectImage.Left;
float deltaY = ptControl.Y - rectImage.Top;
int column = (int)(deltaX * (pb.Image.Width / rectImage.Width) + 0.5);
int row = (int)(deltaY * (pb.Image.Height / rectImage.Height) + 0.5);
return new Point(column, row);
}
/// <summary>
/// Converts coordinates of a point from the grid (column, row) into the coordinate system of the picture box.
/// </summary>
/// <param name="pb">The PictureBox.</param>
/// <param name="ptImage">The point in image coordinates (column, row).</param>
/// <returns>Point in control coordinates (X, Y).</returns>
private PointF ToControlCoordinates(PictureBox pb, Point ptImage)
{
if (pb.Image == null)
{
return new Point(Int32.MinValue, Int32.MinValue);
}
float deltaX = ptImage.X * (rectImage.Width / pb.Image.Width);
float deltaY = ptImage.Y * (rectImage.Height / pb.Image.Height);
return new PointF(deltaX + rectImage.Left, deltaY + rectImage.Top);
}
这些功能已经过测试,似乎可以正常工作。
记住:这些转换仅在 PictureBox 处于 Zoom
模式时有效。