Iwanow said:
Thank you for that hint. Up to now, I've been using... ArrayLists to
store my data.
ArrayList stores System::Object^ managed handles. If you add an integer
value to an ArrayList, it wraps that value into a managed object. This
is called boxing. The C++/CLI compiler automatically generates code that
wraps your integer value into a garbage collected object. In the old
MC++, you had to explicitly __box() them. Either way, this is a major
performance penalty, and a waste of memory too. That's why I suggested
using array<unsigned char>, or even List<unsigned char> (if you're
programming in .NET 2.0). List has an overhead to array, but if used
correctly, it's almost negligible. It's like the difference between
char* and std::string.
I use Bitmap objects as sources of original images, and a destinations
after processing. I usually access them through either:
- bmp->GetPixel(x, y).GetBrightnes() or
- bmp->SetBixel(x, y, Color)
Both functions are called within 'for' loops mentioned in my first
post. Will they work faster with cli::array?
I'm pretty sure that grabbing a pointer to the raw image data would be
many times faster than GetPixel. I don't know how GetPixel works, but it
must do at least a multiplication and an addition (usually TopLeftPtr +
x - y * BytesPerLine, assuming the image is upside down). This is many
times slower than incrementing a pointer.
Even if you use array<unsigned char>, using the array syntax happens to
be much slower for me than interior_ptr<unsigned char>. What I do is the
following:
array<unsigned char> buffer = gcnew array<unsigned char>(width * height);
interior_ptr<unsigned short> ptr = &buffer[0];
while(/*...*/)
{
*ptr++ = /*...*/;
}
This trick alone made my code about twice as fast than using array
syntax, like buffer[offset++].
I'm not familiar with the Bitmap class, but I know it has a way to lock
its pixels and get a byte pointer to its raw underlying data. Here's an
example:
http://vbforums.com/showthread.php?t=260903
I think the C# byte* is the same as the C++/CLI interior_ptr<unsigned char>.
I recommend that you research Bitmap::LockBits and BitmapData a bit:
http://msdn2.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx
Note that if you do this, you must deal with the following:
- windows bitmaps are upside down
- the raw data depends on the bits per pixel value. There are 1, 4, 8,
16, 24, 32-bit images. You must decode the color data from the raw bits
on your own (which is very easy with 8 and 24-bit images, a bit tricky
with 16-bit images, but I refuse to work directly with 16-bit bitmap)
- each line begins on a DWORD boundary, so usually there are some
padding bytes after the last pixel in each line. Here's how to calculate
the number of bytes per line:
BytesPerLine = (Width * BitsPerPixel + 31) / 32 * 4 * Height;
Since images are upside down, the last line is in fact the first, and
instead of incrementing the line pointer by BytesPerLine, you have to
decrement it.
Note that I have very little .NET experience compared to unmanaged code.
99.99% of my code is native C++. You should really do your own
benchmarking with your own algorithm, but you should get much better
result with Bitmap::LockBits than with GetPixel.
Tom