?
Solved

Getting RGB values from a 24-bit Bitmap

Posted on 2003-03-22
16
Medium Priority
?
7,413 Views
Last Modified: 2013-12-03
I have been going through this site and there are clearly several ways in which this can be done, I am looking for the simplest in terms of understanding, as I am really new to C++.

I am using Windows XP, Visual C++ 6.0, and am dealing with 24-bit uncompressed bitmaps.

I wish to be able to create an application (be it command based or window gui based), that can load a bitmap file, and be able to retrieve the RGB values from each pixel. I hope to look for errors in the bitmap, at first starting to look for large areas of green and black. To do this I will need to be able to create an algorithm to loop and search through each pixel. I will also need to be able to note the location of the pixel, as I will need to compare its value with those of the pixels around it.

From what I understand, the structure of a 24-bit bitmap uses 1 byte for each value, thus 3 bytes to store the RGB. How would one get these values in number form to say be checked if it is inbetween say 230-255?

If this question is not entirely worded well, I apologise, I am new to this forum and C++.

Any help or reading material links appreciated, and there is a large urgency as I need this information ASAP, although I dont have the points to offer...

Thanks in advance,
Graham
0
Comment
Question by:PoD
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 3
  • +2
16 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 152 total points
ID: 8188249
The simplist way is not necessarily the most efficient way.  The simplist way is to load the bitmap into a device context (DC) and then use GetPixel() repeatedly to get the value of each pixel.

example follows
0
 
LVL 8

Assisted Solution

by:fl0yd
fl0yd earned 148 total points
ID: 8188287
So do you have a pointer to the bitmap-data already? If so, there is only one thing to pay special attention to, well, two things:
* bitmaps are usually stored upside-down, i.e., the first row in the array is the one at the bottom of the bitmap
* the beginning of each line is aligned at DWORD boundaries with 0-3 padding bytes at the end each row. So the width in memory isn't necessarily the same as bitmap_width * 3
Retrieving the data is simple. Let's assume your pointer to the bitmap-data is called pBits and of type 'unsigned char*':

unsigned char red = *pBits;
++pBits;
unsigned char green = *pBits;
++pBits;
unsigned char blue = *pBits;
++pBits;

Now, red, green, and blue are the color values of the first pixel of the last row (bottom-up!) in the bitmap.

Calculating the pitch (memory stride from one row to the next) you can use this formula:

long lPitch = ( ( bitmap_width * 3 ) + 3 ) & ~3 );

Thus, the pointer to the first row would be:

unsigned char* pFirstRow = pBits + ( bitmap_height - 1 ) * lPitch;

If anything is still unclear [which is very likely] feel free to come back and ask.

.f
0
 
LVL 22

Expert Comment

by:nietod
ID: 8188290
HBITMAP BitMapHnd =               LoadImage(hInstance,"c:\\filename.bmp",IMAGE_BOTMAP,
                                  LR_DEFAULTSIZE,LR_DEFAULTSIZE,
                                   LR_CREATEDIBSECTION | LR_LOADFROMFILE);

HDC MemDCHnd = CreateCompatibleDC(NULL); // Create a DC to work in
HBITMAP OldBmpHnd = SelectObject(MemDCHnd,BitMapHnd); // Select in the new bitmap.

// here you will want to loop through all the pixels.

COLORREF Pixel = GetPixel(MemDCHnd,0,0); // Get the pixel at 0,0.
int RedValue = GetRValue(Pixel); // Extract he value of the Red component of this pixel.

SelectObject(MemDCHnd,OldBmpHnd); //IMPORTANT must return the original bitmap to the DC.
DeleteDC(MemDCHnd); // Delete the memory DC.
DeleteOjbect(BitMapHnd); // Delete the bitmap.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Expert Comment

by:fl0yd
ID: 8188291
@ nietod:
No, this method is likely to alter the color values. Assume you have set your display color depth to 16 bits....

.f
0
 
LVL 1

Expert Comment

by:frogger1999
ID: 8188305
you should also check out the function

int GetDIBits(
  HDC hdc,           // handle to device context
  HBITMAP hbmp,      // handle to bitmap
  UINT uStartScan,   // first scan line to set in destination bitmap
  UINT cScanLines,   // number of scan lines to copy
  LPVOID lpvBits,    // address of array for bitmap bits
  LPBITMAPINFO lpbi, // address of structure with bitmap data
  UINT uUsage        // RGB or palette index
);

I don't have the time at this moment to write an example but I will later on when I get a chance and you need it.
0
 
LVL 22

Expert Comment

by:nietod
ID: 8188306
If you use CREATEDIBSECTION it should not convert the bitmap to display format.   I say shoudl because I;ve never used it.  I load bitmaps more "manually":
0
 
LVL 8

Expert Comment

by:fl0yd
ID: 8188390
@ nietod:

To tell you the truth, after skimming through the MSDN I have more questions than I had before. Actually, I'm more inclined to believe that it does work the way you described it. However, opinions are rather weak compared to validated information. If I find the time I'll test it later.

.f
0
 

Author Comment

