0

What is the most efficient way to go from a System.Drawing.Bitmap (of any format, not a specific one) to a int[] in the form of R G B R G B R G B etc? I don't want the bitmap data in the format it actually is laid out in memory (no stride, no padding, no nothing) but i'm not sure as to what's the fastest way to go from bitmap to what i need, obviously getpixel isn't the way as it is really slow, any advice is welcome.

Additional libraries are not an option, anything .net is fair game however (including .net 4.6 / VS 2015 RC)

edit : 3 arrays (one per channel) is fine too althought i assume this wouldn't be faster to retrieve.

Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78
  • Does this help: http://stackoverflow.com/questions/4747428/getting-rgb-array-from-image-in-c-sharp ? – Rahul Tripathi May 31 '15 at 10:27
  • Not really as it's making assumtions about the image pixelformat argb24 and thus about the pixelwidth – Ronan Thibaudau May 31 '15 at 10:29
  • What have you tried? There's lots of Q&As about this subject. Try searching. – CodeCaster May 31 '15 at 10:33
  • Nothing as my question is not "help me i have no clue how to do this" but "what is the fastest way to do it" . I don't need help fixing my code, i need pointers as to what would be the fastest solution – Ronan Thibaudau May 31 '15 at 10:34
  • It's not clear where your requirements come from, but probably an ARGB24 `byte[]` will be easier and quicker to get than a RGB `int[]`... – pid May 31 '15 at 10:40
  • It's a waste of space but that would be fine too i can afford the space, i just need it to be fast – Ronan Thibaudau May 31 '15 at 10:41
  • It's not a waste of space. 1 pixel in ARGB24 takes 4 bytes. The same pixel in 3 `int` channels (R, G and B integers) takes away 3 integers (32 bits each). That's 12 bytes per pixel. The `int[]`-way will take 3 times as much space and probably any algorithm processing it will require 3 times as much time, too. The ARGB24 `byte[]` also is the fastest solution because **most** (not all) hardware already gives you that natively. – pid May 31 '15 at 10:44
  • Look here: http://stackoverflow.com/questions/7350679/convert-a-bitmap-into-a-byte-array That pretty much sums up all possible ways. And don't be afraid about performance now, just implement it and **measure** how fast it actually is. Only then bother about performance and compare different solutions. – pid May 31 '15 at 10:47
  • No wether it is rgb or argb i need to switch it to int from byte afterward (many operations on it requiring more precision) but that's out of the scope of this question, what i meant is i have no need for the A component so it's an annoyance to get it, but if it's fastet that's fine. All that matters in my use case is raw performance and getting a rgb or rgba array, if it's bytes instead of ints that's fine. – Ronan Thibaudau May 31 '15 at 10:48
  • I need to worry about performance now for my use case, this isn't premature optimisation. In my scenario even saving a couple milliseconds is significant, i voluntarily did not describe this because i don't want the answers to get out of scope. My actual functional and end requirement is "how to get a rgb or rgba array in the fastest possible way out of an arbitrary System.Drawing.Bitmap". Nothing more, nothing less – Ronan Thibaudau May 31 '15 at 10:51
  • Ok, I get your point and all you say. Just one thing that is obvious but I want to say it nonetheless :) Don't convert the `byte[]` to `int[]` separately. Just take the bytes and cast them to `int` in your algorithm so you convert them for precision **on the fly**. That will be way faster than converting the data beforehand. – pid May 31 '15 at 10:57
  • I'm chaining operations and need to keep all the intermediate arrays, so wether i start from a byte or int array is pretty irrelevant as the array isn't getting reused, in the end the second and later steps still end up being int arrays – Ronan Thibaudau May 31 '15 at 10:58

1 Answers1

0

Maybe this code could help you:

            unsafe public SimpleRGBImage(Bitmap bmp)
            {
                data = new byte[bmp.Width, bmp.Height, 3];

                BitmapData bmpData = new BitmapData();

                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

                bmpData = bmp.LockBits(rect,
                    ImageLockMode.ReadOnly,
                    PixelFormat.Format24bppRgb);

                byte* Scan0 = (byte*)bmpData.Scan0.ToPointer();

                int size = bmp.Width * bmp.Height * 3;

                for (int i=0; i<size-1; i++)
                {
                    data[i % bmp.Width, i % bmp.Height, i % 3] = *(Scan0++);
                }

                bmp.UnlockBits(bmpData);
            }
emilim
  • 109
  • 7