Posts tagged ‘libtiff’

Rotate image by 180 degrees (libtiff code)

Fastish inplace rotation of an image by 180 degrees:

  void rotate180() {

    size_t h;
    if((m_height%2) == 1) {
      h = (m_height/2)-1;
      size_t ymid = ((m_height-1)/2);

      for(size_t x=0;x<(m_width/2);x++) {
        swap_pixel(x,ymid,(m_width-x-1),ymid);
      }

    } else h = (m_height/2)-1;
    for(size_t x=0;x<m_width;x++) {
      for(size_t y=0;y<=h;y++) {
        swap_pixel(x,y,m_width-x-1,m_height-y-1);
      }
    }
  }

You need to provide image get and set, and swap_pixel. Complete example below:

#include "tiffio.h"
#include <iostream>
#include <math.h>
#include <vector>
#include <map>
#include <sys/stat.h>
#include <sys/types.h>
#include <sstream>
#include <stdexcept>

#define TIFFSetR(pixel, x) ((unsigned char *)pixel)[0] = x
#define TIFFSetG(pixel, x) ((unsigned char *)pixel)[1] = x
#define TIFFSetB(pixel, x) ((unsigned char *)pixel)[2] = x
#define TIFFSetA(pixel, x) ((unsigned char *)pixel)[3] = x


class BadConversion : public std::runtime_error {
public:
 BadConversion(const std::string& s)
      : std::runtime_error(s) {}
};

template<class _type>
inline std::string stringify(_type x)
{
  std::ostringstream o;
  if (!(o << std::fixed << x))
    throw BadConversion("stringify()");
  return o.str();
}

using namespace std;

class Image {

public:

  Image() {
  }

  enum fragment_type { frag_type_arrow, frag_type_rectange } ;

  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);
  }

  bool is_on_image(size_t x,size_t y) {
    if((x < m_width) && (y < m_height)) return true;
    return false;
  }

  uint32_t get(size_t x,size_t y) {
    return m_image_data[(y*m_width)+x];
  }

  void set(size_t x,size_t y,uint32_t value) {
    m_image_data[(y*m_width)+x] = value;
  }

  void swap_pixel(size_t x1,size_t y1,
                  size_t x2,size_t y2) {

    uint32_t t = get(x1,y1);
    set(x1,y1,get(x2,y2));
    set(x2,y2,t);
  }

  // Inplace 180 degree rotation.
  void rotate180() {

    size_t h;
    if((m_height%2) == 1) {
      h = (m_height/2)-1;
      size_t ymid = ((m_height-1)/2);

      for(size_t x=0;x<(m_width/2);x++) {
        swap_pixel(x,ymid,(m_width-x-1),ymid);
      }

    } else h = (m_height/2)-1;
    for(size_t x=0;x<m_width;x++) {
      for(size_t y=0;y<=h;y++) {
        swap_pixel(x,y,m_width-x-1,m_height-y-1);
      }
    }
  }

  vector<uint32_t> m_image_data;
  size_t m_width;
  size_t m_height;
};

int main(int argc, char* argv[]) {

  Image i;
  i.load_tiff(argv[1]);
  i.rotate180();
  i.save_tiff_rgb(string(argv[2]));
}

(A VERY BAD) Image rotation algorithm using libtiff

The following program rotates a tiff image. I pretty much made up the algorithm myself, and it relies on my rather dodgy trigonometry. There are almost certainly computationally less expensive ways of doing this.

Two methods are present, but the main function only uses (rotate_source). This iterates over pixels in the source image and places them in the correct location in the destination image. The alternative is to iterate over the destination image, this ensures there are no missing datapoints at the destination. However, this method is slower, and the result can look worse.

The disadvantage of the faster method is that there maybe gaps is the rotated image. To get round this I have a quick hack called “fill_gaps” which does some very lazy interpolation to fill in the gaps.

You can compile the code as:

g++ rotation.cpp -ltiff -o rotation