by:PoD
ID: 8188429
Ok well, first off thanks for the major fast responses. At the time I have only basic code to load and display bitmaps from using the appwizard in VisualC++. So I would rather start a small basic application from scratch as the less code needed the better.

@fl0yd: I dont have a pointer at the mo, I have seen many different methods of loading the bitmap from file, I would guess which one to choose would depend on what functions the rest of the program uses?

@nietod: This is looking like the best way todo it. As I can loop through each pixel, and store the values in integer variables for comparison in a function.

Although you two guys are now worrying me as you dont seem to agree :) I will wait a little more to see what other answers there are.
0
 
LVL 22

Expert Comment

by:nietod
ID: 8188582
>> @nietod: This is looking like the best way todo it.
If speed is not an issue, or if the bitmap is fairly small.  That method is probably 100s of times slower than accessing the pixel values directly in memory, as floyd suggested.  That is why I said the simplist way is not necessarily the most efficient way  You might start with that and if its is too slow, move on to some more advanced way.  Like accessing the values from the DIB section yourself.
0
 

Author Comment

by:PoD
ID: 8188772
Well since I plan to be probably be comparing a lot of bitmaps, I would probably want the fastest one. Any chance of trying to explain the more advanced way in gentle dummy terms :)
0
 
LVL 22

Expert Comment

by:nietod
ID: 8189627
>>  I would probably want the fastest one.
You didn't ask for that before!  Its going to get harder now

I think your best bet (there are lots of ways to do this) will be to load the bitmap  as I suggested bfore.  but then use GetDIBits() to extract the pixel information to an array.  

Like

HBITMAP BitMapHnd =               LoadImage(hInstance,"c:\\filename.bmp",IMAGE_BOTMAP,
                                            LR_DEFAULTSIZE,LR_DEFAULTSIZE,
                                             LR_CREATEDIBSECTION | LR_LOADFROMFILE);

HDC MemDCHnd = CreateCompatibleDC(NULL); // Create a DC to work in

DIBSECTION DIBInf; // DIB bitmap information structure.
GetObject(BitMapHnd,sizeof(DIBSECTION),&DIBInf); // Fill in the DIB bitmap information.  

// You might need to swithc top and bottom line if the information is coming out
// flipped upside down..
const int TopLin = 0; // Top line.
const int BtmLin = DIBInf.dsBm.bmHeight; // Bottom line

BITMAPINFO BtmInf;

BmpInf.bmiHeader = DIBInf.dsBmih; // Copy all the format information from the source bitmap.

BmpInf.bmiHeader.biPlanes = 1; // Almost certainly was 1, but just be sure.
BmpInf.bmiHeader.biBitCount = 32; // Specify 32 bits per pixel.
BmpInf.bmiHeader.bicompression = BI_RGB; // Uncompressed
BmpInf.bmiHeader.biSizeImage = 0; // Let windows calculate this.
.
const int PixCnt = DIBInf.dsBmih.biwidth*DIBInf.dsBmih.biHeight; // Number of pixels.
COLORREF PixPtr = new COLORREF[PixCnt];

GetDIIBts(MemDCHnd,BitMapHnd,TopLin,BtmLin,PixPtr,&BtmInf,DIB_RGB_COLORS);

// Now PixPtr shoudl point to an array of 32 bit color values.  Just extract the components from the as I had above.

DeleteDC(MemDCHnd); // Delete the memory DC.
DeleteOjbect(BitMapHnd); // Delete the bitmap.


This code is probably only approximate.  You will need to fool with it to get it to compile and probably it will need other fixes as well.
0
 

Author Comment

by:PoD
ID: 8193041
Thanks for the major effort nietod. Probably stuck my foot in it when I asked for the better method. I don't even know what a DC is! I would very much like to get that method implemented, so any further quicklinks, or what classes etc, I need to look at to learn how to work with that method would be appreciated.
0
 
LVL 8

Expert Comment

by:fl0yd
ID: 8193657
I don't mean to discourage you, but the bitmap-format is an extremely complex beast. Since it was 'invented' by Microsoft I'll give you a link to one of their pages for further information: http://msdn.microsoft.com/library/en-us/gdi/bitmaps_99ir.asp . I suggest that you work with the raw data stored in the file without using device contexts (DC). You have to understand the entire bitmap header though, before you can interpret the data correctly. Chances are, that you don't even find the raw bitmap data if you do not understand the header information.

I hope, this information will get you going. It is a long and winding road, but don't let that get in your way.

.f
0
 
LVL 22

Expert Comment

by:nietod
ID: 8194384
>> I don't even know what a DC
Its a device context.  it repredents a graphical device, like a screen or printer.  memory DCs draw on bitmaps in memory, rather than on a physical device.

>>! suggest that you work with the raw data stored
>> in the file without using device contexts (DC)
That's faster again, but I think its even harder.  
0
 
LVL 11

Expert Comment

by:bcladd
ID: 9544014
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Split: nietod, fl0yd

Please leave any comments here within the next seven days. Experts: Silence
means you don't care.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

-bcl (bcladd)
EE Cleanup Volunteer
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Suggested Courses
Course of the Month8 days, 23 hours left to enroll

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question