16bit grayscale MultiTIFFの読み込み

Linux

はじめに

これまで自作の関数でMulti TIFFファイルを書いたり、読んだりしていたのですが、libtiffライブラリを使ってみることにしました。
私が使うデータは主に8bit、16bitのグレースケールです。
今回は16bit(unsigned short int)グレースケールMulti TIFFの読み込みです。
読み込んだMulti TIFFファイルをSingle TIFFファイルにバラしています。
Single TIFFファイルの書き込みは以前の記事を流用しています。
ImageJなどを使えばMultiTIFFをバラしたり、作成したり出来ますが、プログラムを作っていると自前で行う場面も多いため、メモしておきます。
Windows、Linuxで解析を行うので、両方でコンパイルできるようにしています。
コンパイルの方法は「libtiffの環境構築」を参照。

ソース

環境によっては「nodefaultlib」を付けなくてもコンパイルは通ります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __GNUC__
#include <tiffio.h>
#endif

#ifdef _WIN32
#include "tiffio.h"
#ifdef _DEBUG
#pragma comment(linker, "/nodefaultlib:\"libcmtd.lib\"")
#else
#pragma comment(linker, "/nodefaultlib:\"libcmt.lib\"")
#endif
#pragma comment(lib, "libtiff.lib")
#endif

// 16bit TIFF
#define BIT_COUNT 16

int tiff_count_directory( TIFF * );
void tiff_write( uint16 *, int, int, int );

int main( int argc, char **argv )
{
    int     i, j, k;
    int     width, height;
    uint32  tifsize;
    uint16  samplesperpixel, bitspersample;
    uint16  photometric, fillorder, compression;
    uint16  orientation, resunit, planarconfig;
    uint16  *buf, *line; // unsigned shrot int
    TIFF    *tif;
    int     dircount;

    tif = TIFFOpen("hoge-16bit-multi.tif", "r");
    if ( tif == NULL )
    {
        printf("ERROR: Can not open tiff file \n");
        exit( EXIT_FAILURE );
    }

    // MultiTIFFのDirectory数を取得する
    dircount = TIFFNumberOfDirectories( tif );
    // dircount = tiff_count_directory( tif );
    printf("TIFF Directories: %d \n", dircount);
    // return EXIT_SUCCESS;

    // Tagを読み込む
    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
    TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
    TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
    TIFFGetField(tif, TIFFTAG_FILLORDER, &fillorder);
    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
    TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation);
    TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);

    // 確認
    printf("width: %d \n", width);
    printf("height: %d \n", height);
    printf("bitspersample: %d \n", bitspersample);
    printf("samplesperpixel: %d \n", samplesperpixel);
    printf("compression: %d \n", compression);
    printf("photometric: %d \n", photometric);
    printf("fillorder: %d \n", fillorder);
    printf("planarconfig: %d \n", planarconfig);
    printf("resunit: %d \n", resunit);

    // Error Check
    if ( width <= 0 || height <= 0 )
    {
        printf("ERROR: width or height is error \n");
        exit( EXIT_FAILURE );
    }
    if ( samplesperpixel != 1 )
    {
        printf("ERROR: Only samples/pixel = 1 \n");
        exit( EXIT_FAILURE );
    }
    if ( bitspersample != BIT_COUNT )
    {
        printf("ERROR: Only 16-bit samples \n");
        exit( EXIT_FAILURE );
    }

    // 画像の領域確保
    tifsize = width * height * sizeof( uint16 );
    buf     = ( uint16 * )malloc( tifsize );
    if ( buf == NULL )
    {
        printf("ERROR: Can not get memory [buf] \n");
        exit( EXIT_FAILURE );
    }

    // 画像1ライン分の領域確保
    line = ( uint16 * )_TIFFmalloc( TIFFScanlineSize( tif ) );
    // line = ( uint16 * )_TIFFmalloc( width * 1 * sizeof( uint16 ) );
    if ( line == NULL )
    {
        printf("ERROR: Can not get memory [line] \n");
        exit( EXIT_FAILURE );
    }

    // 画像情報を読み込む・書き込む
    for ( k = 0; k < dircount; k++ )
    {
        if ( ! TIFFSetDirectory( tif, k ) )
        {
            printf("ERROR: Can not set TIFF directory [TIFFSetDirectory] \n");
            exit( EXIT_FAILURE );
        }

        for ( i = 0; i < height; i++ )
        {
            if ( TIFFReadScanline( tif, line, i, 0 ) < 0 )
            {
                printf("ERROR: Can not get TIFF line [TIFFReadScanline] \n");
                exit( EXIT_FAILURE );
            }

            for ( j = 0; j < width; j++ )
            {
                buf[width * i + j] = line[j];
            }
        }
        tiff_write( buf, width, height, k );
    }

    _TIFFfree( line );
    TIFFClose( tif );
    free( buf );
    return EXIT_SUCCESS;
}

//
// TIFFのDirectory数を数える
//
int tiff_count_directory( TIFF *tif )
{
    int cnt = 0;

    do
    {
        cnt++;
    } while ( TIFFReadDirectory( tif ) );

    return cnt;
}

//
// single TIFFファイルを保存する
//
void tiff_write( uint16 *buf, int width, int height, int k )
{
    char   fname[FILENAME_MAX];
    char   tiftitle[FILENAME_MAX] = { '\0' };
    uint16 samplesperpixel, bitspersample;
    uint32 tifsize;
    double resolution;
    TIFF   *tif;

    resolution      = 72.0;
    bitspersample   = BIT_COUNT;
    samplesperpixel = 1;

    // 画像データの保存
    sprintf( fname, "%s_%03d.tif", "out", k );
    tif = TIFFOpen( fname, "w" );

    if ( tif == NULL )
    {
        printf("ERROR: Can not open tiff file \n");
        exit( EXIT_FAILURE );
    }

    strcpy(tiftitle, "Test program");
    tifsize = width * height * sizeof( uint16 );

    TIFFSetField(tif, TIFFTAG_SOFTWARE, tiftitle);
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, resolution);
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, resolution);
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);

    TIFFWriteEncodedStrip(tif, 0, buf, tifsize);

    TIFFClose( tif );
}


Comments