Read Pixel Value in Bmp File

read pixel value in bmp file

The following code snippet is not complete, and contains lots of hidden assumptions and bugs. I wrote it from scratch for a university course project from mere observation, where it minimally fulfilled all the requirements. I didn't work on it any more, because there must be libraries that would do the job way better.

Here are the conditions where it worked okay (some assumptions are pointed out in the comments):

  1. It ran on Windows, I'm not sure about other platforms
  2. It works for 24-bit color BMP images
  3. It assumes that the width of the image is a multiple of 4, so it doesn't handle the padding bytes in case it's not
  4. It decodes the image width and height as 32-bit little endian integers
  5. It returns a pointer to dynamically allocated memory, it may cause memory leak if it's not released by the caller

Other answers have covered some of these issues.


You can try this one:

unsigned char* readBMP(char* filename)
{
int i;
FILE* f = fopen(filename, "rb");
unsigned char info[54];

// read the 54-byte header
fread(info, sizeof(unsigned char), 54, f);

// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];

// allocate 3 bytes per pixel
int size = 3 * width * height;
unsigned char* data = new unsigned char[size];

// read the rest of the data at once
fread(data, sizeof(unsigned char), size, f);
fclose(f);

for(i = 0; i < size; i += 3)
{
// flip the order of every 3 bytes
unsigned char tmp = data[i];
data[i] = data[i+2];
data[i+2] = tmp;
}

return data;
}

Now data should contain the (R, G, B) values of the pixels. The color of pixel (i, j) is stored at data[3 * (i * width + j)], data[3 * (i * width + j) + 1] and data[3 * (i * width + j) + 2].

In the last part, the swap between every first and third pixel is done because I found that the color values are stored as (B, G, R) triples, not (R, G, B).

Getting the pixel value of BMP file

The easy way would be to find a good image manipulation library for your chosen platform and use that.

  • Linux ImLib / GDK-Pixbuf (Gnome/GTK) / QT Image (KDE/Qt) should be able to do what you need.
  • Windows I'm not familiar with the appropriate system library, but an MSDN Search for "Bitmap" is probably a good place to start.
  • Mac OSX Cocoa has some image manipulation capabilities, see this article.

The hard way would be to open the file and actually interpret the binary data within. To do that you'll need the BMP File Specification. I'd recommend trying the easy way first.

I'm reading the RGB values of pixels from a BMP file and not getting the correct values

Your problem is that you are always checking the RGB values at (0,0)

i = 0; // i is the x value of the pixel that is having its RGB values checked
int j = 0; // j is the y value of the pixel that is having its RGB values checked
...
for(count = 0; count < size; count += 1){
unsigned char R = data[3 * (i * width + j)];
unsigned char G = data[3 * (i * width + j) + 1];
unsigned char B = data[3 * (i * width + j) + 2];

i and j defines the X and Y position of the pixel you are checking, but notice that you never change those in the loop. Your loop will keep doing the same thing over and over again. What you probably want is a double loop, going through all coordinates in your image:

   for(int y=0; y<height; y++)
for(int x=0; x<width; x++){
unsigned char R = data[3 * (y * width + x) + 0];
unsigned char G = data[3 * (y * width + x) + 1];
unsigned char B = data[3 * (y * width + x) + 2];

Reading RGB pixels from bmp file

I ran the code and it works fine, I presume you mean by 'RGB values aren't coming up' you are not seeing the integer values, in which case this will fix it:

ofs<<"R: "<<int(R)<<" G: "<<int(G)<<" B: "<<int(B)<<"  position in file: "<<ifs.tellg()<<"\r\n";

Update: I posted earlier that you could replace ifs.read() with ifs >> R >> G >> B; As @Benjamin Lindley points out, this is incorrect as the >> operator is for formatted text, not binary. This means if the file contains eg a space/newline/etc character, the operator will skip it and take the next char. Better to use ifs.get(char) in this simple case.

How can I read BMP pixel values into an array?

Read the entire file into memory. There will be a small header at the front, and the rest of it will be the pixel values.

The first part will be a BITMAPFILEHEADER structure. The only part you care about is the bfOffBits, which gives the number of bytes from the start of the file to the pixel values.

The next part after the BITMAPFILEHEADER will be a BITMAPINFOHEADER. This will be useful to determine the format of the pixels.

This will be followed by a palette, if the bit depth requires one.

There are a couple of gotchas with the pixel values. First is that the order is (blue,green,red), just opposite of the way everybody else does it. Second is that the rows go from bottom to top of the image, again backwards from everybody else. Finally, the number of bytes in a row will always be padded up to the next multiple of 4.

I almost forgot to mention, it is possible for a JPEG or PNG file to be encoded as a BMP, but this is not common. Have a look at the biCompression field of the BITMAPINFOHEADER, if it's anything but BI_RGB you'll need a little more help.

Reading data from BMP file in C

Short Answer: Set padding to (4-((3*width)%4))%4

Long answer:

Your code included:

int padding = header->width % 4; 

//Some lines of code

fseek(stream, padding, SEEK_CUR);

In a bitmap, padding is added until each row is a multiple of 4 bytes. You took padding as width % 4.

First off, each pixel takes 3 bytes(for rgb). So it should be (3*width)%4. Next, we need to subtract it from 4 bytes (Since padding is 4-pixels occupied). So padding would be 4-((3*width)%4). Another small modification, if (3*width)%4==0 then padding would come to be 4 (whereas, we expect it to be 0). So we take another mod4 just to be sure

So padding would come out to be (4-((3*width)%4))%4

EDIT:

As pointed out by user Craig Estey in the comments, its better to use sizeof(struct pixel) instead of 3



Related Topics



Leave a reply



Submit