reading pixel bits in a bitmap
hi everyone i wrote a method to read in a file and when i detect a black pixel i want to do some processing.
This was working when when my test data was 24bit however now i'm trying it with a 32bit image it doesnt seem to be working.
If i use this method and print out all the coords then ite seems to move through
x1, y1 = 150,150,150
x2,y1 = 150,150,0
x3,y1 = 150,0,150
x4 y1 = 0,150,150
x5 y1 = 150,150,150
... etc
is there prob with my method and is there something i need to change to mke this work?
void readBitmap(LPTSTR path)
{
CString szFilename(path);
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,szFilename,
IMAGE_BITMAP,0,0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
//first read the header
HDC hdc = GetDC(NULL);
BITMAPINFO BitmapInfo = {0};
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(GetDIBits(hdc, hBmp, 0, 0, NULL, &BitmapInfo, DIB_RGB_COLORS))
{
//got the header now need to read it
BYTE *pBits = new BYTE[BitmapInfo.bmiHeader.biSizeImage];
if (pBits)
{
// zero out the bitmap bit buffers
memset(pBits, 0, BitmapInfo.bmiHeader.biSizeImage);
//get the height and width of the image
long h = BitmapInfo.bmiHeader.biHeight;
long w = BitmapInfo.bmiHeader.biWidth;
ocrMsg.Format("bitmp height :%d: width :%d:",h,w);
logMsg(ocrMsg);
BYTE rVal, gVal, bVal;
int x, y = 0;
logmm.open( logzz );
logmm << "starting.. \n";
logmm.close();
//now iterate through the image getting the each pixel
for (x = 0; x < w; x++)
{
//iterate down the column first to try and find first black pixel
for (y = h-1; y > -1; y--)
{
GetDIBits(hdc, hBmp, y, BitmapInfo.bmiHeader.biHeight, pBits, &BitmapInfo, DIB_RGB_COLORS);
rVal = pBits[(x * 3) + 2]; // red
gVal = pBits[(x * 3) + 1]; //green
bVal = pBits[(x * 3) + 0]; //blue
if(rVal == 0 && gVal == 0 && bVal == 0)
{//process}
}
}
}
}
}
regards,
matt.
[2332 byte] By [
flynny1st] at [2007-11-20 11:44:26]

# 1 Re: reading pixel bits in a bitmap
Well, if you use 32 bpp, you must remember that each pixel is defined by 4 bytes, not 3 (Alpha, Red, Green, Blue)
So you'll probably have to change the code to
rVal = pBits[(x * 4) + 2]; // red
gVal = pBits[(x * 4) + 1]; //green
bVal = pBits[(x * 4) + 0]; //blue
EoF at 2007-11-10 22:22:40 >

# 2 Re: reading pixel bits in a bitmap
thanks for that eof.
ive tried the change you suggested unfortunately its not working and i'm getting the **edit** getting
150,150,150 throughout as the output now.
is there anything else i will need to do apart from increase the offset to being 4?
thanks,
Matt.
# 3 Re: reading pixel bits in a bitmap
I just tried it and I am getting the correct results (after replacing the 3 with 4). Can you upload the bitmap you are working on?
EoF at 2007-11-10 22:24:38 >

# 4 Re: reading pixel bits in a bitmap
yes no problem.
This is the bitmap i'm using.
thanks for all your help eof.
Matt
# 5 Re: reading pixel bits in a bitmap
I checked your bitmap and the code works OK. If you look closely (zoom in a lot) at the bitmap, you will see that it has a 1 pixel grayish border - the color being (150,150,150), that's where you get those results from. But once it gets over the border the results are as you'd expect them to be.
EoF at 2007-11-10 22:26:36 >

# 6 Re: reading pixel bits in a bitmap
yeah i did see this grey border however my code doesn't seem to be getting past this border (according to my output every pixel is 150,150,150).
This is the code i'm using now does it differ to your at all?
I have made a slight change to calculate the bitcount bu thats all.
void readBitmap(LPTSTR path)
{
CString szFilename(path);
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,szFilename,
IMAGE_BITMAP,0,0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
//got bitmap now get and read the byte array
//first read the header
HDC hdc = GetDC(NULL);
BITMAPINFO BitmapInfo = {0};
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(GetDIBits(hdc, hBmp, 0, 0, NULL, &BitmapInfo, DIB_RGB_COLORS))
{
//got the header now need to read it
BYTE *pBits = new BYTE[BitmapInfo.bmiHeader.biSizeImage];
if (pBits)
{
// zero out the bitmap bit buffers
memset(pBits, 0, BitmapInfo.bmiHeader.biSizeImage);
//get the height and width of the image
long h = BitmapInfo.bmiHeader.biHeight;
long w = BitmapInfo.bmiHeader.biWidth;
int bitCount = BitmapInfo.bmiHeader.biBitCount;
//ocrMsg.Format("bitmp height :%d: width :%d:",h,w);
//logMsg(ocrMsg);
if(BitmapInfo.bmiHeader.biCompression == BI_RGB)
{
//ocrMsg.Format("BI_RGB compression");
//logMsg(ocrMsg);
}
BYTE rVal, gVal, bVal;
int x, y = 0;
logmm.open( logzz ); //for outputting the bmp to file for debugging
logmm << "starting.. \n";
logmm.close();
//now iterate through the image getting the each pixel
for (x = 0; x < w; x++)
{
//iterate down the column first to try and find first black pixel
for (y = h-1; y > -1; y--)
{
GetDIBits(hdc, hBmp, y, BitmapInfo.bmiHeader.biHeight, pBits, &BitmapInfo, DIB_RGB_COLORS);
//ignore alpha, not interested
rVal = pBits[(x * (bitCount/8)) + 2]; // red
gVal = pBits[(x * (bitCount/8)) + 1]; //green
bVal = pBits[(x * (bitCount/8)) + 0]; //blue
//ocrMsg.Format("bitmap[x%d,y%d] pos[%d] R:%d:G:%d:B:%d:",x,y,x*(bitCount/8),rVal,gVal,bVal);
//logMsg(ocrMsg);
if(rVal == 0 && gVal == 0 && bVal == 0)
{
logmm.open( logzz, ios::app );
logmm << "#";
logmm.close();
//if find black pixel then one need to get bitmap for set area and compare
}
else
{
logmm.open( logzz, ios::app );
logmm << "_";
logmm.close();
}
}
logmm.open( logzz, ios::app );
logmm << "\n";
logmm.close();
}
// clean up
delete[] pBits;
}
}
}
# 7 Re: reading pixel bits in a bitmap
That's weird, my code is not different. I even tried taking your code and tried it and I still got the correct results. I modified your code to dump the bitmap info in a file (dump.txt), here it is:
void readBitmap()
{
CString szFilename("2.bmp");
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,szFilename,
IMAGE_BITMAP,0,0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
//got bitmap now get and read the byte array
//first read the header
HDC hdc = ::GetDC(NULL);
BITMAPINFO BitmapInfo = {0};
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(GetDIBits(hdc, hBmp, 0, 0, NULL, &BitmapInfo, DIB_RGB_COLORS))
{
//got the header now need to read it
BYTE *pBits = new BYTE[BitmapInfo.bmiHeader.biSizeImage];
if (pBits)
{
// zero out the bitmap bit buffers
memset(pBits, 0, BitmapInfo.bmiHeader.biSizeImage);
//get the height and width of the image
long h = BitmapInfo.bmiHeader.biHeight;
long w = BitmapInfo.bmiHeader.biWidth;
int bitCount = BitmapInfo.bmiHeader.biBitCount;
//ocrMsg.Format("bitmp height :%d: width :%d:",h,w);
//logMsg(ocrMsg);
if(BitmapInfo.bmiHeader.biCompression == BI_RGB)
{
//ocrMsg.Format("BI_RGB compression");
//logMsg(ocrMsg);
}
BYTE rVal, gVal, bVal;
int x, y = 0;
FILE *f = fopen("dump.txt", "w+");
//now iterate through the image getting the each pixel
for (x = 0; x < w; x++)
{
//iterate down the column first to try and find first black pixel
for (y = h-1; y > -1; y--)
{
GetDIBits(hdc, hBmp, y, BitmapInfo.bmiHeader.biHeight, pBits, &BitmapInfo, DIB_RGB_COLORS);
//ignore alpha, not interested
rVal = pBits[(x * (bitCount/8)) + 2]; // red
gVal = pBits[(x * (bitCount/8)) + 1]; //green
bVal = pBits[(x * (bitCount/8)) + 0]; //blue
//ocrMsg.Format("bitmap[x%d,y%d] pos[%d] R:%d:G:%d:B:%d:",x,y,x*(bitCount/8),rVal,gVal,bVal);
//logMsg(ocrMsg);
if(rVal == 0 && gVal == 0 && bVal == 0)
{
//if find black pixel then one need to get bitmap for set area and compare
}
else
{
}
fprintf(f, "(X:%d - Y:%d, R:%d, G:%d, B:%d)\n", x, y, rVal, gVal, bVal);
}
fprintf(f, "----New line----\n");
}
// clean up
delete[] pBits;
fclose(f);
}
}
}
The color components that I got for the first 2 lines are
(X:0 - Y:19, R:150, G:150, B:150)
(X:0 - Y:18, R:150, G:150, B:150)
(X:0 - Y:17, R:150, G:150, B:150)
(X:0 - Y:16, R:150, G:150, B:150)
(X:0 - Y:15, R:150, G:150, B:150)
(X:0 - Y:14, R:150, G:150, B:150)
(X:0 - Y:13, R:150, G:150, B:150)
(X:0 - Y:12, R:150, G:150, B:150)
(X:0 - Y:11, R:150, G:150, B:150)
(X:0 - Y:10, R:150, G:150, B:150)
(X:0 - Y:9, R:150, G:150, B:150)
(X:0 - Y:8, R:150, G:150, B:150)
(X:0 - Y:7, R:150, G:150, B:150)
(X:0 - Y:6, R:150, G:150, B:150)
(X:0 - Y:5, R:150, G:150, B:150)
(X:0 - Y:4, R:150, G:150, B:150)
(X:0 - Y:3, R:150, G:150, B:150)
(X:0 - Y:2, R:150, G:150, B:150)
(X:0 - Y:1, R:150, G:150, B:150)
(X:0 - Y:0, R:150, G:150, B:150)
----New line----
(X:1 - Y:19, R:150, G:150, B:150)
(X:1 - Y:18, R:255, G:255, B:255)
(X:1 - Y:17, R:255, G:255, B:255)
(X:1 - Y:16, R:255, G:255, B:255)
(X:1 - Y:15, R:255, G:255, B:255)
(X:1 - Y:14, R:255, G:255, B:255)
(X:1 - Y:13, R:255, G:255, B:255)
(X:1 - Y:12, R:255, G:255, B:255)
(X:1 - Y:11, R:255, G:255, B:255)
(X:1 - Y:10, R:255, G:255, B:255)
(X:1 - Y:9, R:255, G:255, B:255)
(X:1 - Y:8, R:255, G:255, B:255)
(X:1 - Y:7, R:255, G:255, B:255)
(X:1 - Y:6, R:255, G:255, B:255)
(X:1 - Y:5, R:255, G:255, B:255)
(X:1 - Y:4, R:255, G:255, B:255)
(X:1 - Y:3, R:255, G:255, B:255)
(X:1 - Y:2, R:255, G:255, B:255)
(X:1 - Y:1, R:255, G:255, B:255)
(X:1 - Y:0, R:150, G:150, B:150)
----New line----which is correct. Just making sure, are you passing the correct file to the method?
EoF at 2007-11-10 22:28:45 >

# 8 Re: reading pixel bits in a bitmap
Hi eof,
just to add. I've just tested this same test image bbut turned it into a 24-bit bitmap an ran it through the code and this has worked fine. it seems to be a problem on the 32bit bitmaps.
# 9 Re: reading pixel bits in a bitmap
If you run the code I posted above, and compare the results in the dump.txt file, does it look the same?
EoF at 2007-11-10 22:30:45 >

# 10 Re: reading pixel bits in a bitmap
hi eof,
sorry i posted that last message without refreshing so didnt see the dump you posted.
I get the same results with you code too which is strange. However i have managed to play round and see what its doing. basically, it reading the first line every time and this is why i'm always getting 150,150,150.
regardless of the y value i send to GetDibits it seems to return the first line.
# 11 Re: reading pixel bits in a bitmap
ok heres a bmp i tried and the first few lines of the output
(X:0 - Y:19, R:150, G:150, B:150)
(X:0 - Y:18, R:150, G:150, B:150)
(X:0 - Y:17, R:150, G:150, B:150)
(X:0 - Y:16, R:150, G:150, B:150)
(X:0 - Y:15, R:150, G:150, B:150)
(X:0 - Y:14, R:150, G:150, B:150)
(X:0 - Y:13, R:150, G:150, B:150)
(X:0 - Y:12, R:150, G:150, B:150)
(X:0 - Y:11, R:150, G:150, B:150)
(X:0 - Y:10, R:150, G:150, B:150)
(X:0 - Y:9, R:150, G:150, B:150)
(X:0 - Y:8, R:150, G:150, B:150)
(X:0 - Y:7, R:150, G:150, B:150)
(X:0 - Y:6, R:150, G:150, B:150)
(X:0 - Y:5, R:150, G:150, B:150)
(X:0 - Y:4, R:150, G:150, B:150)
(X:0 - Y:3, R:150, G:150, B:150)
(X:0 - Y:2, R:150, G:150, B:150)
(X:0 - Y:1, R:150, G:150, B:150)
(X:0 - Y:0, R:150, G:150, B:150)
----New line----
(X:1 - Y:19, R:255, G:255, B:255)
(X:1 - Y:18, R:255, G:255, B:255)
(X:1 - Y:17, R:255, G:255, B:255)
(X:1 - Y:16, R:255, G:255, B:255)
(X:1 - Y:15, R:255, G:255, B:255)
(X:1 - Y:14, R:255, G:255, B:255)
(X:1 - Y:13, R:255, G:255, B:255)
(X:1 - Y:12, R:255, G:255, B:255)
(X:1 - Y:11, R:255, G:255, B:255)
(X:1 - Y:10, R:255, G:255, B:255)
(X:1 - Y:9, R:255, G:255, B:255)
(X:1 - Y:8, R:255, G:255, B:255)
(X:1 - Y:7, R:255, G:255, B:255)
(X:1 - Y:6, R:255, G:255, B:255)
(X:1 - Y:5, R:255, G:255, B:255)
(X:1 - Y:4, R:255, G:255, B:255)
(X:1 - Y:3, R:255, G:255, B:255)
(X:1 - Y:2, R:255, G:255, B:255)
(X:1 - Y:1, R:255, G:255, B:255)
(X:1 - Y:0, R:255, G:255, B:255)
----New line----
(X:2 - Y:19, R:150, G:150, B:150)
(X:2 - Y:18, R:150, G:150, B:150)
(X:2 - Y:17, R:150, G:150, B:150)
(X:2 - Y:16, R:150, G:150, B:150)
(X:2 - Y:15, R:150, G:150, B:150)
(X:2 - Y:14, R:150, G:150, B:150)
(X:2 - Y:13, R:150, G:150, B:150)
(X:2 - Y:12, R:150, G:150, B:150)
(X:2 - Y:11, R:150, G:150, B:150)
(X:2 - Y:10, R:150, G:150, B:150)
(X:2 - Y:9, R:150, G:150, B:150)
(X:2 - Y:8, R:150, G:150, B:150)
(X:2 - Y:7, R:150, G:150, B:150)
(X:2 - Y:6, R:150, G:150, B:150)
(X:2 - Y:5, R:150, G:150, B:150)
(X:2 - Y:4, R:150, G:150, B:150)
(X:2 - Y:3, R:150, G:150, B:150)
(X:2 - Y:2, R:150, G:150, B:150)
(X:2 - Y:1, R:150, G:150, B:150)
(X:2 - Y:0, R:150, G:150, B:150)
# 12 Re: reading pixel bits in a bitmap
Hmmm, way weird. I tried your bitmap and I got different results. It seems that it takes the value of the first pixel on the line and then repeats it for the entire line. Can you strip all the functionality from your project except for this part and upload it so I can take a look?
This is what I got (X:0 - Y:19, R:150, G:150, B:150)
(X:0 - Y:18, R:255, G:255, B:255)
(X:0 - Y:17, R:150, G:150, B:150)
(X:0 - Y:16, R:255, G:255, B:255)
(X:0 - Y:15, R:150, G:150, B:150)
(X:0 - Y:14, R:255, G:255, B:255)
(X:0 - Y:13, R:150, G:150, B:150)
(X:0 - Y:12, R:255, G:255, B:255)
(X:0 - Y:11, R:255, G:255, B:255)
(X:0 - Y:10, R:255, G:255, B:255)
(X:0 - Y:9, R:255, G:255, B:255)
(X:0 - Y:8, R:255, G:255, B:255)
(X:0 - Y:7, R:255, G:255, B:255)
(X:0 - Y:6, R:255, G:255, B:255)
(X:0 - Y:5, R:255, G:255, B:255)
(X:0 - Y:4, R:255, G:255, B:255)
(X:0 - Y:3, R:255, G:255, B:255)
(X:0 - Y:2, R:255, G:255, B:255)
(X:0 - Y:1, R:255, G:255, B:255)
(X:0 - Y:0, R:150, G:150, B:150)
----New line----
(X:1 - Y:19, R:255, G:255, B:255)
(X:1 - Y:18, R:255, G:255, B:255)
(X:1 - Y:17, R:255, G:255, B:255)
(X:1 - Y:16, R:255, G:255, B:255)
(X:1 - Y:15, R:255, G:255, B:255)
(X:1 - Y:14, R:255, G:255, B:255)
(X:1 - Y:13, R:255, G:255, B:255)
(X:1 - Y:12, R:255, G:255, B:255)
(X:1 - Y:11, R:255, G:255, B:255)
(X:1 - Y:10, R:255, G:255, B:255)
(X:1 - Y:9, R:255, G:255, B:255)
(X:1 - Y:8, R:255, G:255, B:255)
(X:1 - Y:7, R:255, G:255, B:255)
(X:1 - Y:6, R:255, G:255, B:255)
(X:1 - Y:5, R:255, G:255, B:255)
(X:1 - Y:4, R:255, G:255, B:255)
(X:1 - Y:3, R:255, G:255, B:255)
(X:1 - Y:2, R:255, G:255, B:255)
(X:1 - Y:1, R:255, G:255, B:255)
(X:1 - Y:0, R:150, G:150, B:150)
----New line----
EoF at 2007-11-10 22:33:46 >

# 13 Re: reading pixel bits in a bitmap
the problem is the project is quite large.I coudl email it to ou if you would like though?
the jist of the project is this i add a button to a program and i want to read off a section and do some basic ocr-ing. so this code is triggered when a button i pressed.
One thiing that is worth mentioning is the fact that this code is inside a dll. Will that make any difference do you think?
so in the call-back function on the lbutton up function i will eventually output the section i want to read and then ocr this bmp. however at the moment i am sending it a hardcoded bmp like the one i sent you.
so i'm doing nothing ot affect the bmp after i've created it or whilst i'm looping around it.
# 14 Re: reading pixel bits in a bitmap
flynny1st, try using this code to loop through your bitmap and see if you get the same results
void readBitmap(LPTSTR path)
{
CString szFilename(path);
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,szFilename,
IMAGE_BITMAP,0,0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
BITMAP WorkBmp;
GetObject(hBmp, sizeof(WorkBmp), &WorkBmp);
int dWidth = WorkBmp.bmWidth;
int dActualWidth = (WorkBmp.bmWidth * bitsPerPixel + 3)&(~3);
int dHeight = WorkBmp.bmHeight;
int x, y;
int r,g,b;
FILE *f = fopen("dump.txt", "w+");
for(x=0;x<dWidth;x++)
{
for (y=dHeight - 1;y>=0;y--)
{
r = *((BYTE*)WorkBmp.bmBits + y * dActualWidth + x * 4 + 2);
g = *((BYTE*)WorkBmp.bmBits + y * dActualWidth + x * 4 + 1);
b = *((BYTE*)WorkBmp.bmBits + y * dActualWidth + x * 4 + 0);
fprintf(f, "(X:%d - Y:%d, R:%d, G:%d, B:%d)\n", x, y, r, g, b);
}
fprintf(f, "----New line----\n");
}
fclose(f);
}
EoF at 2007-11-10 22:35:53 >

# 15 Re: reading pixel bits in a bitmap
Brilliant! thats working a treat. why the previous method didn't i'm not sure just a couple of questions about how this works.
int dActualWidth = WorkBmp.bmWidth + WorkBmp.bmWidth % 4;
why is the actual width twice the width mod 4?
WorkBmp.bmBits
i assume is the pointers to the start of the pixel bits? so why is the displacement
WorkBmp.bmBits + y * dActualWidth * 4 + x * 4 + 2
(i understand the +2 is the position of the actual value)
# 16 Re: reading pixel bits in a bitmap
Glad to hear it works. I don't know either why the previous code didn't work on your side.
int dActualWidth = WorkBmp.bmWidth + WorkBmp.bmWidth % 4;
why is the actual width twice the width mod 4?
It is not twice the width mod 4. It is Width + (Width mod 4)
This is a requirement of the bitmap format. Each horizontal line must contain a number of pixels divisible by 4. If the line is not long enough, it must be padded with 0 to make it divisible by 4. The actual width is needed to compute the offset of each pixel.
WorkBmp.bmBits
i assume is the pointers to the start of the pixel bits? so why is the displacement
WorkBmp.bmBits + y * dActualWidth * 4 + x * 4 + 2
(i understand the +2 is the position of the actual value) In a bitmap, the pixel values are not stored as a 2dimensional matrix but as a linear array. So I was actually computing the address for each pixel. Assuming that I have a bitmap that looks like (each letter represents a pixel)
XXXXXXXXXX
XXOXXXXXXX
XXXXXXXXXX
NOTE that we have 10 pixels per line, which is not divisible by 4, so the actual bitmap will be extended to 12 pixels per line
XXXXXXXXXX(XX)
XXOXXXXXXX(XX)
XXXXXXXXXX(XX)
the content will be stored in memory in an array like this:
XXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXX
Now, the offset of the pixel marked by O would be number_of_lines_before * number_of_pixels_per_line + pixel_position_in_line In this case it would be 1 * 12 + 2 = 14.
The values were multiplied by 4, because in this case we had 32bpp so each pixel uses 4 bytes (R,G,B,Alpha)
EoF at 2007-11-10 22:37:54 >

# 17 Re: reading pixel bits in a bitmap
thank EoF.
thats great.
# 18 Re: reading pixel bits in a bitmap
You're welcome :)
EoF at 2007-11-10 22:39:51 >
