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. .NET (Core and Framework)
  4. How to shift a bitmap efficiently (Spectrogram Application) [modified]

How to shift a bitmap efficiently (Spectrogram Application) [modified]

Scheduled Pinned Locked Moved .NET (Core and Framework)
graphicsc++winformsgame-devperformance
16 Posts 2 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.
  • B bimbambumbum

    Hi Luc Thanks for your reply - once more....you are a fast responder :) 1. My matrix is not really a matrix but just an array of bytes of size [3*bitmap.height*bitmap.width] so by the 3 term this should correspond to 24bit but less resolution will be ok for the final application. I want to insert the 20*log10(abs(FFT-bins/2) into each column of the bitmap (FFT-bins/2 could be 256, 512 or 1024). Yes I can define the producer type/format myself. Grayscale is probably fine. "..Trace in the image" - can you elaborate? 2. OK, I'm starting to understand now. 3. Yes I get the point. I just read that scrollWindow might be what I'm looking as it offers horizontal shifting by a pixel which is basically what I'm looking for. You know of this method? 4. Image size could be up to 1024x1024. Update frequency is likely to be around 25Hz. I can share the code if you are interested but I'm thinking you can do a much better job than me. 5. There is another spectrum analyzis tool I'm thinking of adding to my application. Maybe that can beef up your article if you are interested. Thx Tom

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

    If I understand correctly, you have at most a 1024*1024 color image, that is scrolling horizontally and gets up to 25 columns added per second, with a producer you control. That should not be any problem. Yes, I think I have used ScrollWindows in the dark ages of Win32, I wouldn't need it in .NET I would consider a Control (say a Panel) that would show a Bitmap and accept a columnar data update. Give me 24 hours, I'll experiment a bit in C#, and get back to you. What would you want for initial content? axes? grid lines? legend? BTW: I found a plotting graph here: High Speed, Feature Rich, and Easy-To-Use Graphs and Charts[^]. Haven't looked inside yet. :)

    Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

    Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

    B 1 Reply Last reply
    0
    • L Luc Pattyn

      If I understand correctly, you have at most a 1024*1024 color image, that is scrolling horizontally and gets up to 25 columns added per second, with a producer you control. That should not be any problem. Yes, I think I have used ScrollWindows in the dark ages of Win32, I wouldn't need it in .NET I would consider a Control (say a Panel) that would show a Bitmap and accept a columnar data update. Give me 24 hours, I'll experiment a bit in C#, and get back to you. What would you want for initial content? axes? grid lines? legend? BTW: I found a plotting graph here: High Speed, Feature Rich, and Easy-To-Use Graphs and Charts[^]. Haven't looked inside yet. :)

      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

      Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

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

      Hi Luc, Sounds cool! looking forward to see what you come up with. For the spectrogram I wouldn't worry about axis for my app but if you want to write an article you might want to put a frequency and time axis and possible a colorbar which maps the spectrogram colors to an intensity for the frequency components. Let me know if I can contribute in any way...going to bed know Thx Tom

      1 Reply Last reply
      0
      • B bimbambumbum

        Hi I'm working on a Spectrum analyzer application and need some help to get the graphics updated in an optimal manner. Whenever my program receives a new block of audio data I do an FFT and I then update the oldest FFT data (a column) in my 2D-matrix which is then copied to a bitmap for display. So this spectrogram is shifted horizontally as data arrives in blocks. I see two options for achieving the shifting of the NxM bitmap whenever a new FFT output block arrives: 1. Copy columns [0:M-2] to [1:M-1] and then copy in the new FFT data...hope the notation makes sense. This requires a lot of memory copying and I hope to avoid that using GDI. 2. Replace the "oldest" column (the matrix works as a circular buffer in the time-direction) and let GDI ensure that when wrap-around happens GDI the remaining columns (the columns up to the column where the new FFT data resides) are copied to the bitmap. I once did a spectrum Analyzer in C++ project using OpenGL that supports this functionality. Can find the project anymore..I tried to look for it to find the name of the instruction used. Does GDI/GDI+ support this? Do any of you guys know how I get to do this efficiently? Thx Tom

        modified on Sunday, September 19, 2010 8:00 PM

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

        Hi Tom, 1. I studied the article High Speed, Feature Rich, and Easy-To-Use Graphs and Charts[^] a bit; it has a Plotter class which is a UserControl displaying a number of traces, each trace defined as a sequence of points. So there is no bitmap, no image, involved at all. It basically is vector graphics, which makes it high-performance. 2. I did some experiments with a bitmap-based plotter-like Panel, where one column of pixels would be updated at a time, using the circular buffer approach we discussed earlier. It is double-buffered to avoid flickering, and it works remarkably smooth, in fact it looks much better than the other article's demo, however I suspect that is due to the demo having fewer data points than the plotter is wide, causing the graph to jump all the time. At 512*512 my plotter happily handles 30 updates (frames) per second, using between 10 and 15% of a middle-of-the-road dual-core (I use both cores, as one executes the main thread, i.e. the painting, whereas the other calculates the new column in a BackgroundWorker). Yet I am convinced it takes too much CPU load for the net result. So I think I should look into other technologies, being OpenGL and DirectX. And I will, in time. 3. For the moment, I'm convinced if all that gets shown basically is a line graph, one should not resort to images at all. It will be much more lightweight when the graphs are drawn straight from a sequence of points, no matter what technology is used for painting images. ADDED Of course, when doing so, there is no problem whatsoever to make it scroll. /ADDED :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

        Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

        modified on Monday, September 20, 2010 10:43 PM

        B 1 Reply Last reply
        0
        • L Luc Pattyn

          Hi Tom, 1. I studied the article High Speed, Feature Rich, and Easy-To-Use Graphs and Charts[^] a bit; it has a Plotter class which is a UserControl displaying a number of traces, each trace defined as a sequence of points. So there is no bitmap, no image, involved at all. It basically is vector graphics, which makes it high-performance. 2. I did some experiments with a bitmap-based plotter-like Panel, where one column of pixels would be updated at a time, using the circular buffer approach we discussed earlier. It is double-buffered to avoid flickering, and it works remarkably smooth, in fact it looks much better than the other article's demo, however I suspect that is due to the demo having fewer data points than the plotter is wide, causing the graph to jump all the time. At 512*512 my plotter happily handles 30 updates (frames) per second, using between 10 and 15% of a middle-of-the-road dual-core (I use both cores, as one executes the main thread, i.e. the painting, whereas the other calculates the new column in a BackgroundWorker). Yet I am convinced it takes too much CPU load for the net result. So I think I should look into other technologies, being OpenGL and DirectX. And I will, in time. 3. For the moment, I'm convinced if all that gets shown basically is a line graph, one should not resort to images at all. It will be much more lightweight when the graphs are drawn straight from a sequence of points, no matter what technology is used for painting images. ADDED Of course, when doing so, there is no problem whatsoever to make it scroll. /ADDED :)

          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

          Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

          modified on Monday, September 20, 2010 10:43 PM

          B Offline
          B Offline
          bimbambumbum
          wrote on last edited by
          #9

          Hi Luc Glad to hear you are in good progress. I will take a look at the article you are refering to. I've advanced a bit tonight myself because the spectrogram is now up running. I'm currently using drawImage() which seems to do well. My laptop (Lenovo T61p) uses about 20% of it's resources but the app also does FFTs 50 times a second and computes the log-spectrum of these FFT outputs which costs a little too so I'm pretty impressed with the GDI performance. Even though I running double-buffering I still think my 768x1024 pixel spectrogram does some flickering..do you have a way to get rid of this? Also, I need an efficient way of mapping from FFT log-outputs to a colorrange...you know of an easy way of doing this? Sorry for all the question...I have a lot to learn with .NET (and programming in general besides Matlab) Addition: I guess the flickering comes because I'm manipulating the bitmap directly and not bitmapdata. If that is the case maybe drawimage is not such a good option???? Thx Thomas

          modified on Tuesday, September 21, 2010 12:09 AM

          L 2 Replies Last reply
          0
          • B bimbambumbum

            Hi Luc Glad to hear you are in good progress. I will take a look at the article you are refering to. I've advanced a bit tonight myself because the spectrogram is now up running. I'm currently using drawImage() which seems to do well. My laptop (Lenovo T61p) uses about 20% of it's resources but the app also does FFTs 50 times a second and computes the log-spectrum of these FFT outputs which costs a little too so I'm pretty impressed with the GDI performance. Even though I running double-buffering I still think my 768x1024 pixel spectrogram does some flickering..do you have a way to get rid of this? Also, I need an efficient way of mapping from FFT log-outputs to a colorrange...you know of an easy way of doing this? Sorry for all the question...I have a lot to learn with .NET (and programming in general besides Matlab) Addition: I guess the flickering comes because I'm manipulating the bitmap directly and not bitmapdata. If that is the case maybe drawimage is not such a good option???? Thx Thomas

            modified on Tuesday, September 21, 2010 12:09 AM

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

            bimbambumbum wrote:

            .do you have a way to get rid of this?

            yes. do it correctly. and no. there is no perfect solution, switching from one image to the next always takes a finite amount of time, it is a matter of getting it minimal. you will not see flickering when the repaint time is small compared to the steady time. I suggest you show the relevant code.

            bimbambumbum wrote:

            mapping from FFT log-outputs to a colorrange

            technically, have an array of colors, one for each integer in a limited range of possible values (if need be, divide by some constant so only say 256 colors remain). esthetically, whatever you like. You could create a hue-wig, i.e. all colors with same (probably max) saturation and brightness but different hue values. :)

            Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

            Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

            B 1 Reply Last reply
            0
            • B bimbambumbum

              Hi Luc Glad to hear you are in good progress. I will take a look at the article you are refering to. I've advanced a bit tonight myself because the spectrogram is now up running. I'm currently using drawImage() which seems to do well. My laptop (Lenovo T61p) uses about 20% of it's resources but the app also does FFTs 50 times a second and computes the log-spectrum of these FFT outputs which costs a little too so I'm pretty impressed with the GDI performance. Even though I running double-buffering I still think my 768x1024 pixel spectrogram does some flickering..do you have a way to get rid of this? Also, I need an efficient way of mapping from FFT log-outputs to a colorrange...you know of an easy way of doing this? Sorry for all the question...I have a lot to learn with .NET (and programming in general besides Matlab) Addition: I guess the flickering comes because I'm manipulating the bitmap directly and not bitmapdata. If that is the case maybe drawimage is not such a good option???? Thx Thomas

              modified on Tuesday, September 21, 2010 12:09 AM

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

              bimbambumbum wrote:

              I'm manipulating the bitmap directly

              so do I. The alternative with LockBits prevents multi-threading, i.e. you can no longer have concurrent image updates and image repaints by different threads. However, SetPixel() is a very slow method. My test does two DrawLine() to update one column (one full-height background, one foreground). :)

              Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

              Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

              B 1 Reply Last reply
              0
              • L Luc Pattyn

                bimbambumbum wrote:

                .do you have a way to get rid of this?

                yes. do it correctly. and no. there is no perfect solution, switching from one image to the next always takes a finite amount of time, it is a matter of getting it minimal. you will not see flickering when the repaint time is small compared to the steady time. I suggest you show the relevant code.

                bimbambumbum wrote:

                mapping from FFT log-outputs to a colorrange

                technically, have an array of colors, one for each integer in a limited range of possible values (if need be, divide by some constant so only say 256 colors remain). esthetically, whatever you like. You could create a hue-wig, i.e. all colors with same (probably max) saturation and brightness but different hue values. :)

                Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

                Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

                B Offline
                B Offline
                bimbambumbum
                wrote on last edited by
                #12

                Hi Luc Here is the core of my bitmap shifting. If you run it you can see that the shifting flickers a little and I would like to avoid that. Hope you have a simple way of getting rid of the flickering. Sorry for the messy code....Mind you I'm a newbie :)

                using System;
                using System.Collections.Generic;
                using System.ComponentModel;
                using System.Data;
                using System.Drawing;
                using System.Drawing.Drawing2D;
                using System.Drawing.Imaging;
                using System.Linq;
                using System.Text;
                using System.Windows.Forms;
                using System.Runtime.InteropServices;
                using fftwlib;

                namespace GDI_evaluation
                {
                public partial class Form1 : Form
                {
                Timer timer = new Timer();
                Graphics g;

                    int XREF = 50;
                    int YREF = 50;
                
                    // Bitmap
                    Bitmap myBitmap;
                    Random rnd;
                    int tIndx = 0;
                
                    public Form1()
                    {
                        InitializeComponent();
                
                        rnd = new Random();
                
                        this.SetStyle(
                       ControlStyles.UserPaint |
                       ControlStyles.AllPaintingInWmPaint |
                       ControlStyles.OptimizedDoubleBuffer, true);
                
                        myBitmap = new Bitmap(768, 512, PixelFormat.Format24bppRgb);
                
                        timer.Tick += new EventHandler(timer\_tick);
                        timer.Interval = 1000 / 25;      // opdater grafik 50 /sekund!!!
                        timer.Enabled = true;
                        timer.Start();
                    }
                
                    void timer\_tick(object sender, EventArgs e)
                    {
                        this.Refresh(); // Update GUI
                    }
                
                    private void Form1\_Paint(object sender, PaintEventArgs e)
                    {
                    }
                
                    protected override void OnPaint(PaintEventArgs pe)
                    {
                        g = pe.Graphics;
                
                        Rectangle block1 = new Rectangle(XREF + tIndx, YREF, myBitmap.Width - tIndx, myBitmap.Height);
                        g.DrawImage(myBitmap, block1, 0, 0, myBitmap.Width - tIndx, myBitmap.Height, GraphicsUnit.Pixel);
                        Rectangle block2 = new Rectangle(XREF, YREF, tIndx, myBitmap.Height);
                        g.DrawImage(myBitmap, block2, myBitmap.Width - tIndx, 0, tIndx, myBitmap.Height, GraphicsUnit.Pixel);
                
                
                        int tIndx2 = tIndx - 1;
                        if (tIndx2 < 0)
                            tIndx2 = myBitmap.Width - 1;
                
                        // Insert new FFT data
                        for (int ii = 0; ii < myBitmap.Height; ii++)
                            myBitmap.SetPixel(myBitmap.Width - 1 - tIndx2, ii, Color.FromArgb(rnd.Next(255), rnd.Next(255), rnd.Next(255)));
                
                        if (++tIndx == myBitmap.Width)
                
                L 1 Reply Last reply
                0
                • B bimbambumbum

                  Hi Luc Here is the core of my bitmap shifting. If you run it you can see that the shifting flickers a little and I would like to avoid that. Hope you have a simple way of getting rid of the flickering. Sorry for the messy code....Mind you I'm a newbie :)

                  using System;
                  using System.Collections.Generic;
                  using System.ComponentModel;
                  using System.Data;
                  using System.Drawing;
                  using System.Drawing.Drawing2D;
                  using System.Drawing.Imaging;
                  using System.Linq;
                  using System.Text;
                  using System.Windows.Forms;
                  using System.Runtime.InteropServices;
                  using fftwlib;

                  namespace GDI_evaluation
                  {
                  public partial class Form1 : Form
                  {
                  Timer timer = new Timer();
                  Graphics g;

                      int XREF = 50;
                      int YREF = 50;
                  
                      // Bitmap
                      Bitmap myBitmap;
                      Random rnd;
                      int tIndx = 0;
                  
                      public Form1()
                      {
                          InitializeComponent();
                  
                          rnd = new Random();
                  
                          this.SetStyle(
                         ControlStyles.UserPaint |
                         ControlStyles.AllPaintingInWmPaint |
                         ControlStyles.OptimizedDoubleBuffer, true);
                  
                          myBitmap = new Bitmap(768, 512, PixelFormat.Format24bppRgb);
                  
                          timer.Tick += new EventHandler(timer\_tick);
                          timer.Interval = 1000 / 25;      // opdater grafik 50 /sekund!!!
                          timer.Enabled = true;
                          timer.Start();
                      }
                  
                      void timer\_tick(object sender, EventArgs e)
                      {
                          this.Refresh(); // Update GUI
                      }
                  
                      private void Form1\_Paint(object sender, PaintEventArgs e)
                      {
                      }
                  
                      protected override void OnPaint(PaintEventArgs pe)
                      {
                          g = pe.Graphics;
                  
                          Rectangle block1 = new Rectangle(XREF + tIndx, YREF, myBitmap.Width - tIndx, myBitmap.Height);
                          g.DrawImage(myBitmap, block1, 0, 0, myBitmap.Width - tIndx, myBitmap.Height, GraphicsUnit.Pixel);
                          Rectangle block2 = new Rectangle(XREF, YREF, tIndx, myBitmap.Height);
                          g.DrawImage(myBitmap, block2, myBitmap.Width - tIndx, 0, tIndx, myBitmap.Height, GraphicsUnit.Pixel);
                  
                  
                          int tIndx2 = tIndx - 1;
                          if (tIndx2 < 0)
                              tIndx2 = myBitmap.Width - 1;
                  
                          // Insert new FFT data
                          for (int ii = 0; ii < myBitmap.Height; ii++)
                              myBitmap.SetPixel(myBitmap.Width - 1 - tIndx2, ii, Color.FromArgb(rnd.Next(255), rnd.Next(255), rnd.Next(255)));
                  
                          if (++tIndx == myBitmap.Width)
                  
                  L Offline
                  L Offline
                  Luc Pattyn
                  wrote on last edited by
                  #13

                  Hi, I did not run your code, I have some comments just by looking at it: 1. you paint onto your Form, I always avoid that. I prefer adding a Panel to the Form, then painting to the Panel. Make the Panel the exact size of the plot, and make the Panel double-buffered, not the entire Form. ADDED and only repaint (i.e. Invalidate or Refresh) the panel. /ADDED 2. I see you modify your data inside OnPaint; one should not do that, as OnPaint may be called by the system whenever it feels a need (e.g. when an unrelated window gets shown, then disappears, uncovering your window). 3. you should use a local variable to store the value of myBitmap.Height, and not call any unnecessary property inside a loop; it will typically not be optimized away! 4.

                  bimbambumbum wrote:

                  opdater grafik 50 /sekund!!!

                  ? :)

                  Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

                  Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

                  modified on Tuesday, September 21, 2010 5:58 PM

                  B 1 Reply Last reply
                  0
                  • L Luc Pattyn

                    Hi, I did not run your code, I have some comments just by looking at it: 1. you paint onto your Form, I always avoid that. I prefer adding a Panel to the Form, then painting to the Panel. Make the Panel the exact size of the plot, and make the Panel double-buffered, not the entire Form. ADDED and only repaint (i.e. Invalidate or Refresh) the panel. /ADDED 2. I see you modify your data inside OnPaint; one should not do that, as OnPaint may be called by the system whenever it feels a need (e.g. when an unrelated window gets shown, then disappears, uncovering your window). 3. you should use a local variable to store the value of myBitmap.Height, and not call any unnecessary property inside a loop; it will typically not be optimized away! 4.

                    bimbambumbum wrote:

                    opdater grafik 50 /sekund!!!

                    ? :)

                    Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

                    Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

                    modified on Tuesday, September 21, 2010 5:58 PM

                    B Offline
                    B Offline
                    bimbambumbum
                    wrote on last edited by
                    #14

                    Hi Luc Thanks for your comments. I get your points - I think :) Will try to follow your recipe when I have time tomorrow. If you have an example I can steal from that would be great... Thanks Thomas

                    1 Reply Last reply
                    0
                    • L Luc Pattyn

                      bimbambumbum wrote:

                      I'm manipulating the bitmap directly

                      so do I. The alternative with LockBits prevents multi-threading, i.e. you can no longer have concurrent image updates and image repaints by different threads. However, SetPixel() is a very slow method. My test does two DrawLine() to update one column (one full-height background, one foreground). :)

                      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

                      Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

                      B Offline
                      B Offline
                      bimbambumbum
                      wrote on last edited by
                      #15

                      One last thing... Will my spectrogram shift more smoothly if I do it the panel way? Cheers Tom

                      L 1 Reply Last reply
                      0
                      • B bimbambumbum

                        One last thing... Will my spectrogram shift more smoothly if I do it the panel way? Cheers Tom

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

                        My plotting Panel is perfectly smooth, however I can't compare, I never do it the Form way, as 1) it isn't really object-oriented 2) too many things probably are going on with Forms. :)

                        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

                        Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

                        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