Search code examples
pythoncimagebmp

read.bmp image using qdbmp


I am using a library called qdbmc to read a bmp gray image (lena_gray.bmp)

this the link to the library

and this is my code:

int read_image(char *filename)
{
struct _BMP* bmp;
UINT    width, height;
UCHAR red,green,blue;

bmp = BMP_ReadFile(filename);
BMP_CHECK_ERROR( stderr, -1 );

/* Get image's dimensions */
 width = BMP_GetWidth( bmp );
 height = BMP_GetHeight( bmp );
 printf("%lu   %lu \n",width,height);

 /* Iterate through all the image's pixels */
 for (int x = 0 ; x < width ; ++x )
 {
     for (int y = 0 ; y < height ; ++y )
     {
         /* Get pixel's RGB values */
         BMP_GetPixelRGB( bmp, x, y, &red, &green, &blue );
         printf("%d \t %d \t %d \n",red,green,blue);
     }
 }
 return 0;
}

the width and the height are displayed correctly (512 x 512) but the pixels values are in correct because it is showing me all zeros.

when i used the imread() function with python i got this :

60 160 160 159 161 156 161 159 162 159 160 158 154 162 158 154 156 155
160 160 153 156 154 156 154 156 154 152 155 153 153 155 153 157 155 158
.....

can someone please help?

edit

This is the link to the image (choose Lena, 8 bit gray (512 x 512), bmp )


Solution

  • Neither output is correct. Gray colors in grayscale bitmap are of the form: (x,x,x) where the red, blue, and green are the same. Therefore zero is wrong. And and 60 160 160 159 161 156 ... is wrong because there is no repeat pattern.

    8-bit bitmap uses a table. The first 54 bytes are the file heading. Then there is 256 colors (each 4 bytes long) and then width * height bytes, where width has to be padded so the size of width in bytes is a multiple of 4.

    The bitmap pixels start from bottom to top, first you have to read the row (starting from bottom) then read each column. This code should print the correct output for the first 5 columns in each row:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <windows.h>
    
    #pragma pack(push, 1)
    struct my_BITMAPFILEHEADER {
        short bfType;
        int bfSize;
        short bfReserved1;
        short bfReserved2;
        int bfOffBits;
    };
    
    struct my_BITMAPINFOHEADER {
        int biSize;
        int biWidth;
        int biHeight;
        short biPlanes;
        short biBitCount;
        int biCompression;
        int biSizeImage;
        int biXPelsPerMeter;
        int biYPelsPerMeter;
        int biClrUsed;
        int biClrImportant;
    };
    #pragma pack(pop)
    
    int main(void)
    {
        if(sizeof(struct my_BITMAPFILEHEADER) != 14)
        {
            printf("stop!\n");
            return 0;
        }
    
        FILE *fp = fopen("c:\\test\\barbara_gray.bmp", "rb");
    
        //Read file header
        struct my_BITMAPFILEHEADER fhdr;
        struct my_BITMAPINFOHEADER ihdr;
        fread(&fhdr, sizeof(fhdr), 1, fp);
        fread(&ihdr, sizeof(ihdr), 1, fp);
    
        if(fhdr.bfType == 'MB' && ihdr.biBitCount == 8 && ihdr.biPlanes == 1)
        {
            //Read table
            unsigned int table[256] = { 0 };
            fread(table, 4, 256, fp);
    
            int w = ihdr.biWidth;
            int h = ihdr.biHeight;
    
            //Find width in bytes. Use a math trick to make sure it's divisble by 4
            int w_in_bytes = ((w * 8 + 31) / 32) * 4;
            int size = w_in_bytes * h;
    
            //Read pixels
            unsigned char *pixels = malloc(size);
            fread(pixels, 1, size, fp);
    
            //Read from bottom to top:
            for(int row = h - 1; row >= 0; row--)
            {
                printf("%3d: ", h - 1 - row);
                //Read from left to right:
                for(int col = 0; col < w; col++)
                {
                    int pos = row * w_in_bytes + col;
                    unsigned char color_index = pixels[pos];
                    unsigned int clr = table[color_index];
                    printf("%02X%02X%02X ", 
                        clr & 0xFF, (clr >> 8) & 0xFF, (clr >> 16) & 0xFF);
                    if(col > 5) break;
                }
                printf("\n");
            }
    
            free(pixels);
        }
    
        printf("\n");
        fclose(fp);
        return 0;
    }