アフィン変換は、ある点Pを線形変換で、ある点Qに、写像する座標変換です。画像分野では、画像の拡大・縮小・回転・移動や画像処理で使われます。ここでは、アフィン変換(画像処理関係なし次回やるかも・・・)だけのC言語プログラムを紹介したいと思います。
アフィン変換の詳しい説明は、wikipediaでも見てもらって、要は、下記のような行列演算で、ある座標x,y,zを新しい座標cx,cy,czに変換することになります。

式を見ればわかるように、a11〜a34までの8個のパラメータを指定するだけで、3次元画像の座標変換ができてしまいます。どこを変えれば、回転とか、拡大とかは、他のサイトを見てください。
作成したC言語プログラムは、アフィン変換を使用しやすいように、行列の設定で回転や平行移動や拡大縮小専用の関数を作っています。座標変換をするときは、まずSetMatrix〜関数で行列を設定して、ConvertCoordinate関数で変換座標を取得するというようにしてください。
// C言語、アフィン変換プログラム
#include "stdafx.h" // VisualStudio2008でCプログラムを作成するのに必要
#include <malloc.h> // malloc/callocといった動的メモリ確保のために必要
#include <math.h> // 数学関数を使用するためのヘッダ
#include <iostream>
using namespace std; // VisualStudio2008でCプログラムを作成するのに必要
using namespace System;
#define PI 3.1415
// double型の二次元配列動的メモリ確保
double** GetDoubleArrayMemory(int xSize, int ySize)
{
int i;
double** arraydata;
// 2次元配列を動的に確保
// callocで縦方向の動的メモリ確保。
arraydata = (double**)calloc(ySize, sizeof(double*));
if(arraydata == NULL) // メモリが確保できなければ終了
{
printf("縦方向の動的メモリが確保できません。\n");
}
for(i = 0; i < ySize; i++)
{
// callocで横方向の動的メモリ確保。
arraydata[i] = (double*)calloc(xSize, sizeof(double));
if(arraydata[i] == NULL) // メモリが確保できなければ終了
{
printf("横方向の動的メモリが確保できません。\n");
}
}
return arraydata;
}
// degreeからradianに変換
double ConvertAngleToRadian(double angle)
{
return angle * PI / 180;
}
// X軸回りの回転設定
double** SetMatrixXRotate(double angle)
{
double** matrix = GetDoubleArrayMemory(4, 4);
matrix[0][0] = 1;
matrix[1][1] = cos(ConvertAngleToRadian(angle));
matrix[2][1] = -sin(ConvertAngleToRadian(angle));
matrix[1][2] = sin(ConvertAngleToRadian(angle));
matrix[2][2] = cos(ConvertAngleToRadian(angle));
matrix[3][3] = 1;
return matrix;
}
// Y軸回りの回転設定
double** SetMatrixYRotate(double angle)
{
double** matrix = GetDoubleArrayMemory(4, 4);
matrix[0][0] = cos(ConvertAngleToRadian(angle));
matrix[2][0] = sin(ConvertAngleToRadian(angle));
matrix[1][1] = 1;
matrix[0][2] = -sin(ConvertAngleToRadian(angle));
matrix[2][2] = cos(ConvertAngleToRadian(angle));
matrix[3][3] = 1;
return matrix;
}
// Z軸回りの回転設定
double** SetMatrixZRotate(double angle)
{
double** matrix = GetDoubleArrayMemory(4, 4);
matrix[0][0] = cos(ConvertAngleToRadian(angle));
matrix[1][0] = -sin(ConvertAngleToRadian(angle));
matrix[0][1] = sin(ConvertAngleToRadian(angle));
matrix[1][1] = cos(ConvertAngleToRadian(angle));
matrix[2][2] = 1;
matrix[3][3] = 1;
return matrix;
}
// 拡大・縮小設定
double** SetMatrixScale(double s1, double s2, double s3)
{
double** matrix = GetDoubleArrayMemory(4, 4);
matrix[0][0] = s1;
matrix[1][1] = s2;
matrix[2][2] = s3;
matrix[3][3] = 1;
return matrix;
}
// 平行移動設定
double** SetMatrixTranslate(double t1, double t2, double t3)
{
double** matrix = GetDoubleArrayMemory(4, 4);
matrix[0][0] = 1; matrix[3][0] = t1;
matrix[1][1] = 1; matrix[3][1] = t2;
matrix[2][2] = 1; matrix[3][2] = t3;
matrix[3][3] = 1;
return matrix;
}
// 座標変換(アフィン変換実行)
void ConvertCoordinate(
double** matrix,
double x,
double y,
double z,
double *cx,
double *cy,
double *cz)
{
*cx =
matrix[0][0] * x +
matrix[1][0] * y +
matrix[2][0] * z +
matrix[3][0] * 1;
*cy =
matrix[0][1] * x +
matrix[1][1] * y +
matrix[2][1] * z +
matrix[3][1] * 1;
*cz =
matrix[0][2] * x +
matrix[1][2] * y +
matrix[2][2] * z +
matrix[3][2] * 1;
}
int main(array<System::String ^> ^args)
{
// 変換前座標
double x = 1;
double y = 1;
double z = 1;
// 変換後座標
double cx, cy, cz;
// 変換設定(x軸90度回転)
double** matrix = SetMatrixXRotate(90);
// 変換実行
ConvertCoordinate(matrix, x, y, z, &cx, &cy, &cz);
// 結果出力
printf("変換前: (x, y, z) = (%f, %f, %f)\n", x, y, z);
printf("変換後: (cx, cy, cz) = (%f, %f, %f)\n", cx, cy, cz);
return 0;
}
実際に画像拡大縮小する場合は、座標アフィン変換後、飛び飛びになったピクセル間を補間する必要がありますが、それについては次回やります。
ちなみにC#で書くと
http://colnagow61s.me.land.to/affine_transform.zip
ソースコードを置いておきます。
| 詳解 画像処理プログラミング C言語で実装する画像処理アルゴリズムのすべて | |
![]() | 昌達 慶仁 ソフトバンククリエイティブ 2008-03-27 売り上げランキング : 5054 おすすめ平均 ![]() とてもわかりやすくて、多くのアルゴリズムを網羅しています。Amazonで詳しく見る |
| 新版 明解C言語 入門編 | |
![]() | 柴田望洋 ソフトバンククリエイティブ 2004-08-28 売り上げランキング : 1324 おすすめ平均 ![]() 満足 見易さ・解説の徹底具合 十分明解だが…Amazonで詳しく見る |
この記事のトラックバックURL
http://thorshammer.blog95.fc2.com/tb.php/246-eafed393
この記事にトラックバックする(FC2ブログユーザー)
この記事にトラックバックする(FC2ブログユーザー)
この記事へのトラックバック




十分明解だが…