1

I'm trying to write an unsigned char array that I grab from a camera to a bmp file. It's seems to work well except that the output image is strange and blurry. What's strange is that when I save to png format I have a good image. When I check the file with an hexreader I get the good header and the right data size. So I'm wondering why the image is getting blurry if I just write pixel to it.I'm wanting to use bmp format because I grab picture from a camera on a raspberry pi. I want to have a high framerate so png is too slow to write on disk.

The header of the bmp file :

00000000: 424d 36bb 1700 0000 0000 3600 0000 2800  BM6.......6...(.
00000010: 0000 a005 0000 3804 0000 0100 0800 0000  ......8.........
00000020: 0000 00bb 1700 232e 0000 232e 0000 0000  ......#...#.....
00000030: 0000 0000 0000                           ......

The after is the right length : 1555200 bytes.

Here is my function that write bmp file :

#define BMP_HEADER_SIZE 14
#define BMP_INFO_HEADER_SIZE 40
#define BMP_NO_COMPRESSION 0
#define BMP_MAX_NUMBER_OF_COLORS 0
#define BMP_ALL_COLOR_REQUIRED 0

int saveImgToBmp(unsigned char *data, const char *path, int width, int height,
                 int bytesPerPixel) {
    FILE *fp = fopen(path, "wb");

    // Writing header
    const char *BM = "BM";
    fwrite(&BM[0], 1, 1, fp);
    fwrite(&BM[1], 1, 1, fp);

    int paddedRowSize = (int) (4 * ceil((float) width / 4.0f)) * bytesPerPixel;
    uint32_t fileSize = paddedRowSize * height + BMP_HEADER_SIZE + BMP_INFO_HEADER_SIZE;
    fwrite(&fileSize, 4, 1, fp);
    uint32_t reserved = 0x0000;
    fwrite(&reserved, 4, 1, fp);
    uint32_t dataOffset = BMP_HEADER_SIZE + BMP_INFO_HEADER_SIZE;
    fwrite(&dataOffset, 4, 1, fp);

    // Writing info header
    uint32_t infoHeaderSize= BMP_INFO_HEADER_SIZE;
    fwrite(&infoHeaderSize, 4, 1, fp);
    fwrite(&width, 4, 1, fp);
    fwrite(&height, 4 ,1, fp);
    uint16_t planes = 1;
    fwrite(&planes, 2, 1, fp);
    uint16_t bitsPerPixel =  bytesPerPixel * 8;
    fwrite(&bitsPerPixel, 2, 1, fp);
    uint32_t compression = BMP_NO_COMPRESSION;
    fwrite(&compression, 4, 1, fp);
    uint32_t imageSize = width * height * bytesPerPixel;
    fwrite(&imageSize, 4, 1, fp);
    uint32_t resolution = 11811;
    fwrite(&resolution, 4, 1, fp);
    fwrite(&resolution, 4, 1, fp);
    uint32_t colorsUsed = BMP_MAX_NUMBER_OF_COLORS;
    fwrite(&colorsUsed, 4, 1, fp);
    uint32_t importantColors = BMP_ALL_COLOR_REQUIRED;
    fwrite(&importantColors, 4, 1, fp);

    // Writing pixels
    int i = 0;
    int unpaddedRowSize = width * bytesPerPixel;
    for(i = 0; i < height; i++) {
        int pixelOffset = ((height - i) - 1) * unpaddedRowSize;
        fwrite(&data[pixelOffset], 1, paddedRowSize, fp);
    }

    fclose(fp);
    return 0;
}

And the piece of code that's calling this function :

if(grabResult.Status == Grabbed) {
    // Success
    getMinMax(imgBuf, grabResult.SizeX, grabResult.SizeY, &min, &max);
    printf("Acquisition de l'image #%2d. Valeur grise min = %3u, max = %3u\n",
        i + 1, min, max);
    char path[11];
    sprintf(path, "data/%d.bmp", i + 1);
    c = clock();
    saveImgToBmp(imgBuf, path, grabResult.SizeX, grabResult.SizeY, 1);
    c = clock() - c;
    double time_taken = ((double) c)/CLOCKS_PER_SEC;
    printf("Temps écoulé : %fs\n", time_taken);
} else if(grabResult.Status == Failed){
    fprintf(stderr, "L'image %d n'as pas pu être acquise avec succès. Code d'erreur : 0x%08X/\n", i + 1, grabResult.ErrorCode);
}

The saveImgToPng function :

int saveImgToPng(unsigned char *data, const char * path, int width, int height){
    FILE *fp;
    int status;
    png_bytep row;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t x, y;

    fp = fopen(path, "wb");
    if(!fp) {
        goto fopen_failed;
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(png_ptr == NULL) {
        goto png_create_write_struct_failed;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if(info_ptr == NULL) {
        goto png_create_info_struct_failed;
    }

    if (setjmp (png_jmpbuf (png_ptr))) {
        goto png_failure;
    }

    png_set_IHDR (png_ptr,
                  info_ptr,
                  width,
                  height,
                  8,
                  PNG_COLOR_TYPE_GRAY,
                  PNG_INTERLACE_NONE,
                  PNG_COMPRESSION_TYPE_DEFAULT,
                  PNG_FILTER_TYPE_DEFAULT);

    png_init_io(png_ptr, fp);

    png_write_info(png_ptr, info_ptr);

    row = (png_bytep) data;

    for(y = 0; y < height; y++) {
        png_write_row(png_ptr, row);
        row += width;
    }
    
    png_write_end(png_ptr, NULL);



    png_failure:
    png_create_info_struct_failed:
        png_destroy_write_struct (&png_ptr, &info_ptr);
    png_create_write_struct_failed:
        fclose (fp);
    fopen_failed:
        return status;

}

Here an example picture :

bmp picture

louisld
  • 323
  • 2
  • 15
  • 1
    `an unsigned char array that I grab from a camera` How? What camera? What makes you think your error isn't there? It seems you are misinterpreting the pixel format from the image output, but we can't tell you what it should be unless you show us where it came from. What does the camera API tell you about the format of that array? – J... Apr 11 '21 at 10:26
  • It comes from the Basler Pylon library. It's a grayscale image and followed an example given in the ibrary. Each char is a pixel. I think I'm not missusing the data because I wrote a savetopng functions that works. – louisld Apr 11 '21 at 10:29
  • 1
    Where is the savetopng function that works, then? – J... Apr 11 '21 at 10:38
  • I edit my post to add it. – louisld Apr 11 '21 at 10:39
  • I just use saveImgToPng(imgBuf, path, grabResult.SizeX, grabResult.SizeY);` to save the image. – louisld Apr 11 '21 at 10:42
  • 1
    also : [What is the BMP format for Gray scale Images?](https://stackoverflow.com/q/11086649/327083) – J... Apr 11 '21 at 10:50
  • 1
    see : [BMP Pixel Format](https://en.wikipedia.org/wiki/BMP_file_format#Pixel_format). You're missing the colour index table. For 8bpp greyscale you need this. – J... Apr 11 '21 at 10:53
  • I see, thank you very much! It's just my way to write bmp file for grayscale image that is wrong. I will keep this function for further use in color. Do you think it's better to use BMP with colour index table or to use GMP ? – louisld Apr 11 '21 at 10:58
  • 1
    You may also find PNG to be more performant if you disable compression. Your existing code is using the default compression. I'm not sure what "GMP" is. – J... Apr 11 '21 at 10:59
  • 1
    Thank you for all your answers. I'll try the differetnt format and see what is the best. – louisld Apr 11 '21 at 11:05

0 Answers0