简体   繁体   中英

C# WindowsForms PictureBox: Transformation between control coordinates and pixel position in image

I have a control with a PictureBox within it. The PictureBox displays an image (in Zoom mode, at least in this particular case). I need to do two kinds of things:

  • Click with the mouse and find out which pixel of the image I hit
  • Draw a vertical line over the PictureBox at a given column in the image.

Obviously, I need some kind of coordinate transformations between the control coordinates and the (row, column) of the pixel in the image. The first one I may have found (www.codeproject.com/Articles/20923/Mouse-Position-over-Image-in-a-PictureBox), but not the vice versa. Any ideas?

I can suggest a "workaround": you do not draw lines etc. on the PictureBox, but, instead, on the bitmap itself, using its Graphics. Then you can only use the image coordinates (row, column) and do not need to convert from control to image. The other way round (from mouse click to row and column), as you mention, is solved and can be used.

After a few attempts to draw graphical elements on the bitmap rather than on containing PictureBox I found this approach clumsy: it poses more problems than it solves. I returned to TaW's proposal ( This Posting, function SetImageScale(PictureBox pbox, out RectangleF rectImage, out float zoom) .)

If you know the rectImage rectangle ( ImgArea in TaW's code), both conversions (to the control's coordinates and to the column and row of the image are then rather simple:

    /// <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);
    }

The functions were tested and seem to do what they should.

Remember : these conversions are only valid if the PictureBox is in the Zoom mode.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM