幾何変換
[幾何計算]


説明

線形幾何変換を行うためのライブラリです。 画像の幾何変換に関しては 画像の幾何変換ページ を、 リージョンの幾何変換に関しては リージョンの幾何変換ページ を、 それぞれご参照ください。

同次変換行列
FIEライブラリでは、二次元座標空間上の画像および図形の線形幾何変換を 同次変換行列を用いて指定します。同次変換行列とは、ある座標から別の 座標への線形変換を表す行列です。変換前の座標を x, y 変換後の座標を u, v で表すとすると、2次元座標でのアフィン変換は次のように表されます。

\[ \left(\begin{array}{c} u \\ v \\ 1 \end{array}\right) = M \left(\begin{array}{c} x \\ y \\ 1 \end{array}\right) \]

この M を同次変換行列とよびます。この $M$ は 3x3のサイズです。 この同次変換行列を使用すると、回転、平行移動、スケール変換などの 変換を行列の掛け算による統一的な表現で表すことが出来ることが メリットです。
同次変換行列計算ライブラリ
座標変換のための各種パラメータ(回転、平行移動、スケール変換など)が既知の場合に 同次変換行列が簡単に計算できるよう、下記の関数が用意されています。
また、「変換前の点座標と変換後の点座標のペア」が既知で有る場合は、 以下の関数により座標変換行列を作成することができます。
同次変換行列の組み合わせ
たとえば、
  1. 平行移動する同次変換行列 $M_{S1}$
  2. 回転する同次変換行列 $M_{R}$
  3. 平行移動する同次変換行列 $M_{S2}$
  4. スケールする同次変換行列 $M_{M}$
という変換行列が有った場合、これらを掛け合わせた行列

