Sign in to follow this  
biowarrior

BITMAP optimization

Recommended Posts

biowarrior    127
Hey Guys, if someone can help me, I'll be thankful. Well, I have a program which transfer the bitmap (DIB Section) from a MFC's CImage object to an array of integers, which is my pixels array. Here's the code: for (unsigned int y = 0; y < height; y++) { int line = y * width; for (unsigned int x = 0; x < width; x++) { // Extract color information for pixel and build an equivalent Java pixel // for storage in the Java-based integer array. // The CImage::GetPixel return an pixel in the following format: 0xAARRGGBB // But java.awt.Image needs a image in the follow format: 0xAABBGGRR // Where: // A = alpha, R=red, G=green, B=blue, // And the 'or' operator (|) is used to make the image opaque: A=0xFF // This code is very inefficient, try other approaches COLORREF pixel = (COLORREF)cImage.GetPixel(x,y); pixel = 0xff000000 | RGB(GetBValue(pixel), GetGValue(pixel), GetRValue(pixel)); // Store the pixel in the array at the appropriate index. pixelsArray[line + x] = (jint) pixel; } } As you can see, I get pixel by pixel the image from CImage object and put it in my pixel array. This code is extremelly slow and is consuming too much time and processing of my application. Here's the deal, I need performance in this specific code! First of all, my objective was make that code work, now I need to improve that! The most important thing is that I have to make a swith from RGB to BGR pixel format, because the object which will receive the filled array interpret the bytes/pixels in that format. Thanks

Share this post


Link to post
Share on other sites
Hello,

1) you can use either [code][/code] or [source lang="cpp"][/source] tags to write code that will be easier to read.

2) If you know how to gain access to the internal pointer of your CImage object, you can use this pointer to read your pixels. To be able to correctly read your bitmap data, you need to know:
  • the pointer to the beginning of the data
  • the height and the width of the image
  • the pitch (ie the distance in bytes from the beginning of one line to the beginning of the next line).

The pitch is equal to
pitch = ((width+3)&(~3))*(bpp)

bpp is bytes per pixel. The address of pixel (x, y) is then

byte *pixeladdr = imagebegin + y * pitch + x * bpp;

Of course, you can use the same kind of addressing that you are using with your java image buffer:

byte *linebegin = imagebegin + y;
byte *p = linebegin;
for (int x=0; x<width; x++) [
p = linebegin + (x * bpp);
// or even simple and faster, since you avoid the multiply:
// p += bpp; (for each iteration)
}

The only problem for me is that I don't know the CImage lib very well (I did my own when I needed one) thus I don't know how to get the image pointer from your CImage instance :P

3) concerning your java image it can help you a lot if you define a union type like this:

union ArgbPixel
{
unsigned int argb;
struct
{
unsigned char a, r, g, b;
}
};

Your code can be greatly simplified:

ArgbPixel *pixelArray;
ArgbPixel pixel;
// ...
pixel.argb = cImage.GetPixel(x,y);
std::swap(pixel.r, pixel.g);
pixelArray[line+x].argb = pixel.argb;


HTH,

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
I would recommend removing the GetPixel() function call if possible, That is probably your bottleneck.
eg:

void CopyImage( jint* pixelsArray, CImage& cImage )
{
int width( cImage.GetWidth() ), height( cImage.GetHeight() );

void CopyPixel( jint& out, const COLORREF& in )
{
// intel format
// in : 0xAARRGGBB
unsigned char* pucIn= (unsigned char*)( &in );
// out : 0xAABBGGRR
unsigned char* pucOut= (unsigned char*)( &out );
// Copy
pucOut[0] =pucIn[2]; //x )
{ // GetPixel (slowly but surely)
in =cImage.GetPixel( x, y );
// copy pixel
CopyPixel( *pOut, in );
// next pixel
++pOut;
++x;
}
}
}
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
I would recommend removing the GetPixel() function call if possible, That is probably your bottleneck.
eg:


