How to Read Bmp Pixel Values into an Array

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.

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).

How to read a BMP file into a grid of pixels in C?

Given how you're struggling with structs, lists, and basic I/O, reading in a BMP is probably over your head right now. I'd suggest trying to populate a simpler struct. If this is for a production code, please use an existing library.

I'm going to do some basic fixups so your code at least compiles, hopefully you can take it from there.

BMPImage *readImage(FILE * fp) {
// Allocate space for the image.
// This also covers BMPHeader, since it's not a pointer.
BMPImage *bmp = malloc(sizeof(BMPImage));
BMPHeader *bmph = &(bmp->header);

The basic unit is the BMPImage struct. That contains the BMPHeader as well as a pointer to list of Pixels. The BMPHeader is not a pointer, the actual memory is contained in the BMPImage struct, so malloc(sizeof(BMPImage)) also allocates memory for the BMPHeader. I've taken a pointer to the BMPHeader to make it easier to work with, otherwise the code is sprinkled with bmp.header->height_x.

I'll leave populating the BMPHeader to you. Once you've done that...

// Allocate space for the pixels.
bmp->pixels = malloc( bmph->height_px * sizeof(Pixel *) );
for(int i = 0; i < bmph->height_px; i++){
bmp->pixels[i] = malloc(bmph->width_px * sizeof(Pixel));
}

I think you've basically got the memory allocation right. Your problem was trying to use the Pixel struct when you should have been using BMPImage. While the height and width comes from the BMPHeader.

That isn't really how you should be reading in a BMP since the size of the pixels are variable according to the bits_per_pixel header. Your structs only support the 8bpp format. It also might be compressed. I'm going to assume this is an exercise and not production code, so I'll avoid going further into the details of BMP.

// Read in each pixel
for (int i = 0; i < bmph->height_px; i++){
for(int j = 0; j < bmph->width_px; j++){
Pixel px;

if( fread(&px, sizeof(Pixel), 1, fp) < 1 ) {
fprintf(stderr, "Error while reading bmp: %s", strerror(errno));
return NULL;
}

bmp->pixels[i][j] = px;
}
}

Again, you had the BMPImage and BMPHeader mixed up with Pixel. Furthermore, fopen does not return the structure to be read. Instead, you're responsible for allocating the necessary memory (a theme in C). fopen returns the number of items read. It's very important to do error checking on all file operations, else you'll be left with difficult to understand garbage.

I suspect you can do this much simpler by reading in all the pixels in one big chunk, but I don't know the details of the BMP format.

This is by no means 100% correct, I'm not even sure it's 80% correct, but it'll at least clean up the worst of the confusion.

How can I convert a .bmp file into an array of 1s and 0s in C#?

Try following :

            byte[] input = {0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF,
0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x00, 0x00, 0x00,
0xE0, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF
};
string[] doubleWords = input.Select((x,i) => new {b = x, index = i})
.GroupBy(x => x.index/4)
.Select(x => string.Join("",x.Select(y => Convert.ToString(y.b, 2).PadLeft(8,'0'))))
.ToArray();


Related Topics



Leave a reply



Submit