You are not logged in.

#1 2008-12-30 06:35:43

vkumar
Member
Registered: 2008-10-06
Posts: 166

bitmap rw library for scientific use

I work with my brother's professor on a university project.
We do cerebrovascular research, and our image-processing code is done mostly in Matlab (the rest is Mex/C).

All of our MRA data sets have one constant; the images are all grayscale 512x512 8bpp bitmaps.

I dislike Matlab for many reasons, but here's the major one: it's very slow.
So in the interest of speeding things up, I wrote a library in C++ that can read/write to these bitmaps.

The performance gain is amazing, even considering that the code has been highly optimized.

Most of the code is derived from Paul Macklin's ebmp library.
I've eliminated a lot (literally thousands of lines of) useless stuff - useless to me anyways, and re-written all of the functions to be noticeably faster. Enjoy wink.

// sample usage

#include "sbi_bmp.h" // iostream included in there

int main() {
    BMP slice;
    slice.read("sub76_001.bmp");
    
/*
 * BMP objects have these public members;
 * - (short) slice.Pixels[][] : you can read/modify all of the pixels
 * - (short) slice.histogram[] : 1-255
 * bmpFileHeader data, slice.bmfh
 * bmpInfoHeader data, slice.bmih
*/

    slice.write("final_001.bmp");
}

I find this library to be very hackable, so feel free to remove the histogram code or add your own manipulation functions.

/*
 * sbi_bmp.h
 * -vk
 *
 * This file offers basic r/w capabilities for 8bit 512x512 Windows BMPs.
 * Big-endian support has been removed, but it should work well on POSIX
 * compliant operating systems, both 32 and 64 bit.
 *
 * The code is derived from Paul Macklin's ebmp library.
*/

#include <iostream>

typedef unsigned char bmpByte;
typedef unsigned short bmpWord;
typedef unsigned int bmpDWord;

typedef unsigned long ulong;
typedef unsigned short ushort;

inline bool isBigEndian() {
    short word = 0x0001;
    return ((*(char*)& word) != 0x01);
}

inline bool typeChecks() {
    return sizeof(bmpByte) == 1
        && sizeof(bmpWord) == 2
        && sizeof(bmpDWord) == 4
        && !isBigEndian();
}

bool errmsg(const char* msg) {
    std::cout << "cvp_err:: " << msg << "\n";
    return false;
}

class bmpFileHeader {
public:
    bmpWord bfType;
    bmpDWord bfSize;
    bmpWord bfReserved1;
    bmpWord bfReserved2;
    bmpDWord bfOffBits; 

    bmpFileHeader() {
        bfType = 19778;
        bfReserved1 = 0;
        bfReserved2 = 0;
    };
};

class bmpInfoHeader {
public:
    bmpDWord biSize;
    bmpDWord biWidth;
    bmpDWord biHeight;
    bmpWord biPlanes;
    bmpWord biBitCount;
    bmpDWord biCompression;
    bmpDWord biSizeImage;
    bmpDWord biXPelsPerMeter;
    bmpDWord biYPelsPerMeter;
    bmpDWord biClrUsed;
    bmpDWord biClrImportant;

    bmpInfoHeader() {
        biPlanes = 1;
        biCompression = 0;
        biXPelsPerMeter = 3780;  
        biYPelsPerMeter = 3780;
        biClrUsed = 0;
        biClrImportant = 0;
        biWidth = 512;
        biHeight = 512;
        biBitCount = 8;
        
    };
};

typedef struct {
    bmpByte r, g, b, a;
} rgbaPix;

rgbaPix numToPix(ushort n) {
    rgbaPix temp;
    temp.r = n;
    temp.g = n;
    temp.b = n;
    temp.a = 0;
    return temp;
}

class BMP {
private:
    bool canWrite;

    inline bool fileRead(char* buf, ushort size, ushort number, FILE* fptr) {
        if (feof(fptr)) {
            return false;
        }
        return !(((ushort) fread(buf, size, number, fptr)) < number);
    }
    
    void r8bitRow(bmpByte* Buffer, ushort Row) {
        for (ushort i=0; i < 512; ++i) {
            Pixels[Row][i] = Buffer[i];
            histogram[ Pixels[Row][i] ] += 1;
        }
    };
    
    inline void w8bitRow(bmpByte* Buffer, ushort Row) {
        for (ushort i=0; i < 512; ++i) {
            Buffer[i] = Pixels[Row][i];
        }
    };
    
public:
    ushort Pixels[512][512];
    ulong histogram[256];
    bmpFileHeader bmfh;
    bmpInfoHeader bmih;

    BMP() {
        if (!typeChecks()) {
            errmsg("typechecks failed. Unsupported platform.");
        }
        
        for (ushort q=0; q < 256; ++q) {
            histogram[q] = 0;
        }
        
        canWrite = false;
    };
    
