Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

c# - Draw Rectangle inside picture box SizeMode Zoom

I have a picture box in a WindowsForms project with its SizeMode to "Zoom".

I want to draw a rectangle inside image and get its coordinates relative to the image and not to the picture box.

The problem is that the rectangle's coordinates do not match with the same rectangle selected on Windows Paint Application.

Here is the code used:

  1. Start Painting:

    /// <summary>
    /// Starts drawing.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        backupImage = pictureBox1.Image;
        _once = true;
        RectStartPoint = e.Location;
        pictureBox1.Invalidate();
    }
    
  2. While moving mouse:

    /// <summary>
    /// While moving mouse event, paint rectangle
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (_once) //Only draw rectangle while drawing mode
        {
            Point tempEndPoint = e.Location;
            Rect.Location = new Point(Math.Min(RectStartPoint.X, tempEndPoint.X),
                Math.Min(RectStartPoint.Y, tempEndPoint.Y));
    
            Rect = new Rectangle(
                Math.Min(tempEndPoint.X, Rect.Left),
                Math.Min(tempEndPoint.Y, Rect.Top),
                Math.Min(e.X - RectStartPoint.X, pictureBox1.ClientRectangle.Width - RectStartPoint.X),
                Math.Min(e.Y - RectStartPoint.Y, pictureBox1.ClientRectangle.Height - RectStartPoint.Y));
    
            pictureBox1.Refresh();
            pictureBox1.CreateGraphics().DrawRectangle(cropPen, Rect);
        }
    }
    
  3. When 2 click, finhish painting rectange:

    /// <summary>
    /// When mouse click is released, write in texbox the rectangle's coordinates.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (_once)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                Point tempEndPoint = e.Location;
    
                _once = false;
                string sAux = string.Format("Left: {0}; Top: {1}; Width: {2}; Height: {3} 
    ", Math.Min(tempEndPoint.X, Rect.Left), Math.Min(tempEndPoint.Y, Rect.Top),
                        Math.Min(e.X - RectStartPoint.X, pictureBox1.ClientRectangle.Width - RectStartPoint.X), Math.Min(e.Y - RectStartPoint.Y, pictureBox1.ClientRectangle.Height - RectStartPoint.Y));
    
                textBox1.Text += sAux;
            }
        }
    }
    

The results are:

Windows Image Windows Image

Paint Image enter image description here

As you can see on both images, left, top, width and height do not match.

Can you tell me how to obtain the same result?

Example2

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a function to help with various calculations:

void SetImageScale(PictureBox pbox, out RectangleF ImgArea, out float zoom)
{
    SizeF sp = pbox.ClientSize;
    SizeF si = pbox.Image.Size;
    float rp = sp.Width / sp.Height;   // calculate the ratios of
    float ri = si.Width / si.Height;   // pbox and image

    if (rp > ri)
    {
        zoom = 1f * sp.Height / si.Height;
        float width = si.Width * zoom;
        float left = (sp.Width - width) / 2;
        ImgArea = new RectangleF(left, 0, width, sp.Height);
    }
    else
    {
        zoom = 1f * sp.Width / si.Width;
        float height = si.Height * zoom;
        float top = (sp.Height - height) / 2;
        ImgArea = new RectangleF(0, top, sp.Width, height);
    }
}

Here is how you can use it, given a Rectangle Rect which you created from the mouse coordinates:

float zoom = 1f;
RectangleF ImgArea = Rectangle.Empty;

SetImageScale(pictureBox1, out ImgArea, out zoom);

Point RLoc = Point.Round(new PointF( (Rect.X - ImgArea.X) / zoom, 
                                     (Rect.Y - ImgArea.Y) / zoom ));
Size RSz = Size.Round(new SizeF(Rect.Width / zoom, Rect.Height / zoom));

label1.Text =  "Selection in mouse coordinates: "  + Rect.ToString();
label2.Text =  "Selection in image coordinates: "  + new Rectangle(RLoc, RSz).ToString();

This should work no matter whether the images are landscape or portrait or which ratio if any is greater, the Image's or the PictureBox's.

enter image description here

Note that with the images strongly zoomed it is hard to do a pixel-pefect selection..

The function is variant of the one in this post.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...