And then execute it as:

./rotation input.tif

The program will then write a series of files named imgN.tif where N is an integer. Each of these files will contain a rotated copy of the original image in 0.1 radian increments.

On a Mac you can use the following to get Preview to open all these files in one window, and display them in the correct order:

ls img*.tif | awk 'BEGIN{FS="g";}{print $0 " " $2}' |sort -n -k 2 | awk '{print $1}' | xargs open

#include “tiffio.h”
#include
#include
#include
#include

#include “stringify.h”
#include
#include
#include
#include
#include

class BadConversion : public std::runtime_error {
public:
BadConversion(const std::string& s)
: std::runtime_error(s) {}
};

template
inline std::string stringify(_type x)
{
std::ostringstream o;
if (!(o << std::fixed << x)) throw BadConversion("stringify()"); return o.str(); } #define TIFFSetR(pixel, x) ((unsigned char *)pixel)[0] = x #define TIFFSetG(pixel, x) ((unsigned char *)pixel)[1] = x #define TIFFSetB(pixel, x) ((unsigned char *)pixel)[2] = x #define TIFFSetA(pixel, x) ((unsigned char *)pixel)[3] = x using namespace std; void rotate_point(double x, double y, double o_x, double o_y, double radians, double &r_x, double &r_y) { //1. calculate theta //tan theta = opp (y) / adj (x) double dx = x - o_x; double dy = y - o_y; if(dx < 0) dx = 0-dx; if(dy < 0) dy = 0-dy; int q=1; if((x > o_x) && (y >= o_y)) q = 1;
if((x >= o_x) && (y < o_y)) q = 2; if((x < o_x) && (y <= o_y)) q = 3; if((x <= o_x) && (y > o_y)) q = 4;
double theta;
if(q == 1) theta = atan(dy/dx);
if(q == 2) theta = atan(dx/dy);
if(q == 3) theta = atan(dy/dx);
if(q == 4) theta = atan(dx/dy);

double h = sqrt(dx*dx + dy*dy);

if((dy==0) || (dx==0)) theta = 0;

theta -= radians;

for(;theta < 0;) { theta = 0 - theta; theta = ((2*3.14)/4) - theta; q++; if(q==5) q=1;} for(;theta > ((2*3.14)/4);) {theta -= ((2*3.14)/4); q–; if(q==0) q=4; }

if(q == 1) { r_y = (sin(theta) * h); r_x = (cos(theta) * h); }
if(q == 2) { r_x = (sin(theta) * h); r_y = (cos(theta) * h); }
if(q == 3) { r_y = (sin(theta) * h); r_x = (cos(theta) * h); }
if(q == 4) { r_x = (sin(theta) * h); r_y = (cos(theta) * h); }

if(q == 1) {r_x = o_x + r_x; r_y = o_y + r_y;}
if(q == 2) {r_x = o_x + r_x; r_y = o_y – r_y;}
if(q == 3) {r_x = o_x – r_x; r_y = o_y – r_y;}
if(q == 4) {r_x = o_x – r_x; r_y = o_y + r_y;}

}

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(m_width*m_height,0);
}

Image rotate(size_t o_x,size_t o_y,double radians,uint32_t bg_val) {
return rotate_source(o_x,o_y,radians,bg_val);
}

