libtiff RGB image to greyscale + loading and saving
This example shows you how to load a RGB tiff image, convert it to greyscale and save it as 32 and 8bit greyscale images. It will also write the same RGB image to another file.
#include "tiffio.h" #include <iostream> #include <math.h> #include <vector> using namespace std; class Image { public: Image() { } void load_tiff(string input_filename) { m_image_data.clear(); TIFF* tif = TIFFOpen(input_filename.c_str(), "r"); if (tif) { uint32 w, h; size_t npixels; uint32* raster; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); npixels = w * h; m_width = w; m_height = h; raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); if (raster != NULL) { if (TIFFReadRGBAImageOriented(tif, w, h, raster,ORIENTATION_TOPLEFT, 0)) { for(size_t n=0;n<npixels;n++) m_image_data.push_back(raster[n]); } _TIFFfree(raster); } TIFFClose(tif); } } void save_tiff_rgb(string output_filename) { TIFF *output_image; // Open the TIFF file if((output_image = TIFFOpen(output_filename.c_str(), "w")) == NULL){ cerr << "Unable to write tif file: " << output_filename << endl; } // We need to set some values for basic tags before we can add any data TIFFSetField(output_image, TIFFTAG_IMAGEWIDTH, m_width); TIFFSetField(output_image, TIFFTAG_IMAGELENGTH, m_height); TIFFSetField(output_image, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output_image, TIFFTAG_SAMPLESPERPIXEL, 4); TIFFSetField(output_image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output_image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output_image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); // Write the information to the file TIFFWriteEncodedStrip(output_image, 0, &m_image_data[0], m_width*m_height * 4); // Close the file TIFFClose(output_image); } void save_tiff_grey_32bit(string output_filename) { TIFF *output_image; // Open the TIFF file if((output_image = TIFFOpen(output_filename.c_str(), "w")) == NULL){ cerr << "Unable to write tif file: " << output_filename << endl; } // We need to set some values for basic tags before we can add any data TIFFSetField(output_image, TIFFTAG_IMAGEWIDTH, m_width); TIFFSetField(output_image, TIFFTAG_IMAGELENGTH, m_height); TIFFSetField(output_image, TIFFTAG_BITSPERSAMPLE, 32); TIFFSetField(output_image, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(output_image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output_image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output_image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); // Write the information to the file TIFFWriteEncodedStrip(output_image, 0, &m_image_data[0], m_width*m_height * 4); // Close the file TIFFClose(output_image); } void save_tiff_grey_8bit(string output_filename) { TIFF *output_image; // Open the TIFF file if((output_image = TIFFOpen(output_filename.c_str(), "w")) == NULL){ cerr << "Unable to write tif file: " << output_filename << endl; } // We need to set some values for basic tags before we can add any data TIFFSetField(output_image, TIFFTAG_IMAGEWIDTH, m_width); TIFFSetField(output_image, TIFFTAG_IMAGELENGTH, m_height); TIFFSetField(output_image, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output_image, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(output_image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(output_image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output_image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); // convert data to 8bit vector<uint8_t> data; for(size_t n=0;n<m_image_data.size();n++) { data.push_back(255-(m_image_data[n]/(256*256*256))); } // Write the information to the file TIFFWriteEncodedStrip(output_image, 0, &data[0], m_width*m_height); // Close the file TIFFClose(output_image); } void make_greyscale() { for(size_t n=0;n<m_image_data.size();n++) { double r = TIFFGetR(m_image_data[n]); double g = TIFFGetG(m_image_data[n]); double b = TIFFGetB(m_image_data[n]); double grey = (0.3*r) + (0.59*g) + (0.11*b); // See http://en.wikipedia.org/wiki/Grayscale m_image_data[n] = grey * 256 * 256 * 256; } } vector<uint32_t> m_image_data; size_t m_width; size_t m_height; }; int main(int argc, char* argv[]) { Image input; input.load_tiff(string(argv[1])); input.save_tiff_rgb(string(argv[2])); input.make_greyscale(); input.save_tiff_grey_32bit(string(argv[3])); input.save_tiff_grey_8bit(string(argv[4])); }
Compile as:
g++ makegrey.cpp -ltiff
And run as:
./a.out inputfilename.tif rgb.tif 8bitgrey.tif 32bitgrey.tif
Note: The 8bit version is slightly different than the 32bit version. It converts the data such that 0 represents white. This is because Preview.app, at least in MacOS X Lion, does not seem to be able to cope with 0 being black.
This has not been applied to the 32bit output, so this will display incorrectly in Preview. However it will display correctly in Imagemagick.