hye,
anybody know how to convert 8bit grayscale image to halftone or dither?
Would you share the source code for that? :)
micheal_lobster 0 Newbie Poster
mahlerfive 23 Junior Poster in Training
I have only dealt with bitmaps (.bmp), but essentially you need to open the file, read in the header information (stuff about how big the file is, width, height, # of colours, etc.) followed by the image data.
I'm assuming by dither or halftone, you mean to cut down the number of colours (like to black and white). If so, you would loop through the image data and change each pixel depending on the RGB value already there. If you are aiming to reduce the size of the image, you may need to process the pixels a bit differently and you will need to mess with the header.
The BMP file format can be found here: http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
micheal_lobster 0 Newbie Poster
could you show me some example of the source code? coz i'm still blur.
Thank you for reply..
mahlerfive 23 Junior Poster in Training
Here is how I load a bitmap in my bitmap class (note that my bitmap class only supports 24bit bitmaps):
// Loads bitmap from a file, converts to grayscale
bool Bitmap::load_bitmap_file( char *filename ) {
ifstream fileStream;
int fileLength;
bool previouslyLoaded = this->loaded;
this->loaded = false;
//open filename in read binary mode
fileStream.open( filename, ifstream::binary );
if( !fileStream.is_open() )
return false;
// get length of file:
fileStream.seekg (0, ios::end);
fileLength = fileStream.tellg();
fileStream.seekg (0, ios::beg);
//read the bitmap file header
fileStream.read( (char*)&( (this->bitmapFileHeader).bfType ), sizeof( WORD ) );
fileStream.read( (char*)&( (this->bitmapFileHeader).bfSize ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapFileHeader).bfReserved1 ), sizeof( WORD ) );
fileStream.read( (char*)&( (this->bitmapFileHeader).bfReserved2 ), sizeof( WORD ) );
fileStream.read( (char*)&( (this->bitmapFileHeader).bfOffBits ), sizeof( DWORD ) );
//verify that this is a bmp file by check bitmap id
if( (this->bitmapFileHeader).bfType != 0x4D42 ) {
fileStream.close();
return false;
}
//read the bitmap info header
fileStream.read( (char*)&( (this->bitmapInfoHeader).biSize ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biWidth ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biHeight ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biPlanes ), sizeof( WORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biBitCount ), sizeof( WORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biCompression ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biSizeImage ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biXPelsPerMeter ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biYPelsPerMeter ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biClrUsed ), sizeof( DWORD ) );
fileStream.read( (char*)&( (this->bitmapInfoHeader).biClrImportant ), sizeof( DWORD ) );
//move file point to the begging of bitmap data
fileStream.seekg( (this->bitmapFileHeader).bfOffBits );
//allocate enough memory for the bitmap image data
if( previouslyLoaded ) {
delete[] this->bitmapImage;
}
this->bitmapImage = new unsigned char[ (this->bitmapInfoHeader).biHeight * (this->bitmapInfoHeader).biWidth * 3 ];
//verify memory allocation
if( bitmapImage == NULL ) {
fileStream.close();
return false;
}
//read in the bitmap image data
unsigned char junk[4];
for( int i = 0; i < (this->bitmapInfoHeader).biHeight; i++ ) {
fileStream.read( (char*) &(this->bitmapImage[i*(this->bitmapInfoHeader).biWidth * 3]), (this->bitmapInfoHeader).biWidth * 3 );
// Discard padding bytes
if( (this->bitmapInfoHeader).biWidth % 4 != 0 ) {
fileStream.read( (char*)junk, (this->bitmapInfoHeader).biWidth % 4 );
}
}
//make sure bitmap image data was read
if( bitmapImage == NULL ) {
fileStream.close();
return false;
}
// Bitmap is BGR
for( int imageIdx = 0; imageIdx < (this->bitmapInfoHeader).biHeight * (this->bitmapInfoHeader).biWidth * 3; imageIdx+=3 ) {
unsigned char temp = this->bitmapImage[imageIdx];
this->bitmapImage[imageIdx] = this->bitmapImage[imageIdx + 2];
this->bitmapImage[imageIdx + 2] = temp;
}
// Copy filename
if( previouslyLoaded ) {
delete[] this->filename;
}
this->filename = new char[ strlen(filename) + 1 ];
strcpy( this->filename, filename );
//close file
fileStream.close();
this->loaded = true;
this->print_info();
return true;
}
Here is an example of how to alter the image data:
/**
* Converts entire image to monochrome (black/white).
**/
bool Bitmap::convert_to_monochrome( int threshold ) {
for( int i = 0; i < (this->bitmapInfoHeader).biHeight * (this->bitmapInfoHeader).biWidth * 3; i++ ) {
if( this->bitmapImage[i] > threshold ) {
this->bitmapImage[i] = 255;
}
else {
this->bitmapImage[i] = 0;
}
}
return true;
}
Note that the above method already assumes we have a grayscale image (i was only working with grayscale). Grayscale images always have R, G, and B values that are equal. The threshold is the number at which we separate black from white, so commonly you would use 127 in this case (0-127 = black, 128-255 = white).
micheal_lobster 0 Newbie Poster
wow! amazing..
nice explanation.. i'll try this out..
thank you for helping me..
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.