Image rotate_source(size_t o_x,size_t o_y,double radians,uint32_t bg_val) {

Image new_image; // image to copy data in to

size_t pad;
if(m_width > m_height) pad = m_width;
else pad = m_height;
new_image.m_width = pad*4;
new_image.m_height = pad*4;
new_image.zero_image();

for(uint32_t cx=0;cx adjs;
adjs.push_back(get(x+1,y));
adjs.push_back(get(x-1,y));
adjs.push_back(get(x,y+1));
adjs.push_back(get(x,y-1));

int perform_set=0;
for(size_t n=0;n m_height) pad = m_width;
else pad = m_height;
new_image.m_width = pad*4;
new_image.m_height = pad*4;
new_image.zero_image();

for(int32_t cx=0-pad;cx m_image_data;
size_t m_width;
size_t m_height;
};

int main(int argc, char* argv[]) {

Image i;
i.load_tiff(string(argv[1]));

int n=0;
for(double r=0;r<(2*3.141);r+=0.1) { //Image i2 = i.rotate(i.m_width/2,i.m_height/2,1.78525,0); Image i2 = i.rotate(i.m_width/2,i.m_height/2,r,0); //Image i2 = i.rotate(0,0,r,0); for(int x=0;x<10;x++) { for(int y=0;y<10;y++) { i2.set(x,y,0xFFFFFFFF); } } i2.fill_gaps(0); i2.save_tiff_rgb(string("img") + stringify(n) + string(".tif")); n++; } } [/sourcecode]

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&#91;n&#93;);
	}
	_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&#91;0&#93;, 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&#91;0&#93;, 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&#91;n&#93;/(256*256*256)));
    }

    // Write the information to the file
    TIFFWriteEncodedStrip(output_image, 0, &data&#91;0&#93;, 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&#91;n&#93;);
      double g = TIFFGetG(m_image_data&#91;n&#93;);
      double b = TIFFGetB(m_image_data&#91;n&#93;);

      double grey = (0.3*r) + (0.59*g) + (0.11*b); // See http://en.wikipedia.org/wiki/Grayscale
      m_image_data&#91;n&#93; = 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.

Simple libtiff Example

First, you have to install libtiff. On Linux it’s almost certainly in your repository you should install a package with an name similar to libtiff-dev.

On MacOS X I did the following:

curl ftp://ftp.remotesensing.org/pub/libtiff/tiff-3.9.5.zip > tiff-3.9.5.zip
tar xvzf tiff-3.9.5.zip
cd tiff-3.9.5
./configure
make
sudo make install

Then create the following cpp file:

#include "tiffio.h"
#include <iostream>

using namespace std;

main(int argc, char* argv[])
{

  TIFF* tif = TIFFOpen(argv[1], "r");
  if (tif) {
    uint32 w, h;
    size_t npixels;
    uint32* raster;

    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
    npixels = w * h;

    raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
    if (raster != NULL) {
      if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {


        cout << "P2" << endl;
        cout << w << " " << h << endl;
        cout << 255 << endl;

        for(size_t c_h=0;c_h<h;c_h++) {
          for(size_t c_w=0;c_w<w;c_w++) {
            cout << raster&#91;(w*h)-((c_h*w)+(w-c_w))&#93;%256 << " ";
          }
          cout << endl;
        }

      }
      _TIFFfree(raster);
    }
    TIFFClose(tif);
  }
}
&#91;/sourcecode&#93;

This program converts a tiff file to a PGM (portable grey map) file. PGM is a simple text based format, this makes it very easy to debug. You can read more about PGM on <a href="http://en.wikipedia.org/wiki/Portable_graymap">wikipedia</a>.

Note: It's not converting the RGB value to grey very well it's simply modding the value for the example.

Compile the program as follow (on MacOS you'll need to have install XCode or another gcc version):

[sourcecode language="bash"]
g++ tiffsimple.cpp -ltiff

Then run it as:

./a.out inputfile.tif

You can view the resulting PGM file with ImageMagick.

Notes

You can also transform the TIFF coordinates rather than performing the transformation yourself when converting to PGM as follows:

#include “tiffio.h”
#include

using namespace std;

main(int argc, char* argv[])
{

TIFF* tif = TIFFOpen(argv[1], “r”);
if (tif) {
uint32 w, h;
size_t npixels;
uint32* raster;

TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;

raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, w, h, raster,ORIENTATION_TOPLEFT, 0)) {

cout << "P2" << endl; cout << w << " " << h << endl; cout << 255 << endl; for(size_t c_h=0;c_h