libgeotiff

ライセンスMIT/X ?
URLhttp://trac.osgeo.org/geotiff/

GeoTIFFを扱うライブラリで、libtiffと併せて使用するものです。

コンパイル

v1.2.5

先にlibtiffをコンパイル、インストールしておく必要があります。

MinGWならconfigure --prefix=/c/mingwmake、make install
で普通にできますが、DLLは作れません。

nmakeは大変で、libtiffをまずnmakeでコンパイルしておく必要があります。これが少々大変。
コンパイルが済んでいれば、makefile.vcのTIFF_DIRのところをlibtiffのディレクトリに
書き換えて、nmakeを実行します。

インクルード

使い方によりますが、複数インクルードする必要があります。
ライブラリ付属のgeotifcpでは、geotiff.h、geo_normalize.h、geo_tiffp.h、geo_keyp.h、xtiffio.h、cpl_serv.h
がインクルードされています。

基本的な使い方

GeoTIFF情報はタグに保存されているものと、キーと呼ばれる情報に保存されているものがあります。
キーはGEOKEYDIRECTORYタグに保存されているようです。

タグに保存されている情報は、座標値、ピクセルの地上解像度などで、これだけでも事足りる場合もあります。
ただし、ソフトウェアによってはGEOKEYDIRECTORYが無いとGeoTIFFとみなされない場合もあるようです。

画像の地上での位置情報を表す方法は2種類あり、ModelTiepointTagModelPixelScaleTag
を定義するか、もしくはModelTransformationTagを定義するかのどちらかです。

ModelTiepointTagは6つのdouble値が記録されており、前の3つが画像座標(u,v,w)、あとの3つが地上座標
(x,y,z)で、両者がそれぞれ対応しますよという意味になります。
なので、タグの値が{0,0,0,-10,-20,0}となっている場合は、画像の左上が地上座標(-10,-20)になるという意味になります。
ほとんどの場合画像の左上座標が使用されますが、別にそうでなくてもいいです。
Z値も使うことは一応できますが、通常は0であり、
GeoTIFFベースラインではソフトウェアは必ずしも対応しなくてもよいということになっています。

ModelPixelScaleTagは3つのdouble値が記録されており、
それぞれX方向解像度、Y方向解像度、Z方向解像度が記録されます。
ModelTiepointTagModelPixelScaleTagで画像の地上座標を定義した場合は
必ず北上になり、回転は表現することができません。

一方、ModelTransformationTagは4X4の変換行列そのものを記録するもので、
したがって16個のdouble値が記録されます。
変換行列そのものなので、回転も表現することができます。

キーには、座標系、投影法、座標原点の経緯度、縮尺係数などが記録されます。
キーはたくさんの種類があるので、詳しくはオリジナルのドキュメントを参照してください。

読み込み

GeoTIFFの場合は、XTIFFOpen()関数でTIFFファイルを開きます。
この関数で開くことによって、GeoTIFFの拡張タグの情報を読み込むことができるようになります。

キーにアクセスする場合はGTIFNew()関数にTIFF型のポインタを渡します。

大体以下のようなコードになるかと思います。

  double dTL_X, dTL_Y, dResoX, dResoY;
  double *pdReso = NULL, *pdTie = NULL;
  int iCount;
  GTIF *pGTif;
  TIFF *pTif = XTIFFOpen( lpszFName, "r" );

  // TiepointタグとPixelscaleタグの場合
  if ( TIFFGetField( pTif, GTIFF_PIXELSCALE, &iCount, &pdReso      ) == 1 &&
     TIFFGetField( pTif, GTIFF_TIEPOINTS,  &iCount, &pdTie       ) == 1 )
  {
    // 左上座標とピクセル解像度を取り出す
    dResoX = pdReso[0];
    dResoY = pdReso[1];
    dTL_X = pdTie[3] - pdTie[0]*dResoX;
    dTL_Y = pdTie[4] - pdTie[1]*dResoY;
  }

  // GTIFオブジェクトを作成
  pGTif = GTIFNew( pTif );

  // 楕円体情報を取り出すなら
  GTIFKeyGet( pGTif, GeogEllipsoidGeoKey, &nEllipse, 0, 1 );

  // GTIFオブジェクトを解放
  GTIFFree( pGTif );

  XTIFFClose( pTif );

書き込み

同じようにXTIFFOpen()で開いて、GTIFNew()でTIFF型ポインタを渡し、
GTIFKeySet()でキーをセットします。
最後にGTIFWriteKeys()でキーを書き込んで、GTIFFree()で開放します。

  double dTL_X, dTL_Y, dResoX, dResoY;
  double pdReso[3], pdTie[6];
  int iCount, i;
  GTIF *pGTif;
  TIFF *pTif = XTIFFOpen( lpszFName, "w" );

  // TiepointタグとPixelscaleタグの場合
  pdTie[0] = pdTie[1] = pdTie[2] = pdTie[5] = 0.0;
  pdTie[3] = dTL_X;
  pdTie[4] = dTL_Y;
  pdReso[0] = dResoX;
  pdReso[1] = dResoY;
  pdReso[2] = 0.0;
  TIFFSetField( pTif, TIFFTAG_GEOTIEPOINTS, 6, pdTie );
  TIFFSetField( pTif, TIFFTAG_GEOPIXELSCALE,, 3, pdReso );
  
  // GTIFオブジェクトを作成
  pGTif = GTIFNew( pTif );

  // 楕円体情報を書き込むなら
  GTIFKeySet( pGTif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, Ellipse_GRS_1980 );
  
  // キーの書き込み(下記コメント参照。ありがとうございます。)
  GTIFWriteKeys( pGTif );

  // GTIFオブジェクトを解放
  GTIFFree( pGTif );

  XTIFFClose( pTif );

