あまり一般的には知られていないようですが、TIFFファイルはピクセルの値に
浮動小数を持つことができます。
もっとも、この形式をサポートするソフトは少なく、
PhotoshopやGIMPでも読み込めません。
読み込みが可能なのは、筆者の手元にあるソフトでは、QGIS、GRASS、OpenEV、Ossimでした。
書き込み
以下では、グレイスケールの浮動小数ピクセルの書き込みの例を示します。
#include <tiffio.h> #include <windows.h> BOOL WriteTIFF( LPCTSTR lpszFName, int nImageWidth, int nImageLength, float *pImg ) { int nRowsPerStrip; int nStripSize; int nRow; int nStrip = 0; int i, j; float *pData = pImg; WORD wRed[256], wGreen[256], wBlue[256]; TIFF *pOut = TIFFOpen( lpszFName, "w" ); if ( !pOut ) { return FALSE; } if ( TIFFSetField( pOut, TIFFTAG_IMAGEWIDTH, nImageWidth ) != 1 ) return false; //横 if ( TIFFSetField( pOut, TIFFTAG_IMAGELENGTH, nImageLength ) != 1 ) return false; //縦 if ( TIFFSetField( pOut, TIFFTAG_COMPRESSION, COMPRESSION_NONE ) != 1 ) return false; //圧縮形式 if ( TIFFSetField( pOut, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK ) != 1 ) return false; //種別 if ( TIFFSetField( pOut, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(pOut, 0) ) != 1 ) return false; //ストリップあたり行数 if ( TIFFSetField( pOut, TIFFTAG_SAMPLESPERPIXEL, 1 ) != 1 ) return false; //色数 if ( TIFFSetField( pOut, TIFFTAG_BITSPERSAMPLE, 32 ) != 1 ) return false; //色深度 if ( TIFFSetField( pOut, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ) != 1 ) return false; //PLANARCONFIG if ( TIFFSetField( pOut, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ) != 1 ) return false; //Orientation if ( TIFFSetField( pOut, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP ) != 1 ) return false; if ( TIFFSetField( pOut, TIFFTAG_MINSAMPLEVALUE, 0 ) != 1 ) return false; if ( TIFFSetField( pOut, TIFFTAG_MAXSAMPLEVALUE, 11 ) != 1 ) return false; TIFFGetFieldDefaulted( pOut, TIFFTAG_ROWSPERSTRIP, &nRowsPerStrip ); for ( i = 0; i < nImageLength; i += nRowsPerStrip ) { nRow = ( i+nRowsPerStrip > nImageLength ) ? nImageLength - i : nRowsPerStrip; nStripSize = TIFFVStripSize( pOut, nRow ); if ( TIFFWriteEncodedStrip( pOut, nStrip++, pData, nStripSize ) < 0 ) { TIFFClose( pOut ); return FALSE; } pData += nRowsPerStrip*nImageWidth; } TIFFClose( pOut ); }
太字部分がポイントです。
TIFFTAG_SAMPLEFORMAT
をSAMPLEFORMAT_IEEEFP
にすることで、float型を持つようになります。
もう1箇所BITSPERSAMPLE
の指定も必須で、float型のビット数を指定します。
こうしないとTIFFTAG_SAMPLEFORMAT
でSAMPLEFORMAT_IEEEFP
を指定しても
正しい画像を作成できません。
あとは普通にfloat型の配列を書き込めます。
読み込み
これも特に難しいところは無く、libtiffが読み込んだデータを受け取るバッファをfloat型配列にすれば良いです。
#include <tiffio.h> #include <stdlib.h> int main( int argc, char *argv[] ) { int nImageLength, nImageWidth; int nBitsPerSample, nSamplePerPixel; int nSampleFormat; int nRowsPerStrip; int nPhotometric; int nRow; int nStrip = 0; float *pfPix; int i, j; TIFF *pTif = TIFFOpen( argv[1], "r" ); TIFFGetField( pTif, TIFFTAG_IMAGEWIDTH, &nImageWidth ); TIFFGetField( pTif, TIFFTAG_IMAGELENGTH, &nImageLength ); TIFFGetField( pTif, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample ); TIFFGetField( pTif, TIFFTAG_SAMPLESPERPIXEL, &nSamplePerPixel ); TIFFGetField( pTif, TIFFTAG_ROWSPERSTRIP, &nRowsPerStrip ); TIFFGetField( pTif, TIFFTAG_PHOTOMETRIC, &nPhotometric ); TIFFGetField( pTif, TIFFTAG_SAMPLEFORMAT, &nSampleFormat ); if ( nSampleFormat == SAMPLEFORMAT_IEEEFP ) { pfPix = new float[nImageWidth*nRowsPerStrip]; for ( i = 0; i < nImageLength; i += nRowsPerStrip ) { nRow = (i + nRowsPerStrip > nImageLength) ? nImageLength - i : nRowsPerStrip; nStrip = TIFFVStripSize( pTif, nRow ); if ( TIFFReadEncodedStrip( pTif, TIFFComputeStrip ( pTif, i, 0 ), pfPix, nStrip ) == -1 ) { fprintf( stderr, "ahokan" ); delete[] pfPix; TIFFClose( pTif ); exit( 1 ); } //何か適当な処理 } delete[] pfPix; } TIFFClose( pTif ); return 0; }
ほとんど用途はないかと思いますが、DEMデータの保存なんかに良いでしょう。
おそらくそういう用途を想定してGIS系ソフトではサポートされているのでしょう。