    ~BMP() {
        for (int q=0; q < 512; ++q) {
            delete[] Pixels[q];
        }
        delete[] Pixels;
        delete[] histogram;
    };
    
    void reset() {
        ushort y = 0, q = 0;
        for (; q < 256; ++q) {
            histogram[q] = 0;
        }
        for (q=0; q < 512; ++q) {
            for (; y < 512; ++y) {
                Pixels[q][y] = 0;
            }
        }
        
        canWrite = false;
    };

    void forcew() {
        canWrite = true;
    }
    
    bool write(const char* filepath) {
        FILE* fptr = fopen(filepath, "wb");
        if (fptr == NULL || !canWrite) {
            errmsg("Cannot write to file.");
            fclose(fptr);
            return false;
        }

        fwrite((char*) &(bmfh.bfType), 2, 1, fptr);
        fwrite((char*) &(bmfh.bfSize), 4, 1, fptr);
        fwrite((char*) &(bmfh.bfReserved1), 2, 1, fptr);
        fwrite((char*) &(bmfh.bfReserved2), 2, 1, fptr);
        fwrite((char*) &(bmfh.bfOffBits), 4, 1, fptr);

        fwrite((char*) &(bmih.biSize), 4, 1, fptr);
        fwrite((char*) &(bmih.biWidth), 4, 1, fptr);
        fwrite((char*) &(bmih.biHeight), 4, 1, fptr);
        fwrite((char*) &(bmih.biPlanes), 2, 1, fptr);
        fwrite((char*) &(bmih.biBitCount), 2, 1, fptr);
        fwrite((char*) &(bmih.biCompression), 4, 1, fptr);
        fwrite((char*) &(bmih.biSizeImage), 4, 1, fptr);
        fwrite((char*) &(bmih.biXPelsPerMeter), 4, 1, fptr);
        fwrite((char*) &(bmih.biYPelsPerMeter), 4, 1, fptr); 
        fwrite((char*) &(bmih.biClrUsed), 4, 1, fptr);
        fwrite((char*) &(bmih.biClrImportant), 4, 1, fptr);

        rgbaPix temp;
        for (ushort n=0; n < 256; ++n) {
            temp = numToPix(n);
            fwrite((char*) &temp, 4, 1, fptr);
        }

        int j = 0;
        bmpByte* Buffer = new bmpByte[512];

        j = 511;

        while (j > -1) {
            w8bitRow(Buffer, j);
            
            int BytesWritten = (int) fwrite((char*) Buffer, 1, 512, fptr);
            if (BytesWritten != 512) {
                j = -1;
            }
            
            --j; 
        }

        delete[] Buffer;
        fclose(fptr);
        
        return true;    
    };
    
    bool read(const char* filepath) {
        FILE* fptr = fopen(filepath, "rb");
        if (fptr == NULL) {
            return errmsg("Invalid filepath.");
        }
        
        bool safe = true;
        
        safe &= fileRead((char*) &(bmfh.bfType), 2, 1, fptr);

        safe &= fileRead((char*) &(bmfh.bfSize), 4, 1, fptr); 
        safe &= fileRead((char*) &(bmfh.bfReserved1), 2, 1, fptr);
        safe &= fileRead((char*) &(bmfh.bfReserved2), 2, 1, fptr);
        safe &= fileRead((char*) &(bmfh.bfOffBits), 4, 1 , fptr);

        safe &= fileRead((char*) &(bmih.biSize), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biWidth), 4, 1, fptr); 
        safe &= fileRead((char*) &(bmih.biHeight), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biPlanes), 2, 1, fptr); 
        safe &= fileRead((char*) &(bmih.biBitCount), 2, 1, fptr);

        safe &= fileRead((char*) &(bmih.biCompression), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biSizeImage), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biXPelsPerMeter), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biYPelsPerMeter), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biClrUsed), 4, 1, fptr);
        safe &= fileRead((char*) &(bmih.biClrImportant), 4, 1, fptr);
        
        if (!safe || bmih.biCompression >= 1 || bmih.biBitCount != 8) {
            fclose(fptr);
            return errmsg("Invalid bitmap. Cannot proceed with read operation.");
        }
        
        rgbaPix temp;
        for (ushort n=0; n < 256; ++n) {
            fileRead((char*) &temp, 4, 1, fptr);     
        }
        
        bmpByte* Buffer = new bmpByte[512];
        int j = 511;
        
        while (j > -1) {
            fread((char*) Buffer, 1, 512, fptr);
            
            r8bitRow(Buffer, j);
            
            --j;
        }
        
        delete[] Buffer; 
        fclose(fptr);
        
        canWrite = true;
        
        return true;
    };
};

Last edited by vkumar (2008-12-31 01:07:58)


div curl F = 0

Offline

Board footer

Powered by FluxBB