void CopyImage( jint* pixelsArray, CImage& cImage )
{
int width( cImage.GetWidth() ), height( cImage.GetHeight() );

void CopyPixel( jint& out, const COLORREF& in )
{
// intel format
// in : 0xAARRGGBB
unsigned char* pucIn= (unsigned char*)( &in );
// out : 0xAABBGGRR
unsigned char* pucOut= (unsigned char*)( &out );
// Copy
pucOut[0] =pucIn[2]; //< red
pucOut[1] =pucIn[1]; //< green
pucOut[2] =pucIn[0]; //< blue
// fake the alpha
pucOut[3] =0xFF;//pucIn[3];
};

// shortcut for true color images
int BitsPerPixel( cImage.GetBPP() );
if( 32 ==BitsPerPixel || 24 ==BitsPerPixel )
{ // assumes 32bit BMP is standard 8bit component bitfield style.
// convert BitsPerPixel to BytesPerPixel.
BitsPerPixel /=8;
// copy image pixel per pixel
COLORREF* pIn;
jint* pOut;
unsigned int x, y( height );
while( y-- )
{ // setup to copy a row
pIn =(COLORREF*)( cImage.GetPixelAddress( 0, y ) );
pOut =&pixelsArray[y *width];
x =width;
while( x-- )
{ // copy pixel
CopyPixel( *pOut, *pIn );
// next pixel
++pOut;
pIn =(COLORREF*)( &((char*)pIn)[BitsPerPixel] );
}
}
}
else
{ // safe but slow version for other bmp types
COLORREF in;
jint* pOut;
unsigned int x, y( height );
while( y-- )
{ // setup to copy a row
pOut =&pixelsArray[y *width];
x =0;
while( width >x )
{ // GetPixel (slowly but surely)
in =cImage.GetPixel( x, y );
// copy pixel
CopyPixel( *pOut, in );
// next pixel
++pOut;
++x;
}
}
}
}


Share this post


Link to post
Share on other sites
biowarrior    127
Another thing, someone knows how could I avoid the following multiplication:

line = y * width;

where width is constant through the loop and y variable?

(x << 5) evaluates to the same value as (x * 32), but is very faster! But it only works on number of power of two, like 2, 4, 8, 16, 32, 64, etc. How could I do the same with numbers like 320 and 240, which aren't (at all) multiples of two.

Another thing, anyone here already work with JAI or know something related?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Yep, do not multiply. I couldn't be bothered to improve that.
To move the multiply out of the loop realise the following:

y =height;
while( y-- )
{ // calc line
line =y*width;
}

is equal to:

y =height;
line =height*width;
while( y-- )
{ // calc line
line -=width;
}

But you should not be saving much moving that out of the row loop. Concentrate on the inner per pixel loop.

Share this post


Link to post
Share on other sites
biowarrior    127
Ok, you're right, although I gained about 100 ms doing that, every impovement is worth.

My code became this:


unsigned int javaLine = 0;
unsigned int cppLine = 0;

for (unsigned int y = 0; y < height; y++) {

for (unsigned int x = 0; x < width; x++) {
int index = cppLine + (x << shiftBPP); // = cppLine + (x * bytesPerPixel)

// Notice that I switch from RGB to BGR through index changing
unsigned int pixel = 0xff000000 | (bitmap[index+2] << 16)
| (bitmap[index+1] << 8)
| bitmap[index];

pixelsArray[javaLine + x] = (jint) pixel;
}

javaLine += width;
cppLine += pitch;
}

Share this post


Link to post
Share on other sites
biowarrior    127
Maybe I did a mistake by specifying that cppLine is unsigned, because my pitch could be negative, but It worked anyway.

Do you see anithing that can be improved in that code?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
You are not doing any conversion (done here)...
I assume shiftBPP is bytes per pixel...


unsigned char *pPixOut = (unsigned char*)&pixelsArray[0];
unsigned char *pRowIn = (unsigned char*)&bitmap[0], *pPixIn;
int x;

while( height-- ) {
// setup row
pPixIn =pRowIn;
x =width;
while( x-- ) {
// copy pixel, switching from 8bit ARGB to ABGR (intel)
*(pPixOut++) =pPixIn[2];
*(pPixOut++) =pPixIn[1];
*(pPixOut++) =pPixIn[0];
*(pPixOut++) =0xFF;//pPixIn[3];
// next pixel
pPixIn +=shiftBPP;
}
// next row
pRowIn +=pitch;
}


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this