\[ M' = M_{M} M_{S2} M_{R} M_{S1} \]

を計算します。すると、$M'$ は 1.平行移動して 2.回転して 3.平行移動して 4.スケールする変換 を表す事になります。 これにより複数の変換を1回の変換にまとめることができるため、 複雑な変換が必用な場合には処理時間の短縮を図ることが出来ます。 また $M$ の逆行列 $M^{-1}$ を求めれば、 $M$ の逆の変換を行うことが出来ます。

なお、これら行列同士の演算は行列演算の fnFIE_mat_mul_aa() により行うことが出来ます。
座標変換マップ作成ライブラリ
線形幾何変換では表現できない複雑な幾何変換は、座標変換マップを用いて実行することができます。 「変換前の点座標と変換後の点座標のペア」が既知で有る場合は、 fnFIE_geotrans_estimate_warp_map() により座標変換マップを作成することができます。


列挙型

enum  f_geotrans_warp_mode {
  F_WARP_MODE_EUCLIDEAN, F_WARP_MODE_SIMILARITY,
  F_WARP_MODE_AFFINE, F_WARP_MODE_PERSPECTIVE,
  F_WARP_MODE_PIECEWISE_AFFINE, F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR
}
 座標変換マップ作成モード [詳細]

関数

INT FVALGAPI fnFIE_geotrans_calc_rotate_matrix (FMATRIX *mat, DOUBLE rad, DOUBLE cx, DOUBLE cy)
 回転をする同次変換行列を作成
INT FVALGAPI fnFIE_geotrans_calc_shift_matrix (FMATRIX *mat, DOUBLE dx, DOUBLE dy)
 平行移動する同次変換行列を作成
INT FVALGAPI fnFIE_geotrans_calc_scale_matrix (FMATRIX *mat, DOUBLE sx, DOUBLE sy)
 スケール変化する同次変換行列を作成
INT FVALGAPI fnFIE_geotrans_calc_xshear_matrix (FMATRIX *mat, DOUBLE rad)
 せん断変形(x方向)する同次変換行列を作成
INT FVALGAPI fnFIE_geotrans_calc_yshear_matrix (FMATRIX *mat, DOUBLE rad)
 せん断変形(y方向)する同次変換行列を作成
INT FVALGAPI fnFIE_geotrans_affine_point (DPNT_T src, DPNT_T *dst, const FMATRIX *mat)
 点のアフィン変換
INT FVALGAPI fnFIE_geotrans_affine_npoints (const DPNT_T *src, DPNT_T *dst, INT num, const FMATRIX *mat)
 点群のアフィン変換
INT FVALGAPI fnFIE_geotrans_affine_line (DLINE_T src, DLINE_T *dst, const FMATRIX *mat)
 直線のアフィン変換
INT FVALGAPI fnFIE_geotrans_affine_lineseg (DSGMT_T src, DSGMT_T *dst, const FMATRIX *mat)
 線分のアフィン変換
INT FVALGAPI fnFIE_geotrans_perspective_point (DPNT_T src, DPNT_T *dst, const FMATRIX *mat)
 点の射影変換
INT FVALGAPI fnFIE_geotrans_perspective_npoints (const DPNT_T *src, DPNT_T *dst, INT num, const FMATRIX *mat)
 点群の射影変換
INT FVALGAPI fnFIE_geotrans_perspective_line (DLINE_T src, DLINE_T *dst, const FMATRIX *mat)
 直線の射影変換
INT FVALGAPI fnFIE_geotrans_perspective_lineseg (DSGMT_T src, DSGMT_T *dst, const FMATRIX *mat)
 線分の射影変換
INT FVALGAPI fnFIE_geotrans_estimate_perspective_matrix (FMATRIX *fpMat, const DPNT_T *pntspFrom, const DPNT_T *pntspTo, UINT uiNum)
  [[OSS]] 射影変換の変換行列を計算
INT FVALGAPI fnFIE_geotrans_estimate_affine_matrix (FMATRIX *fpMat, const DPNT_T *pntspFrom, const DPNT_T *pntspTo, UINT uiNum)
  [[OSS]] アフィン変換の変換行列を計算
INT FVALGAPI fnFIE_geotrans_estimate_similarity_matrix (FMATRIX *trans_mat, const DPNT_T *pnts_from, const DPNT_T *pnts_to, UINT pnts_num)
  [[OSS]] 相似変換の変換行列を計算
INT FVALGAPI fnFIE_geotrans_estimate_euclidean_matrix (FMATRIX *trans_mat, const DPNT_T *pnts_from, const DPNT_T *pnts_to, UINT pnts_num)
  [[OSS]] ユークリッド変換の変換行列を計算
INT FVALGAPI fnFIE_geotrans_estimate_warp_map (FHANDLE hmap, const DPNT_T *pnts_from, const DPNT_T *pnts_to, UINT pnts_num, enum f_geotrans_warp_mode warp_mode, DOUBLE param)
  [[OSS]] 変換前後の点列を用いて座標変換マップを作成

列挙型

座標変換マップ作成モード

列挙型の値:
F_WARP_MODE_EUCLIDEAN  ユークリッド変換
F_WARP_MODE_SIMILARITY  相似変換
F_WARP_MODE_AFFINE  アフィン変換
F_WARP_MODE_PERSPECTIVE  射影変換
F_WARP_MODE_PIECEWISE_AFFINE  区分アフィン変換
F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR  局所重み付き平均による変換(線形)


関数

INT FVALGAPI fnFIE_geotrans_calc_rotate_matrix ( FMATRIX mat,
DOUBLE  rad,
DOUBLE  cx,
DOUBLE  cy 
)

回転をする同次変換行列を作成

点( cx , cy )を中心として、 rad 回転する同次変換行列を作成します。 mat に指定する行列は、あらかじめ3×3のサイズで確保しておかなければいけません。 なお mat の意味や利用法については 同次変換行列 を参照してください。

本関数は、下記のように行列を設定します。

\[ mat = \left( \begin{array}{ccc} \cos(rad) & -\sin(rad) & cx - ( cx*\cos(rad) - cy*\sin(rad) ) \\ \sin(rad) & \cos(rad) & cy - ( cx*\sin(rad) + cy*\cos(rad) ) \\ 0 & 0 & 1 \end{array}\right) \]

fie_geotrans_rotate.png

回転行列の作成(左右共に、同一座標系)

引数:
[out] mat 同次変換行列
[in] rad 回転角(ラジアン)
[in] cx 回転中心x座標
[in] cy 回転中心y座標
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー

INT FVALGAPI fnFIE_geotrans_calc_shift_matrix ( FMATRIX mat,
DOUBLE  dx,
DOUBLE  dy 
)

平行移動する同次変換行列を作成

x方向に dx, y方向に dy だけ平行移動する同次変換行列を作成します。 mat に指定する行列は、あらかじめ3×3のサイズで確保しておかなければいけません。 なお mat の意味や利用法については 同次変換行列 を参照してください。

本関数は、下記のように行列を設定します。

\[ mat = \left( \begin{array}{ccc} 1 & 0 & dx \\ 0 & 1 & dy \\ 0 & 0 & 1 \end{array}\right) \]

fie_geotrans_shift.png

平行移動行列の作成(左右共に、同一座標系)

引数:
[out] mat 同次変換行列
[in] dx x方向移動量
[in] dy y方向移動量
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー

INT FVALGAPI fnFIE_geotrans_calc_scale_matrix ( FMATRIX mat,
DOUBLE  sx,
DOUBLE  sy 
)

スケール変化する同次変換行列を作成

x方向を sx 倍、y方向を sy 倍する同次変換行列を作成します。 mat に指定する行列は、あらかじめ3×3のサイズで確保しておかなければいけません。 なお mat の意味や利用法については 同次変換行列 を参照してください。

本関数は、下記のように行列を設定します。

\[ mat = \left( \begin{array}{ccc} sx & 0 & 0 \\ 0 & sy & 0 \\ 0 & 0 & 1 \end{array}\right) \]

fie_geotrans_scale.png

スケール変化行列の作成(左右共に、同一座標系)

引数:
[out] mat 同次変換行列
[in] sx x方向倍率
[in] sy y方向倍率
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー

INT FVALGAPI fnFIE_geotrans_calc_xshear_matrix ( FMATRIX mat,
DOUBLE  rad 
)

せん断変形(x方向)する同次変換行列を作成

x方向にせん断変形をする同次変換行列を作成します。 mat に指定する行列は、あらかじめ3×3のサイズで確保しておかなければいけません。 なお mat の意味や利用法については 同次変換行列 を参照してください。

本関数は、下記のように行列を設定します。

\[ mat = \left( \begin{array}{ccc} 1 & \tan(rad) & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{array}\right) \]

fie_geotrans_xshear.png

x方向のせん断行列の作成(左右共に、同一座標系)

引数:
[out] mat 同次変換行列
[in] rad せん断角(ラジアン)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー

INT FVALGAPI fnFIE_geotrans_calc_yshear_matrix ( FMATRIX mat,
DOUBLE  rad 
)

せん断変形(y方向)する同次変換行列を作成

y方向にせん断変形をする同次変換行列を作成します。 mat に指定する行列は、あらかじめ3×3のサイズで確保しておかなければいけません。 なお mat の意味や利用法については 同次変換行列 を参照してください。

本関数は、下記のように行列を設定します。

\[ mat = \left( \begin{array}{ccc} 1 & 0 & 0 \\ \tan(rad) & 1 & 0 \\ 0 & 0 & 1 \end{array}\right) \]

fie_geotrans_yshear.png

y方向のせん断行列の作成(左右共に、同一座標系)

引数:
[out] mat 同次変換行列
[in] rad せん断角(ラジアン)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー

INT FVALGAPI fnFIE_geotrans_affine_point ( DPNT_T  src,
DPNT_T dst,
const FMATRIX mat 
)

点のアフィン変換

入力点 src を同次変換行列 mat により変換し、 dst を返します。

\[ dst.x = src.x * mat\left[ 0 \right]\left[ 0 \right] + src.y * mat\left[ 0 \right]\left[ 1 \right] + mat\left[ 0 \right]\left[ 2 \right] \]

\[ dst.y = src.x * mat\left[ 1 \right]\left[ 0 \right] + src.y * mat\left[ 1 \right]\left[ 1 \right] + mat\left[ 1 \right]\left[ 2 \right] \]

mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力点座標
[out] dst 出力点座標
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_affine_npoints() , fnFIE_geotrans_affine_line() , fnFIE_geotrans_affine_lineseg() , fnFIE_geotrans_affine()

INT FVALGAPI fnFIE_geotrans_affine_npoints ( const DPNT_T src,
DPNT_T dst,
INT  num,
const FMATRIX mat 
)

点群のアフィン変換

入力点列 src を同次変換行列 mat により変換し、点列 dst を返します。

\[ dst.x = src.x * mat\left[ 0 \right]\left[ 0 \right] + src.y * mat\left[ 0 \right]\left[ 1 \right] + mat\left[ 0 \right]\left[ 2 \right] \]

\[ dst.y = src.x * mat\left[ 1 \right]\left[ 0 \right] + src.y * mat\left[ 1 \right]\left[ 1 \right] + mat\left[ 1 \right]\left[ 2 \right] \]

mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力点座標配列
[out] dst 出力点座標配列
[in] num 入力点数
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_affine_point() , fnFIE_geotrans_affine_line() , fnFIE_geotrans_affine_lineseg() , fnFIE_geotrans_affine()

INT FVALGAPI fnFIE_geotrans_affine_line ( DLINE_T  src,
DLINE_T dst,
const FMATRIX mat 
)

直線のアフィン変換

入力直線 src を同次変換行列 mat により変換し、直線 dst を返します。 mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力直線
[out] dst 出力直線
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_affine_point() , fnFIE_geotrans_affine_npoints() , fnFIE_geotrans_affine_lineseg() , fnFIE_geotrans_affine()

INT FVALGAPI fnFIE_geotrans_affine_lineseg ( DSGMT_T  src,
DSGMT_T dst,
const FMATRIX mat 
)

線分のアフィン変換

入力線分 src を同次変換行列 mat により変換し、線分 dst を返します。 mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力線分
[out] dst 出力線分
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_affine_point() , fnFIE_geotrans_affine_npoints() , fnFIE_geotrans_affine_line() , fnFIE_geotrans_affine()

INT FVALGAPI fnFIE_geotrans_perspective_point ( DPNT_T  src,
DPNT_T dst,
const FMATRIX mat 
)

点の射影変換

入力点 src を同次変換行列 mat により変換し、 dst を返します。

\[ dst.x = \frac{\left( src.x * mat\left[ 0 \right]\left[ 0 \right] + src.y * mat\left[ 0 \right]\left[ 1 \right] + mat\left[ 0 \right]\left[ 2 \right] \right)} {\left( src.x * mat\left[ 2 \right]\left[ 0 \right] + src.y * mat\left[ 2 \right]\left[ 1 \right] + mat\left[ 2 \right]\left[ 2 \right] \right)} \]

\[ dst.y = \frac{\left( src.x * mat\left[ 1 \right]\left[ 0 \right] + src.y * mat\left[ 1 \right]\left[ 1 \right] + mat\left[ 1 \right]\left[ 2 \right] \right)} {\left( src.x * mat\left[ 2 \right]\left[ 0 \right] + src.y * mat\left[ 2 \right]\left[ 1 \right] + mat\left[ 2 \right]\left[ 2 \right] \right)} \]

分母の値が0になる時は、 F_ERR_INVALID_PARAM を返します。 また、分母の値が非常に小さくなる場合は、計算誤差が増大しますので注意してください。

mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力点座標
[out] dst 出力点座標
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_perspective_npoints() , fnFIE_geotrans_perspective_line() , fnFIE_geotrans_perspective_lineseg() , fnFIE_geotrans_perspective()

INT FVALGAPI fnFIE_geotrans_perspective_npoints ( const DPNT_T src,
DPNT_T dst,
INT  num,
const FMATRIX mat 
)

点群の射影変換

入力点列 src を同次変換行列 mat により変換し、点列 dst を返します。

\[ dst.x = \frac{\left( src.x * mat\left[ 0 \right]\left[ 0 \right] + src.y * mat\left[ 0 \right]\left[ 1 \right] + mat\left[ 0 \right]\left[ 2 \right] \right)} {\left( src.x * mat\left[ 2 \right]\left[ 0 \right] + src.y * mat\left[ 2 \right]\left[ 1 \right] + mat\left[ 2 \right]\left[ 2 \right] \right)} \]

\[ dst.y = \frac{\left( src.x * mat\left[ 1 \right]\left[ 0 \right] + src.y * mat\left[ 1 \right]\left[ 1 \right] + mat\left[ 1 \right]\left[ 2 \right] \right)} {\left( src.x * mat\left[ 2 \right]\left[ 0 \right] + src.y * mat\left[ 2 \right]\left[ 1 \right] + mat\left[ 2 \right]\left[ 2 \right] \right)} \]

mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力点座標配列
[out] dst 出力点座標配列
[in] num 入力点数
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_perspective_point() , fnFIE_geotrans_perspective_line() , fnFIE_geotrans_perspective_lineseg() , fnFIE_geotrans_perspective()

INT FVALGAPI fnFIE_geotrans_perspective_line ( DLINE_T  src,
DLINE_T dst,
const FMATRIX mat 
)

直線の射影変換

入力直線 src を同次変換行列 mat により変換し、直線 dst を返します。 mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力点座標
[out] dst 出力点座標
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_perspective_point() , fnFIE_geotrans_perspective_npoints() , fnFIE_geotrans_perspective_lineseg() , fnFIE_geotrans_perspective()

INT FVALGAPI fnFIE_geotrans_perspective_lineseg ( DSGMT_T  src,
DSGMT_T dst,
const FMATRIX mat 
)

線分の射影変換

入力直線 src を同次変換行列 mat により変換し、線分 dst を返します。 mat の意味や作成法については 同次変換行列 を参照してください。

引数:
[in] src 入力線分
[out] dst 出力線分
[in] mat 同次変換行列(3x3の正方行列)
戻り値:
F_ERR_NONE 正常終了
F_ERR_INVALID_PARAM 不正なパラメータが渡された
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
参照:
fnFIE_geotrans_perspective_point() , fnFIE_geotrans_perspective_npoints() , fnFIE_geotrans_perspective_line() , fnFIE_geotrans_perspective()

INT FVALGAPI fnFIE_geotrans_estimate_perspective_matrix ( FMATRIX fpMat,
const DPNT_T pntspFrom,
const DPNT_T pntspTo,
UINT  uiNum 
)

[[OSS]] 射影変換の変換行列を計算

本関数は最小二乗法を使用し、「変換前の点座標と変換後の点座標のペア」の 配列から射影変換行列を求めます。求められた行列は射影変換 (fnFIE_geotrans_perspective) 等で変換行列として使用できます。
射影変換は、線分の直線性は保たれますが、平行性は失われます。 つまり、任意の四角形を別の任意の四角形に移す変換であるといえます。

変換前の点座標を(x',y'), 変換後の点座標(x,y) とすると、射影変換は

\[ \left( \begin{array}{c} Wx \\ Wy \\ W \end{array} \right) = \mathbf{M} \left( \begin{array}{c} x' \\ y' \\ 1 \end{array} \right) \]

\[ \mathbf{M} = \left( \begin{array}{ccc} a & b & c \\ d & e & f \\ g & h & 1 \end{array} \right) \]

\[W = gx'+hy'+1\]

と与えられます。この時(x,y)と(x',y')のペアが複数分かっているとき、 本関数により行列 M を求めることができます。なお、点のペアは同一直線上にない4組以上が必要です。

覚え書き:
  • 関数内部の行列計算はCLAPACKのDGELSD関数を使って行います。
  • 入力点列の点数は同一直線上にない4組以上なければなりません。
  • fpMat は3×3の行列をユーザが用意する必要があります。 3×3以外の行列を入力した場合はエラーとなります。
  • 本関数内では、行列のメモリ確保はおこないません。
引数:
[out] fpMat 求められた射影変換の変換行列
[in] pntspFrom 射影変換前の点の座標列
[in] pntspTo 射影変換後の点の座標列
[in] uiNum pntspFrom/pntspTo の点数
戻り値:
F_ERR_NONE 正常終了
F_ERR_NOMEMORY メモリ不足で確保に失敗した
F_ERR_INVALID_PARAM パラメータ不正
  • fpMat , pntspFrom , または pntspTo がNULL
  • 点数が3点以下、または1073741824点(2^30点)以上
F_ERR_INVALID_OBJECT fpMat が3×3の行列ではない
F_ERR_CALC_IMPOSSIBLE 計算不能で異常終了
  • 関数 DGELSD 中の計算が収束できない
  • 入力点列によって作った座標行列のランクが 8未満のため、計算できない
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
使用例
// エラー処理は省略しているので注意して下さい。
#include "oal_aloc.h"
#include "fie.h"

// 各変換行列を求めて、その変換行列を使用して画像の幾何変換をします。
VOID affine_trans()
{
    FHANDLE hsrc = NULL, hdst = NULL;
    FMATRIX *a_aff = NULL;
    DPNT_T  from[3], to[3];
    INT ch, type;
    INT src_w, src_h;
    INT dst_w, dst_h;

    // 変換する BMP 形式の処理対象画像を読み込みます。
    fnFIE_load_bmp( "testdata/test.bmp", &hsrc, F_COLOR_IMG_TYPE_UC8 );

    // 結果画像を処理対象と同じ型とチャネル数にします。
    // サイズは異なっていてもかまいません。
    fnFIE_img_get_params( hsrc, &ch, &type, NULL, &src_w, &src_h );
    dst_w = src_w * 2;
    dst_h = src_h / 2;
    hdst = fnFIE_img_root_alloc( type, ch, dst_w, dst_h );

    // 3×3の行列を設定します。
    a_aff = fnFIE_mat_aalloc( 3, 3 );

    // アフィン変換は同一直線上にない3組以上の座標列を設定します。
    // 変換前の座標を設定します。
    from[0].x = 0;
    from[0].y = 0;

    from[1].x = 0;
    from[1].y = src_h - 1;

    from[2].x = src_w - 1;
    from[2].y = src_h - 1;

    // 変換後の座標を設定します。
    to[0].x = 0;
    to[0].y = dst_h / 2;

    to[1].x = dst_w / 2;
    to[1].y = dst_h - 1;

    to[2].x = dst_w - 1;
    to[2].y = dst_h / 2;

    // アフィン変換行列を求めます。
    fnFIE_geotrans_estimate_affine_matrix( a_aff, from, to, 3 );

    // 求めたアフィン変換行列より、画像のアフィン変換を行います。
    // 三次畳み込み法により濃度補間で、結果画像を生成します。
    // マスク画像は生成しません。
    // 領域外になる画素は処理をしません。
    fnFIE_geotrans_affine( hsrc, hdst, NULL, a_aff, FALSE, F_SAMPLING_CUBIC );

    // 結果画像を BMP 形式のファイルとして保存します。
    fnFIE_save_bmp( "result/test1.bmp", hdst );

    if( NULL != a_aff ) fnFIE_mat_afree( a_aff );
    if( NULL != hsrc  ) fnFIE_free_object( hsrc );
    if( NULL != hdst  ) fnFIE_free_object( hdst );

    return;
}

VOID perspective_trans()
{
    FHANDLE hsrc = NULL, hdst = NULL;
    FMATRIX *a_pp = NULL;
    DPNT_T  from[4], to[4];
    INT ch, type;
    INT src_w, src_h;
    INT dst_w, dst_h;

    // 変換する BMP 形式の処理対象画像を読み込みます。
    fnFIE_load_bmp( "testdata/test.bmp", &hsrc, F_COLOR_IMG_TYPE_UC8 );

    // 結果画像を処理対象と同じ型とチャネル数にします。
    // サイズは異なっていてもかまいません。
    fnFIE_img_get_params( hsrc, &ch, &type, NULL, &src_w, &src_h );
    dst_w = src_w * 2;
    dst_h = src_h / 2;
    hdst = fnFIE_img_root_alloc( type, ch, dst_w, dst_h );

    // 3×3の行列を設定します。
    a_pp = fnFIE_mat_aalloc( 3, 3 );

    // 射影変換は同一直線上にない4組以上の座標列を設定します。
    // 変換前の座標を設定します。
    from[0].x = 0;
    from[0].y = 0;

    from[1].x = 0;
    from[1].y = src_h - 1;

    from[2].x = src_w - 1;
    from[2].y = src_h - 1;

    from[3].x = src_w - 1;
    from[3].y = 0;

    // 変換後の座標を設定します。
    to[0].x = 0;
    to[0].y = dst_h / 2;

    to[1].x = dst_w / 2;
    to[1].y = dst_h - 1;

    to[2].x = (dst_w / 4) * 3;
    to[2].y = (dst_h / 4) * 3;

    to[3].x = dst_w / 2;
    to[3].y = 0;

    // 射影変換行列を求めます。
    fnFIE_geotrans_estimate_perspective_matrix( a_pp, from, to, 4 );

    // 求めた射影変換行列より、画像の射影変換を行います。
    // 最近傍法により濃度補間で、結果画像を生成します。
    // マスク画像は生成しません。
    // 領域外になる画素は0でクリアします。
    fnFIE_geotrans_perspective( hsrc, hdst, NULL, a_pp, TRUE, F_SAMPLING_NN );

    // 結果画像を BMP 形式のファイルとして保存します。
    fnFIE_save_bmp( "result/test2.bmp", hdst );

    if( NULL != a_pp ) fnFIE_mat_afree( a_pp );
    if( NULL != hsrc ) fnFIE_free_object( hsrc );
    if( NULL != hdst ) fnFIE_free_object( hdst );

    return;
}


INT main()
{
    // FIEライブラリの使用前に必ずコールする必要があります。
    fnFIE_setup();

    affine_trans();
    perspective_trans();

    // 終了処理
    fnFIE_teardown();

    return 0;
}

INT FVALGAPI fnFIE_geotrans_estimate_affine_matrix ( FMATRIX fpMat,
const DPNT_T pntspFrom,
const DPNT_T pntspTo,
UINT  uiNum 
)

[[OSS]] アフィン変換の変換行列を計算

本関数は最小二乗法を使用し、「変換前の点座標と変換後の点座標のペア」の 配列からアフィン変換行列を求めます。求められた行列はアフィン変換 (fnFIE_geotrans_affine) 等で変換行列として使用できます。
アフィン変換は、一般に原図形の長さや角度は保たれませんが、線分の直線性や平行性は保たれます。 つまり、任意の平行四辺形を、別の任意の平行四辺形に移すような変換であるといえます。

変換前の点座標を(x',y'), 変換後の点座標(x,y) とすると、アフィン変換は

\[ \left( \begin{array}{c} x \\ y \\ 1 \end{array} \right) = \mathbf{M} \left( \begin{array}{c} x' \\ y' \\ 1 \end{array} \right) \]

\[ \mathbf{M} = \left( \begin{array}{ccc} a & b & c \\ d & e & f \\ 0 & 0 & 1 \end{array} \right) \]

と与えられます。この時(x,y)と(x',y')のペアが複数分かっているとき、 本関数により行列 M を求めることができます。なお、点のペアは同一直線上にない3組以上が必要です。

覚え書き:
  • 関数内部の行列計算はCLAPACKのDGELSD関数を使って行います。
  • 入力点列の点数は同一直線上にない3組以上なければなりません。
  • fpMat は3×3の行列をユーザが用意する必要があります。 3×3以外の行列を入力した場合はエラーとなります。
  • 本関数内では、行列のメモリ確保は行いません。
引数:
[out] fpMat 求められたアフィン変換の変換行列
[in] pntspFrom アフィン変換前の点列の座標
[in] pntspTo アフィン変換後の点列の座標
[in] uiNum pntspFrom/pntspTo の点数
戻り値:
F_ERR_NONE 正常終了
F_ERR_NOMEMORY メモリ不足で確保に失敗した
F_ERR_INVALID_PARAM パラメータ不正
  • fpMat , pntspFrom , または pntspTo がNULL
  • 点数が2点以下、または1073741824点(2^30点)以上
F_ERR_INVALID_OBJECT fpMat が3×3の行列ではない
F_ERR_CALC_IMPOSSIBLE 計算不能で異常終了
  • 関数 DGELSD 中の計算は収束できない
  • 入力点列によって作った座標行列のランクが6未満のため、計算できない
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
使用例
fnFIE_geotrans_estimate_perspective_matrix() の例を参照してください。

INT FVALGAPI fnFIE_geotrans_estimate_similarity_matrix ( FMATRIX trans_mat,
const DPNT_T pnts_from,
const DPNT_T pnts_to,
UINT  pnts_num 
)

[[OSS]] 相似変換の変換行列を計算

最小二乗法を使用し、「変換前の点座標と変換後の点座標のペア」の 配列から相似変換行列を求めます。求められた行列はアフィン変換 (fnFIE_geotrans_affine) 等で変換行列として使用できます。
相似変換は、任意の平行移動、回転、および縦横の倍率が等しいスケーリングを組み合わせた変換であり、原図形の直線性や角度を保ちます。 つまり、任意の四角形を、その四角形と相似で鏡映でない別の四角形に移すような変換であるといえます。

変換前の点座標を(x',y'), 変換後の点座標(x,y) とすると、相似変換は

\[ \left( \begin{array}{c} x \\ y \\ 1 \end{array} \right) = \mathbf{M} \left( \begin{array}{c} x' \\ y' \\ 1 \end{array} \right) \]

\[ \mathbf{M} = \left( \begin{array}{ccc} s \cos \theta & - s \sin \theta & a \\ s \sin \theta & s \cos \theta & b \\ 0 & 0 & 1 \end{array} \right) \]

と与えられます。この時(x,y)と(x',y')のペアが複数分かっているとき、 本関数により行列 M を求めることができます。なお、点のペアは相違なる2組以上が必要です。

覚え書き:
  • 関数内部の行列計算はCLAPACKのDGELSD関数を使って行います。
  • 入力点列の点数は2組以上なければなりません。
  • trans_mat は3×3の行列をユーザが用意する必要があります。 3×3以外の行列を入力した場合はエラーとなります。
  • 本関数内では、行列のメモリ確保は行いません。
引数:
[out] trans_mat 求められた相似変換の変換行列
[in] pnts_from 相似変換前の点列の座標
[in] pnts_to 相似変換後の点列の座標
[in] pnts_num pnts_from/pnts_to の点数
戻り値:
F_ERR_NONE 正常終了
F_ERR_NOMEMORY メモリ不足で確保に失敗した
F_ERR_INVALID_PARAM パラメータ不正
  • trans_mat , pnts_from , または pnts_to がNULL
  • 点数が1点以下、または1073741824点(2^30点)以上
F_ERR_INVALID_OBJECT trans_mat が3×3の行列ではない
F_ERR_CALC_IMPOSSIBLE 計算不能で異常終了
  • 関数 DGELSD 中の計算は収束できない
  • 入力点列によって作った座標行列のランクが4未満のため、計算できない
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
使用例
fnFIE_geotrans_estimate_perspective_matrix() の例を参照してください。

INT FVALGAPI fnFIE_geotrans_estimate_euclidean_matrix ( FMATRIX trans_mat,
const DPNT_T pnts_from,
const DPNT_T pnts_to,
UINT  pnts_num 
)

[[OSS]] ユークリッド変換の変換行列を計算

最小二乗法を使用し、「変換前の点座標と変換後の点座標のペア」の 配列からユークリッド変換行列を求めます。求められた行列はアフィン変換 (fnFIE_geotrans_affine) 等で変換行列として使用できます。
ユークリッド変換は、任意の平行移動・回転を組み合わせた変換であり、原図形の長さや角度を保ちます。 つまり、任意の四角形を、その四角形と合同な別の四角形に移すような変換であるといえます。

変換前の点座標を(x',y'), 変換後の点座標(x,y) とすると、ユークリッド変換は

\[ \left( \begin{array}{c} x \\ y \\ 1 \end{array} \right) = \mathbf{M} \left( \begin{array}{c} x' \\ y' \\ 1 \end{array} \right) \]

\[ \mathbf{M} = \left( \begin{array}{ccc} \cos \theta & - \sin \theta & a \\ \sin \theta & \cos \theta & b \\ 0 & 0 & 1 \end{array} \right) \]

と与えられます。この時(x,y)と(x',y')のペアが複数分かっているとき、 本関数により行列 M を求めることができます。なお、点のペアは相違なる2組以上が必要です。

覚え書き:
  • 入力点列の点数は2組以上なければなりません。
  • trans_mat は3×3の行列をユーザが用意する必要があります。 3×3以外の行列を入力した場合はエラーとなります。
  • 本関数内では、行列のメモリ確保は行いません。
引数:
[out] trans_mat 求められたユークリッド変換の変換行列
[in] pnts_from ユークリッド変換前の点列の座標
[in] pnts_to ユークリッド変換後の点列の座標
[in] pnts_num pnts_from/pnts_to の点数
戻り値:
F_ERR_NONE 正常終了
F_ERR_NOMEMORY メモリ不足で確保に失敗した
F_ERR_INVALID_PARAM パラメータ不正
  • trans_mat , pnts_from , または pnts_to がNULL
  • 点数が1点以下、または1073741824点(2^30点)以上
F_ERR_INVALID_OBJECT trans_mat が3×3の行列ではない
F_ERR_CALC_IMPOSSIBLE 計算不能で異常終了
  • 内部の行列演算に失敗した
  • 最適解が一意に定まらない
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
使用例
fnFIE_geotrans_estimate_perspective_matrix() の例を参照してください。

INT FVALGAPI fnFIE_geotrans_estimate_warp_map ( FHANDLE  hmap,
const DPNT_T pnts_from,
const DPNT_T pnts_to,
UINT  pnts_num,
enum f_geotrans_warp_mode  warp_mode,
DOUBLE  param 
)

[[OSS]] 変換前後の点列を用いて座標変換マップを作成

「変換前の点座標と変換後の点座標のペア」の配列から座標変換マップを作成します。 求められた変換マップ hmapfnFIE_geotrans_warpping() で使用できます。

hmap の画素タイプは F_IMG_DOUBLE または F_IMG_FLOAT でなければなりません。 hmap のチャネル数は2であり、チャネル0に x 座標が、チャネル1に y 座標が出力されます。

座標変換マップを作成するための処理モードはパラメータ warp_mode で設定します。 warp_mode の値は下記のいずれかです。

  • F_WARP_MODE_PIECEWISE_AFFINE
    区分アフィン変換モードです。 局所領域ごとに異なるアフィン変換が実行されるため、 線形変換では表現できない複雑な変形に対応することができます。

  • F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR
    局所重み付き平均による変換モード(線形)です。 区分アフィン変換と同様に複雑な変形に対応でき、より滑らかな結果を得ることができますが、 多数の一様な点の対応を必要とします。
    点が一様に分布していない場合、点が少ない領域にて変換マップの座標値が定まらないことがあります。 そのような領域では正の無限大を座標値として格納します。

param について
param は変換マップ作成モード warp_mode に応じて意味が変化するパラメータです。 warp_mode が F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR 以外の場合は使用されません。
warp_mode が F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR の場合は、 param は近傍点の数となります。 param は4以上の整数でなければなりません。 近傍点の数が小さいと処理結果が不安定となりやすいため、8以上の値を設定することを推奨します。
注意:
  • 入力点列の点数 pnts_num は変換マップ作成モードごとに下記の値以上でなければなりません。
    • F_WARP_MODE_EUCLIDEAN: 2
    • F_WARP_MODE_SIMILARITY: 2
    • F_WARP_MODE_AFFINE: 3
    • F_WARP_MODE_PERSPECTIVE: 4
    • F_WARP_MODE_PIECEWISE_AFFINE: 4
    • F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR: param (≧ 4)
  • 入力点列に同一直線上に並ぶ点が多数含まれている場合は計算不能エラーになる場合があります。
  • warp_mode が F_WARP_MODE_PIECEWISE_AFFINE または F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR の場合、 入力点列に重複点があるとエラーになります。
  • warp_mode が F_WARP_MODE_PIECEWISE_AFFINE の場合、内部処理の都合上、 座標変換後の点列の座標値の絶対値が100万を超えているとエラーになります。
引数:
[out] hmap 座標変換マップ (type:float, double, ch:2)
[in] pnts_from 座標変換前の点列の座標
[in] pnts_to 座標変換後の点列の座標
[in] pnts_num pnts_from/pnts_to の点数
[in] warp_mode 変換マップ作成モード
  • F_WARP_MODE_EUCLIDEAN
  • F_WARP_MODE_SIMILARITY
  • F_WARP_MODE_AFFINE
  • F_WARP_MODE_PERSPECTIVE
  • F_WARP_MODE_PIECEWISE_AFFINE
  • F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR
[in] param 変換マップ作成モードごとのパラメータ
戻り値:
F_ERR_NONE 正常終了
F_ERR_NOMEMORY メモリ不足で確保に失敗した
F_ERR_INVALID_PARAM パラメータ不正
F_ERR_INVALID_IMAGE 不正な画像オブジェクトハンドルが渡された
F_ERR_CALC_IMPOSSIBLE 計算不能で異常終了
F_ERR_NO_LICENCE ライセンスエラー、または未初期化エラー
使用例
#include <stdio.h>
#include "fie.h"

// FIE関数の異常終了時に処理終了するためのマクロ定義
#define ERROR_CHECK(expr) if ((err = (expr)) != F_ERR_NONE) { printf("err: %d, line: %d\n", err, __LINE__); goto exit; }

// 縦方向の点の数
#define NUM_POINT_ROWS 10
// 横方向の点の数
#define NUM_POINT_COLS 10
// 点の数
#define NUM_POINTS (NUM_POINT_ROWS * NUM_POINT_COLS)

// アーチ状に画像を変形するサンプル
INT warp_image_like_arch()
{
    // 入力画像
    FHANDLE hsrc = NULL;
    // 出力画像
    FHANDLE hdst = NULL;
    // 座標変換マップ
    FHANDLE hmap = NULL;
    // 点列のプロット用画像
    FHANDLE hsrc_plot = NULL;
    FHANDLE hdst_plot = NULL;

    // 変換前座標点列
    DPNT_T pnts_from[NUM_POINTS];
    // 変換後座標点列
    DPNT_T pnts_to[NUM_POINTS];

    // 画像パラメータ
    INT type, channels, width, height;
    INT dst_height;

    // 変換パラメータ
    // 変換マップ作成モード。複雑な変形に対応できるものを設定
    enum f_geotrans_warp_mode warp_mode = F_WARP_MODE_LOCAL_WEIGHTED_MEAN_LINEAR;
    // 近傍点の数
    DOUBLE param = 8.0;
    // 濃度補間法
    enum f_sampling_mode sampling_mode = F_SAMPLING_BILINEAR;

    INT err = F_ERR_NONE;
    INT x, y, i;

    // 入力画像読み込み。1チャネルまたは3チャネルの濃淡画像(F_IMG_UC8)を想定
    ERROR_CHECK( fnFIE_load_img_file("sample.png", &hsrc, F_COLOR_IMG_TYPE_UC8) );

    // 入力画像のパラメータ取得
    ERROR_CHECK( fnFIE_img_get_params(hsrc, &channels, &type, NULL, &width, &height) );
    // アーチ状に変形させるため、出力画像の高さを少し追加
    dst_height = height * 5 / 4;

    // 出力画像と座標変換マップのメモリ確保
    hdst = fnFIE_img_root_alloc(type, channels, width, dst_height);
    hmap = fnFIE_img_root_alloc(F_IMG_DOUBLE, 2, width, dst_height);

    // 変換前後の点列の設定
    for (y = 0; y < NUM_POINT_ROWS; y++)
    {
        for (x = 0; x < NUM_POINT_COLS; x++)
        {
            DOUBLE x_ratio = (DOUBLE)x / (NUM_POINT_COLS - 1);
            DOUBLE y_ratio = (DOUBLE)y / (NUM_POINT_ROWS - 1);
            // 変換前点は格子状に配置
            DPNT_T from = {x_ratio * width, y_ratio * height};
            // 変換後点列のY方向差分。アーチ状に変形するので、X座標が画像中央に近いほどY座標を小さくする
            DOUBLE y_shift_to = (x_ratio - 0.5) * (x_ratio - 0.5) * height;
            // 変換後点
            DPNT_T to = {from.x, from.y + y_shift_to};
            INT idx = y * NUM_POINT_COLS + x;

            pnts_from[idx] = from;
            pnts_to[idx] = to;
        }
    }
    
    // 変換マップ作成
    ERROR_CHECK( fnFIE_geotrans_estimate_warp_map(hmap, pnts_from, pnts_to, NUM_POINTS, warp_mode, param) );
    
    // 変換実施
    ERROR_CHECK( fnFIE_geotrans_warpping(hsrc, hmap, hdst, NULL, TRUE, sampling_mode) );

    // 結果画像保存
    ERROR_CHECK( fnFIE_save_png("sample_deformed.png", hdst, -1) );

    // 可視化用に、点列を赤色で入出力画像にプロットして表示
    hsrc_plot = fnFIE_img_root_alloc(type, 3, width, height);
    hdst_plot = fnFIE_img_root_alloc(type, 3, width, dst_height);
    if (channels == 1) {
        ERROR_CHECK( fnFIE_color_convert(hsrc, F_CS_GRAY, hsrc_plot, F_CS_RGB, NULL) );
        ERROR_CHECK( fnFIE_color_convert(hdst, F_CS_GRAY, hdst_plot, F_CS_RGB, NULL) );
    }
    else {
        // channel == 3
        ERROR_CHECK( fnFIE_img_copy(hsrc, hsrc_plot) );
        ERROR_CHECK( fnFIE_img_copy(hdst, hdst_plot) );
    }

    for (i = 0; i < NUM_POINTS; i++)
    {
        DOUBLE val[3] = {255.0, 0.0, 0.0};
        ERROR_CHECK( fnFIE_draw_circle(hsrc_plot, val, F_DRAW_FILL_IN, pnts_from[i], 2) );
        ERROR_CHECK( fnFIE_draw_circle(hdst_plot, val, F_DRAW_FILL_IN, pnts_to[i], 2) );
    }

    // 点列可視化画像保存
    ERROR_CHECK( fnFIE_save_png("sample_keypoints.png", hsrc_plot, -1) );
    ERROR_CHECK( fnFIE_save_png("sample_deformed_keypoints.png", hdst_plot, -1) );

exit:
    // 画像の解放
    fnFIE_free_object(hsrc);
    fnFIE_free_object(hdst);
    fnFIE_free_object(hmap);
    fnFIE_free_object(hsrc_plot);
    fnFIE_free_object(hdst_plot);

    return err;
}

int main()
{
    INT err;

    // FIEライブラリのセットアップ
    fnFIE_setup();

    err = warp_image_like_arch();

    // ライブラリの終了処理
    fnFIE_teardown();

    return err;
}
処理結果例:
floppy1.png

入力画像

fie_geotrans_estimate_lwm_deformed.png

作成した変換マップにより入力画像を変形した画像

fie_geotrans_estimate_lwm_keypoints.png

変換前点列の可視化画像

fie_geotrans_estimate_lwm_deformed_keypoints.png

変換後点列の可視化画像

参考文献:
  • Goshtasby, Piecewise linear mapping functions for image registration, Pattern Recognition, Vol. 19, pp. 459-466, 1986.
  • Goshtasby, Image registration by local approximation methods, Image and Vision Computing, Vol. 6, pp. 255-261, 1988.


Documentation copyright © 2009-2024 FAST Corporation.
Generated on Fri Aug 9 16:38:47 2024 for FIEライブラリ by doxygen 1.5.6-FASTSP-p2