proj4スタイルでの書き込み

GTIFKeySet()関数で一つ一つキーをセットするのはめんどくさいので何とかならんか、
という要望に応えたのかどうかはわかりませんが、
GTIFSetFromProj4()関数を使うと、proj4で使われる定義スタイルを利用することができます。

大体以下のようなコードになるでしょう。
例では平面直角座標10系を定義しています。

	pGTif = GTIFNew( pTif );
	GTIFSetFromProj4( pGTif, 
	"+proj=tmerc +lat_0=44 +lon_0=140.25 +k=0.9999
	 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs" );
	GTIFWriteKeys( pGTif );
	GTIFFree( pGTif );

GeoTIFF情報をコピーする

入力GeoTIFFから出力TIFFへGeoTIFF情報をコピーしたい場合がありますが、
全てのGeoTIFF情報を1つずつコピーするのは面倒です。
そこで、以下の2つの方法を紹介します。

geotifcp.cで使用されている方法

GTIF構造体の中身を直接書き換える作戦を採っています。
具体的には以下のようにしています。

  // 入力、出力のTIFFポインタがあったとします。
  TIFF *in = XTIFFOpen( szIn, "r" ); 
  TIFF *out = XTIFFOpen( szOut, "w" );
  int nCount;
  double *pdList = NULL; // 修正しました(下記コメントありがとうございます)
  
  // TIEPOINT、PIXELSCALE、もしくはTRANSMATRIXタグをコピー
  if ( TIFFGetField( in, GTIFF_TIEPOINTS, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_TIEPOINTS, nCount, pdList );
  if ( TIFFGetField( in, GTIFF_PIXELSCALE, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_PIXELSCALE, nCount, pdList );
  if ( TIFFGetField( in, GTIFF_TRANSMATRIX, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_TRANSMATRIX, nCount, pdList );
  
  GTIF *gtif = GTIFNew( in );
  // GTIF構造体内にあるTIFFポインタを書き換え
  gtif->gt_tif = out;
  gtif->gt_flags |= FLAG_FILE_MODIFIED;
  
  // 出力ファイルへGeoTIFF情報を書き出し
  GTIFWriteKeys( gtif );
  GTIFFree( gtif );
  
  XTIFFClose( in );
  XTIFFClose( out );

GTIF構造体の書き換え部分がちょっとわかりにくいですが、
これで出力ファイルへGeoTIFF情報がコピーされます。

GTIFDefnを使う方法

まず、入力ファイルからGTIFDefnを取得し、
その情報をproj4文字列に変換した後GTIFSetFromProj4()関数で出力ファイルへ書き込むというものです。

大体以下のようにします。

  // 入力、出力のTIFFポインタがあったとします。
  TIFF *in = XTIFFOpen( szIn, "r" ); 
  TIFF *out = XTIFFOpen( szOut, "w" );
  int nCount;
  double dList = NULL;
  double *pdList = NULL; // 修正しました(下記コメントありがとうございます)
  LPTSTR lpszDefn;
  
  // TIEPOINT、PIXELSCALE、もしくはTRANSMATRIXタグをコピー
  // ここまでは同じ
  if ( TIFFGetField( in, GTIFF_TIEPOINTS, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_TIEPOINTS, nCount, pdList );
  if ( TIFFGetField( in, GTIFF_PIXELSCALE, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_PIXELSCALE, nCount, pdList );
  if ( TIFFGetField( in, GTIFF_TRANSMATRIX, &nCount, &pdList ) )
       TIFFSetField( out, GTIFF_TRANSMATRIX, nCount, pdList );
       
  // GTIFDefn構造体からProj4文字列を取得
  GTIF *pGTIF = GTIFNew( in );
  GTIFDefn sDefn;
  GTIFGetDefn( pGTIF, &sDefn );
  lpszDefn = GTIFGetProj4Defn( &sDefn );
  
  // ここで入力TIFFを閉じても大丈夫
  GTIFFree( pGTIF );
  TIFFClose( in );

  // 出力TIFFへ書き込む
  GTIF *pGTIF_Out = GTIFNew( out );
  GTIFSetFromProj4( pGTIF_Out, lpszDefn );
  GTIFWriteKeys( pGTIF_Out );
  GTIFFree( pGTIF_Out );
  
  XTIFFClose( out );
  
  // これを忘れずに!
  free( lpszDefn );

ほかにも便利な方法あり、続く?

アーカイブ