8

I am trying to understand images some more, and I'm having a great deal of trouble. From using matlab, I have experience in using imread('test.tif'), and getting a beautiful matrix of rows vs. columns, where you have the intensity of each pixel as an integer. So, a 720 x 250 image will give a 720 x 250 matrix, where each cell contains the intensity of the pixel, on a scale from 0-255 (depending on the data type). So, 0 was black, 255 was white.

It was so simple and made so much sense. Now I am attempting to use libtiff, and I am really struggling. I want to do the same thing--access those pixels, and I just can't get it.

I have the following code:

int main(int argc, char *argv[]){
  TIFF* tif = TIFFOpen( argv[1], "r");
    FILE *fp = fopen("test2.txt", "w+");

  if (tif) {
      int * buf;
      tstrip_t strip;
      uint32* bc;
      uint32 stripsize;
  TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
  stripsize = bc[0];
  buf   = _TIFFmalloc(stripsize);
  for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++ ) {
      if( bc[strip] > stripsize) {
          buf = _TIFFrealloc(buf, bc[strip]);
          stripsize = bc[strip];
      }
      TIFFReadRawStrip(tif, strip, buf, bc[strip]);
  }
  int i;
  for (i=0; i<stripsize; i++) {
      if ( i % 960 ==0 )
          fprintf(fp, "\n");
      fprintf(fp,"%d ",  buf[i]);
  }
  _TIFFfree(buf);
  TIFFClose(tif);
  }
  exit(0);
}

But I get completely meaningless results--just completely wacked out numbers. Nothing like the numbers I see when I load the image in matlab.

How can I simply access the pixel values, and look at them?

Thanks so much.

The_Anomaly
  • 83
  • 1
  • 1
  • 3
  • I never used libtiff, but it looks like you are reading the raw image data. Tiff file format can contain raw image data but also compressed formats. So maybe the data is still compressed. – Lucas Mar 29 '11 at 23:37
  • 1
    Start by paying attention to the return value of these functions. You have no idea whether the function failed or not. – Hans Passant Mar 30 '11 at 00:09

3 Answers3

7

I think you should read Using The TIFF Library article. It contains enough information to get started with libtiff.

Here is some code to read image scanlines and print values of each sample.

main()
{
    TIFF* tif = TIFFOpen("myfile.tif", "r");
    if (tif) {
        uint32 imagelength;
        tsize_t scanline;
        tdata_t buf;
        uint32 row;
        uint32 col;

        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
        scanline = TIFFScanlineSize(tif);
        buf = _TIFFmalloc(scanline);
        for (row = 0; row < imagelength; row++)
        {
            TIFFReadScanline(tif, buf, row);
            for (col = 0; col < scanline; col++)
                printf("%d ", buf[col]);

            printf("\n");
        }
        _TIFFfree(buf);
        TIFFClose(tif);
    }
}
Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
  • 2
    error: too few arguments to function ‘TIFFReadScanline’ – malat Feb 04 '15 at 12:58
  • @EdS. Please define 'default value for last arg' for a C function. Also open in a shell the man page: `$ man TIFFReadScanline` – malat Aug 21 '17 at 09:27
  • @malat: I do remember leaving a comment here a while back, but it seems to be gone now. Anyway... Bobrovsky is using C++ here and the OP is using C. I guess I wasn't clear on that in my now non-existent comment. Here is the declaration if `c_plusplus || __cplusplus` is defined: `extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);` – Ed S. Aug 22 '17 at 18:04
3

Regarding this article, I think it'll be better to use TIFFRGBAImage approach, because as it turned out TIFF file could be one of different formats: tiled, scanline-based and strip-oriented. Here's an example from the same article.

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)) {
            ...process raster data...
        }
        _TIFFfree(raster);
    }
    TIFFClose(tif);
}
kmityak
  • 461
  • 5
  • 11
3

raster is a uint32 array (maximum value= 0xffffffff) but you are trying to read a 16-bit array (maximum value 0xffff). you will run into 32bit to 16bit conversion problems. Reading the scanline method is the better way to do it. This way you can convert the void* buf to uint16* and access the pixel values.

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <inttypes.h>
#include "tiffio.h"


using namespace std;


void printArray(uint16 * array, uint16 width);
int main()
{


    TIFF* tif = TIFFOpen("16bit_grayscale_image.tif", "r");
     if (tif) {
    uint32 imagelength,height;
    tdata_t buf;
    uint32 row;
    uint32 config;

    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
    buf = _TIFFmalloc(TIFFScanlineSize(tif));


        uint16 s, nsamples;
        uint16* data;
        TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples);
        for (s = 0; s < nsamples; s++)
        {
            for (row = 0; row < imagelength; row++)
                {
                TIFFReadScanline(tif, buf, row, s);
                data=(uint16*)buf;
                printArray(data,imagelength);
                }
                // printArray(data,imagelength,height);
        }


    _TIFFfree(buf);
    TIFFClose(tif);
    }
    exit(0);
}



void printArray(uint16 * array, uint16 width)
{
    uint32 i;
    for (i=0;i<width;i++)
    {
        printf("%u ", array[i]);
    }
        printf("\n");


}