Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Memory expensive rubber band selection?

Memory expensive rubber band selection?

Scheduled Pinned Locked Moved C#
graphicsquestionperformance
13 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Chesnokov Yuriy
    wrote on last edited by
    #1

    What is the reason of memory consumption in the DrawRoi function leading to hundreds of Mb? There is a Frame bitmap and its FrameWithRoi copy to assign to PictureBox. On the mouse move event new ROI coords are estimated and DrawRoi() is called.

    DrawRoi()
    {
    RectangleF roi = Roi;

    RectangleF rect = new RectangleF()
    {
    X = (float)Frame.Width * roi.X,
    Y = (float)Frame.Height * roi.Y,
    Width = (float)Frame.Width * roi.Width,
    Height = (float)Frame.Height * roi.Height
    };

    // draw roi if it is smaller than the whole image
    if (rect.Left > 0 || rect.Right < (float)FrameWithRoi.Width ||
    rect.Top > 0 || rect.Bottom < (float)FrameWithRoi.Height)
    {
    Graphics g = Graphics.FromImage(FrameWithRoi);
    g.DrawImage(Frame, 0, 0);
    using (Bitmap region = new Bitmap(FrameWithRoi.Width, FrameWithRoi.Height, FrameWithRoi.PixelFormat))
    {
    Graphics roi_g = Graphics.FromImage(region);
    roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
    roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
    region.MakeTransparent(Color.Red);
    g.DrawImage(region, 0, 0);
    }
    }

    this.framePictureBox.Image = FrameWithRoi;
    }

    Чесноков

    B L _ 3 Replies Last reply
    0
    • C Chesnokov Yuriy

      What is the reason of memory consumption in the DrawRoi function leading to hundreds of Mb? There is a Frame bitmap and its FrameWithRoi copy to assign to PictureBox. On the mouse move event new ROI coords are estimated and DrawRoi() is called.

      DrawRoi()
      {
      RectangleF roi = Roi;

      RectangleF rect = new RectangleF()
      {
      X = (float)Frame.Width * roi.X,
      Y = (float)Frame.Height * roi.Y,
      Width = (float)Frame.Width * roi.Width,
      Height = (float)Frame.Height * roi.Height
      };

      // draw roi if it is smaller than the whole image
      if (rect.Left > 0 || rect.Right < (float)FrameWithRoi.Width ||
      rect.Top > 0 || rect.Bottom < (float)FrameWithRoi.Height)
      {
      Graphics g = Graphics.FromImage(FrameWithRoi);
      g.DrawImage(Frame, 0, 0);
      using (Bitmap region = new Bitmap(FrameWithRoi.Width, FrameWithRoi.Height, FrameWithRoi.PixelFormat))
      {
      Graphics roi_g = Graphics.FromImage(region);
      roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
      roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
      region.MakeTransparent(Color.Red);
      g.DrawImage(region, 0, 0);
      }
      }

      this.framePictureBox.Image = FrameWithRoi;
      }

      Чесноков

      B Offline
      B Offline
      BobJanova
      wrote on last edited by
      #2

      Two things strike me immediately: - you are not disposing of the graphics objects you obtain. This might actually be a resource leak. - you create a new RectangleF every time (though I think this is a value type, so it shouldn't matter). It's also possible that the bitmap doesn't get garbage collected immediately, even though it is being disposed of at the end of the using. But it should do.

      C 1 Reply Last reply
      0
      • B BobJanova

        Two things strike me immediately: - you are not disposing of the graphics objects you obtain. This might actually be a resource leak. - you create a new RectangleF every time (though I think this is a value type, so it shouldn't matter). It's also possible that the bitmap doesn't get garbage collected immediately, even though it is being disposed of at the end of the using. But it should do.

        C Offline
        C Offline
        Chesnokov Yuriy
        wrote on last edited by
        #3

        Yes, disposing graphics objects solved the problem. But why the drawing is very slow? The larger the image the slower update.

        Чесноков

        1 Reply Last reply
        0
        • C Chesnokov Yuriy

          What is the reason of memory consumption in the DrawRoi function leading to hundreds of Mb? There is a Frame bitmap and its FrameWithRoi copy to assign to PictureBox. On the mouse move event new ROI coords are estimated and DrawRoi() is called.

          DrawRoi()
          {
          RectangleF roi = Roi;

          RectangleF rect = new RectangleF()
          {
          X = (float)Frame.Width * roi.X,
          Y = (float)Frame.Height * roi.Y,
          Width = (float)Frame.Width * roi.Width,
          Height = (float)Frame.Height * roi.Height
          };

          // draw roi if it is smaller than the whole image
          if (rect.Left > 0 || rect.Right < (float)FrameWithRoi.Width ||
          rect.Top > 0 || rect.Bottom < (float)FrameWithRoi.Height)
          {
          Graphics g = Graphics.FromImage(FrameWithRoi);
          g.DrawImage(Frame, 0, 0);
          using (Bitmap region = new Bitmap(FrameWithRoi.Width, FrameWithRoi.Height, FrameWithRoi.PixelFormat))
          {
          Graphics roi_g = Graphics.FromImage(region);
          roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
          roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
          region.MakeTransparent(Color.Red);
          g.DrawImage(region, 0, 0);
          }
          }

          this.framePictureBox.Image = FrameWithRoi;
          }

          Чесноков

          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          Graphics objects are expensive, and you should dispose them. Why not use a using statement, just like you did for the region Bitmap? And why would you need two Graphics instances, and a DrawImage()? Couldn't you just use the Bitmap(Image) constructor, and have its Graphics, just the one? :)

          Luc Pattyn [My Articles] Nil Volentibus Arduum

          The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
          Please use <PRE> tags for code snippets, they improve readability.
          CP Vanity has been updated to V2.3

          C 1 Reply Last reply
          0
          • L Luc Pattyn

            Graphics objects are expensive, and you should dispose them. Why not use a using statement, just like you did for the region Bitmap? And why would you need two Graphics instances, and a DrawImage()? Couldn't you just use the Bitmap(Image) constructor, and have its Graphics, just the one? :)

            Luc Pattyn [My Articles] Nil Volentibus Arduum

            The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
            Please use <PRE> tags for code snippets, they improve readability.
            CP Vanity has been updated to V2.3

            C Offline
            C Offline
            Chesnokov Yuriy
            wrote on last edited by
            #5

            I was looking for a way to darken non ROI region in the image. You optimizations would be welcomed. Why the picture box update is very slow if I keep drawing on every mouse move event?

            Чесноков

            L B P L 4 Replies Last reply
            0
            • C Chesnokov Yuriy

              I was looking for a way to darken non ROI region in the image. You optimizations would be welcomed. Why the picture box update is very slow if I keep drawing on every mouse move event?

              Чесноков

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              Mouse-move events are fired continuesly, and the drawing routine looks expensive. You might want to check whether the mouse has moved in the meantime, not redrawing if there's no movement detected.

              Bastard Programmer from Hell :suss:

              1 Reply Last reply
              0
              • C Chesnokov Yuriy

                I was looking for a way to darken non ROI region in the image. You optimizations would be welcomed. Why the picture box update is very slow if I keep drawing on every mouse move event?

                Чесноков

                B Offline
                B Offline
                BobJanova
                wrote on last edited by
                #7

                I recommend overlaying the semitransparent mask over the base image (either in OnPaint on the picture box or by placing another object over the top). Then all you have to redraw is the mask. Creating graphics objects is slow, which is why you should typically do it in OnPaint. In fact, in this case, you should do that, and your mouse move handler should only call Invalidate.

                1 Reply Last reply
                0
                • C Chesnokov Yuriy

                  I was looking for a way to darken non ROI region in the image. You optimizations would be welcomed. Why the picture box update is very slow if I keep drawing on every mouse move event?

                  Чесноков

                  P Offline
                  P Offline
                  Pete OHanlon
                  wrote on last edited by
                  #8

                  One other thing to bear in mind. The managed version of GDI+ is slow in comparison to the unmanaged version. You pay a price for the simplicity, and that price is speed.

                  Forgive your enemies - it messes with their heads

                  My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                  1 Reply Last reply
                  0
                  • C Chesnokov Yuriy

                    I was looking for a way to darken non ROI region in the image. You optimizations would be welcomed. Why the picture box update is very slow if I keep drawing on every mouse move event?

                    Чесноков

                    L Offline
                    L Offline
                    Luc Pattyn
                    wrote on last edited by
                    #9

                    Chesnokov Yuriy wrote:

                    Why the picture box update is very slow if I keep drawing on every mouse move event?

                    Because the MouseMove events fire at high frequency (allowing you to track well assuming your handler is fast), possibly 50Hz or higher (which is too high for the human eye to notice), because Graphics objects are expensive, and finally because PictureBoxes are stupid (I wouldn't be surprised if the fact you change the image just causes another mouse move event). You want to run such things continuously? I would experiment with keeping the two Graphics and the Bitmap around as class members, i.e. not create new objects at all, just keep using them over and over. :)

                    Luc Pattyn [My Articles] Nil Volentibus Arduum

                    The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
                    Please use <PRE> tags for code snippets, they improve readability.
                    CP Vanity has been updated to V2.3

                    C 1 Reply Last reply
                    0
                    • L Luc Pattyn

                      Chesnokov Yuriy wrote:

                      Why the picture box update is very slow if I keep drawing on every mouse move event?

                      Because the MouseMove events fire at high frequency (allowing you to track well assuming your handler is fast), possibly 50Hz or higher (which is too high for the human eye to notice), because Graphics objects are expensive, and finally because PictureBoxes are stupid (I wouldn't be surprised if the fact you change the image just causes another mouse move event). You want to run such things continuously? I would experiment with keeping the two Graphics and the Bitmap around as class members, i.e. not create new objects at all, just keep using them over and over. :)

                      Luc Pattyn [My Articles] Nil Volentibus Arduum

                      The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
                      Please use <PRE> tags for code snippets, they improve readability.
                      CP Vanity has been updated to V2.3

                      C Offline
                      C Offline
                      Chesnokov Yuriy
                      wrote on last edited by
                      #10

                      I need to implement rubber band like ROI selection in the image as in paint editor

                      Чесноков

                      1 Reply Last reply
                      0
                      • C Chesnokov Yuriy

                        What is the reason of memory consumption in the DrawRoi function leading to hundreds of Mb? There is a Frame bitmap and its FrameWithRoi copy to assign to PictureBox. On the mouse move event new ROI coords are estimated and DrawRoi() is called.

                        DrawRoi()
                        {
                        RectangleF roi = Roi;

                        RectangleF rect = new RectangleF()
                        {
                        X = (float)Frame.Width * roi.X,
                        Y = (float)Frame.Height * roi.Y,
                        Width = (float)Frame.Width * roi.Width,
                        Height = (float)Frame.Height * roi.Height
                        };

                        // draw roi if it is smaller than the whole image
                        if (rect.Left > 0 || rect.Right < (float)FrameWithRoi.Width ||
                        rect.Top > 0 || rect.Bottom < (float)FrameWithRoi.Height)
                        {
                        Graphics g = Graphics.FromImage(FrameWithRoi);
                        g.DrawImage(Frame, 0, 0);
                        using (Bitmap region = new Bitmap(FrameWithRoi.Width, FrameWithRoi.Height, FrameWithRoi.PixelFormat))
                        {
                        Graphics roi_g = Graphics.FromImage(region);
                        roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
                        roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
                        region.MakeTransparent(Color.Red);
                        g.DrawImage(region, 0, 0);
                        }
                        }

                        this.framePictureBox.Image = FrameWithRoi;
                        }

                        Чесноков

                        _ Offline
                        _ Offline
                        _Erik_
                        wrote on last edited by
                        #11

                        What I understand is that you are trying to darken a rectangle within a image, and that rectangle must be refreshed as long as the mouse is moving. Am I right? If this is what you want to do, the problem is that you are creating too many new Graphics and Bitmap objects in a very short time (and these are expensive objects), and updating the Image property a lot of times as well. The best way to do it is to subscribe to the Paint event of the control and code everything in this event handler, so you will receive a Graphics object as a parameter. In the next example there is only a PictureBox in the Form, called pct:

                        public partial class Form1 : Form
                        {
                        bool drawRect = false;
                        Rectangle r = new Rectangle();
                        Brush br = new SolidBrush(Color.FromArgb(50, Color.Red));

                        public Form1()
                        {
                            InitializeComponent();
                        }
                        
                        private void pct\_Paint(object sender, PaintEventArgs e)
                        {
                            if (drawRect)
                                e.Graphics.FillRectangle(br, r);
                        }
                        
                        private void pct\_MouseDown(object sender, MouseEventArgs e)
                        {
                            drawRect = true;
                            r.X = e.X;
                            r.Y = e.Y;
                        }
                        
                        private void pct\_MouseMove(object sender, MouseEventArgs e)
                        {
                            r.Width = e.X - r.X;
                            r.Height = e.Y - r.Y;
                        
                            Refresh();
                        }
                        
                        private void pct\_MouseUp(object sender, MouseEventArgs e)
                        {
                            drawRect = false;
                            Refresh();
                        }
                        

                        }

                        I've made it quick. You would have to modify it in order to draw the rectangle if the mouse moves to a lower X and/or lower Y coordinate.

                        C 1 Reply Last reply
                        0
                        • _ _Erik_

                          What I understand is that you are trying to darken a rectangle within a image, and that rectangle must be refreshed as long as the mouse is moving. Am I right? If this is what you want to do, the problem is that you are creating too many new Graphics and Bitmap objects in a very short time (and these are expensive objects), and updating the Image property a lot of times as well. The best way to do it is to subscribe to the Paint event of the control and code everything in this event handler, so you will receive a Graphics object as a parameter. In the next example there is only a PictureBox in the Form, called pct:

                          public partial class Form1 : Form
                          {
                          bool drawRect = false;
                          Rectangle r = new Rectangle();
                          Brush br = new SolidBrush(Color.FromArgb(50, Color.Red));

                          public Form1()
                          {
                              InitializeComponent();
                          }
                          
                          private void pct\_Paint(object sender, PaintEventArgs e)
                          {
                              if (drawRect)
                                  e.Graphics.FillRectangle(br, r);
                          }
                          
                          private void pct\_MouseDown(object sender, MouseEventArgs e)
                          {
                              drawRect = true;
                              r.X = e.X;
                              r.Y = e.Y;
                          }
                          
                          private void pct\_MouseMove(object sender, MouseEventArgs e)
                          {
                              r.Width = e.X - r.X;
                              r.Height = e.Y - r.Y;
                          
                              Refresh();
                          }
                          
                          private void pct\_MouseUp(object sender, MouseEventArgs e)
                          {
                              drawRect = false;
                              Refresh();
                          }
                          

                          }

                          I've made it quick. You would have to modify it in order to draw the rectangle if the mouse moves to a lower X and/or lower Y coordinate.

                          C Offline
                          C Offline
                          Chesnokov Yuriy
                          wrote on last edited by
                          #12

                          No, I need to darken the area outside rectangle. Consider ROI region. ROI remains clear and the area outside it is darked. I tried preinitialization of graphics and bitmaps and found that the problem part taking much of the time is:

                          ...
                          roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
                          roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
                          region.MakeTransparent(Color.Red);
                          g.DrawImage(region, 0, 0);
                          ...

                          Despite prinitialization it takes about 150ms

                          Чесноков

                          _ 1 Reply Last reply
                          0
                          • C Chesnokov Yuriy

                            No, I need to darken the area outside rectangle. Consider ROI region. ROI remains clear and the area outside it is darked. I tried preinitialization of graphics and bitmaps and found that the problem part taking much of the time is:

                            ...
                            roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
                            roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
                            region.MakeTransparent(Color.Red);
                            g.DrawImage(region, 0, 0);
                            ...

                            Despite prinitialization it takes about 150ms

                            Чесноков

                            _ Offline
                            _ Offline
                            _Erik_
                            wrote on last edited by
                            #13

                            Well, then, draw four rectangles around the area you want to keep clear. Just change the Paint event handler I posted before this way:

                            private void pct_Paint(object sender, PaintEventArgs e)
                            {
                            if (drawRect)
                            {
                            e.Graphics.FillRectangle(br, 0, 0, pct.Width, r.Y);
                            e.Graphics.FillRectangle(br, 0, r.Y, r.X, pct.Height);
                            e.Graphics.FillRectangle(br, r.X, r.Y + r.Height, pct.Width, pct.Height);
                            e.Graphics.FillRectangle(br, r.X + r.Width, r.Y, pct.Width, r.Height);
                            }
                            }

                            This will work pretty well. Do you also want to save the image after you have darkened the area?

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups