上の画像に対して、誤った方法、最近傍法、線形補完法による拡大縮小例を示す。
1/2縮小
2倍拡大
縮小は問題ないのだが、拡大の場合、単純に各画素の座標を拡大した位置に移動させただけでは、 画素と画素の間がマッピングされないため、とびとびの画像になっているのが 拡大した画像をみるとよくわかる。
1/2縮小
2倍拡大
拡大時に画素がとびとびになる問題点が改善された。
拡大画像をみるとモザイク状になってしまっている
のがわかる。これは、最近傍画素を拡大後の画素とするために、同じ明るさの画素が
連続するためである。
1/2縮小
2倍拡大
拡大するとモザイク状になってしまう問題が改善された。
拡大画像を見ると、画素が滑らかになっているのがわかる。
拡大後の画素は(10.3)式によって計算される。
(10.4)、(10.5)式に基づいて、画像をx方向に50,y方向に25移動させた。
(10.6)、(10.7)式に基づいて、反時計回りに30°回転させた。
アフィン変換を用いることにより、一回の画像の読み込みで、
拡大・縮小、移動、回転を行った。
今回は、x方向に50、y方向に25、30°回転、1/2倍に縮小した。
透視変換を用いて変形を行った。
上の例は、図10.17のパラメータと同じく、
x方向に1.5倍、y方向に3.0倍、移動量はx,y,zいずれも0、
z方向に10°回転、x方向に-75°回転、y方向に10°回転させ、
視点を10、スクリーン座標を5に設定した。
#include "Params.h"
/*--- scale_ng --- 拡大縮小(このやり方は,間違っている)----------------------
image_in: 入力画像配列
image_out: 出力画像配列
zx: 拡大率(横)
zy: 拡大率(縦)
-----------------------------------------------------------------------------*/
void scale_ng(unsigned char image_in[Y_SIZE][X_SIZE],
unsigned char image_out[Y_SIZE][X_SIZE], float zx, float zy)
{
int i, j, m, n;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
for (i = -ys; i < ys; i++) {
for (j = -xs; j < xs; j++) {
m = (int)(zy * i);
n = (int)(zx * j);
if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) )
image_out[m+ys][n+xs] = image_in[i+ys][j+xs];
}
}
}
#include "Params.h"
/*--- scale_near --- 拡大縮小(最近傍法)--------------------------------------
image_in: 入力画像配列
image_out: 出力画像配列
zx: 拡大率(横)
zy: 拡大率(縦)
-----------------------------------------------------------------------------*/
void scale_near(unsigned char image_in[Y_SIZE][X_SIZE],
unsigned char image_out[Y_SIZE][X_SIZE], float zx, float zy)
{
int i, j, m, n;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
for (i = -ys; i < ys; i++) {
for (j = -xs;j < xs; j++) {
if (i > 0) m = (int)(i/zy + 0.5);
else m = (int)(i/zy - 0.5);
if (j > 0) n = (int)(j/zx + 0.5);
else n = (int)(j/zx - 0.5);
if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) )
image_out[i+ys][j+xs] = image_in[m+ys][n+xs];
else
image_out[i+ys][j+xs] = 0;
}
}
}
#include "Params.h"
/*--- scale --- 拡大縮小(線形補間法)-----------------------------------------
image_in: 入力画像配列
image_out: 出力画像配列
zx: 拡大率(横)
zy: 拡大率(縦)
-----------------------------------------------------------------------------*/
void scale(unsigned char image_in[Y_SIZE][X_SIZE],
unsigned char image_out[Y_SIZE][X_SIZE], float zx, float zy)
{
int i, j, m, n;
float x, y, p, q;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
int d;
for (i = -ys; i< ys; i++) {
for (j = -xs; j< xs; j++) {
y = i/zy;
x = j/zx;
if (y > 0) m = (int)y;
else m = (int)(y-1);
if (x > 0) n = (int)x;
else n = (int)(x-1);
q = y - m;
p = x - n;
if (q == 1) {q = 0; m = m + 1;}
if (p == 1) {p = 0; n = n + 1;}
if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) )
d = (int)((1.0-q)*((1.0-p)*image_in[m +ys][n +xs]
+ p*image_in[m +ys][n+1+xs])
+ q*((1.0-p)*image_in[m+1+ys][n +xs]
+ p*image_in[m+1+ys][n+1+xs]));
else
d = 0;
if (d < 0) d = 0;
if (d > 255) d = 255;
image_out[i+ys][j+xs] = d;
}
}
}
#include "Params.h"
/*--- shift --- 位置の移動(線形補間法)---------------------------------------
image_in: 入力画像配列
image_out: 出力画像配列
px: 移動量(横)
py: 移動量(縦)
-----------------------------------------------------------------------------*/
void shift(unsigned char image_in[Y_SIZE][X_SIZE],
unsigned char image_out[Y_SIZE][X_SIZE], float px, float py)
{
int i, j, m, n;
float x, y, p, q;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
int d;
for (i = -ys; i < ys; i++) {
for (j = -xs; j < xs; j++) {
y = i - py;
x = j - px;
if (y > 0) m = (int)y;
else m = (int)(y-1);
if (x > 0) n = (int)x;
else n = (int)(x-1);
q = y - m;
p = x - n;
if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) )
d = (int)((1.0-q)*((1.0-p)*image_in[m +ys][n +xs]
+ p*image_in[m +ys][n+1+xs])
+ q*((1.0-p)*image_in[m+1+ys][n +xs]
+ p*image_in[m+1+ys][n+1+xs]));
else
d = 0;
if (d < 0) d = 0;
if (d > 255) d = 255;
image_out[i+ys][j+xs] = d;
}
}
}
#include <math.h>
#include "Params.h"
/*--- rotation --- 回転(線形補間法)------------------------------------------
image_in: 入力画像配列
image_out: 出力画像配列
deg: 回転角(度)
-----------------------------------------------------------------------------*/
void rotation(unsigned char image_in[Y_SIZE][X_SIZE],
unsigned char image_out[Y_SIZE][X_SIZE], float deg)
{
int i, j, m, n;
float x, y, p, q;
double r;
float c,s;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
int d;
r = deg*3.141592/180.0;
c = (float)cos(r);
s = (float)sin(r);
for (i = -ys; i < ys; i++) {
for (j = -xs; j < xs; j++) {
y = j*s + i*c;
x = j*c - i*s;
if (y > 0) m = (int)y;
else m = (int)(y-1);
if (x > 0) n = (int)x;
else n = (int)(x-1);
q = y - m;
p = x - n;
if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) )
d = (int)((1.0-q)*((1.0-p)*image_in[m +ys][n +xs]
+ p*image_in[m +ys][n+1+xs])
+ q*((1.0-p)*image_in[m+1+ys][n +xs]
+ p*image_in[m+1+ys][n+1+xs]));
else
d = 0;
if (d < 0) d = 0;
if (d > 255) d = 255;
image_out[i+ys][j+xs] = d;
}
}
}
#include <math.h> #include "Params.h" //#define PI 3.141592 /*--- affine --- 拡大縮小,回転,移動(線形補間法)------------------------------ image_in: 入力画像配列 image_out: 出力画像配列 deg: 回転角(度) zx: 拡大率(横) zy: 拡大率(縦) px: 移動量(横) py: 移動量(縦) -----------------------------------------------------------------------------*/ void affine(unsigned char image_in[Y_SIZE][X_SIZE], unsigned char image_out[Y_SIZE][X_SIZE], float deg, float zx, float zy, float px, float py) { int i, j, m, n; float x, y, u, v, p, q; double r; float c, s; int xs = X_SIZE/2; int ys = Y_SIZE/2; int d; r = deg*PI/180.0; c = (float)cos(r); s = (float)sin(r); for (i = -ys; i < ys; i++) { for (j = -xs; j < xs; j++) { v = i - py; u = j - px; y = (u*s + v*c) / zy; x = (u*c - v*s) / zx; if (y > 0) m = (int)y; else m = (int)(y-1); if (x > 0) n = (int)x; else n = (int)(x-1); q = y - m; p = x - n; if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) ) d = (int)((1.0-q)*((1.0-p)*image_in[m +ys][n +xs] + p*image_in[m +ys][n+1+xs]) + q*((1.0-p)*image_in[m+1+ys][n +xs] + p*image_in[m+1+ys][n+1+xs])); else d = 0; if (d < 0) d = 0; if (d > 255) d = 255; image_out[i+ys][j+xs] = d; } } }
#include <math.h> #include "Params.h" void param_pers(float k[9], float a, float b, float x0, float y0, float z0, float z, float x, float y, float t, float s); void matrix(double l[4][4], double m[4][4], double n[4][4]); /*--- perspect --- 透視変換(線形補間法)-------------------------------------- image_in: 入力画像配列 image_out: 出力画像配列 ax: 拡大率(横) ay: 拡大率(縦) px: 移動量(x) py: 移動量(y) pz: 移動量(z) rz: 回転角(z度) rx: 回転角(x度) ry: 回転角(y度) v: 視点の位置(z) s: スクリーンの位置(z) -----------------------------------------------------------------------------*/ void perspect(unsigned char image_in[Y_SIZE][X_SIZE], unsigned char image_out[Y_SIZE][X_SIZE], float ax, float ay, float px, float py, float pz, float rz, float rx, float ry, float v, float s) { int i, j, m, n; float x, y, w, p, q; float k[9]; int xs = X_SIZE/2; int ys = Y_SIZE/2; int d; param_pers(k,ax,ay,px,py,pz,rz,rx,ry,v,s); /* 変換パラメータ決定 */ for (i = -ys; i < ys; i++) { for (j = -xs; j < xs; j++) { w = k[0]*j + k[1]*i + k[2]; x = k[3]*j + k[4]*i + k[5]; y = k[6]*j + k[7]*i + k[8]; x = x/w; y = y/w; if (y > 0) m = (int)y; else m = (int)(y-1); if (x > 0) n = (int)x; else n = (int)(x-1); q = y - m; p = x - n; if ( (m >= -ys) && (m < ys) && (n >= -xs) && (n < xs) ) d = (int)((1.0-q)*((1.0-p)*image_in[m +ys][n +xs] + p*image_in[m +ys][n+1+xs]) + q*((1.0-p)*image_in[m+1+ys][n +xs] + p*image_in[m+1+ys][n+1+xs])); else d = 0; if (d < 0) d = 0; if (d > 255) d = 255; image_out[i+ys][j+xs] = d; } } } /*--- param_pers --- 透視変換のパラメータ計算 --------------------------------- k: 変換パラメータ a: 拡大率(x方向) b: 拡大率(y方向) x0: 移動量(x方向) y0: 移動量(y方向) z0: 移動量(z方向) z: 回転角(z方向,度) x: 回転角(x方向,度) y: 回転角(y方向,度) t: 視点の位置(z方向) s: スクリーンの位置(z方向) -----------------------------------------------------------------------------*/ void param_pers(float k[9], float a, float b, float x0, float y0, float z0, float z, float x, float y, float t, float s) { double l[4][4],m[4][4],n[4][4]; float k1,k2,k3,k4,k5,k6,k7,k8,k9; double u,v,w; int xs = X_SIZE/2; int ys = Y_SIZE/2; u=x*3.141592/180.0; v=y*3.141592/180.0; w=z*3.141592/180.0; l[0][0]= 1.0/xs; l[0][1]= 0; l[0][2]= 0; l[0][3]= 0; l[1][0]= 0; l[1][1]= -1.0/xs; l[1][2]= 0; l[1][3]= 0; l[2][0]= 0; l[2][1]= 0; l[2][2]= 1; l[2][3]= 0; l[3][0]= 0; l[3][1]= 0; l[3][2]= 0; l[3][3]= 1; m[0][0]= a; m[0][1]= 0; m[0][2]= 0; m[0][3]= 0; m[1][0]= 0; m[1][1]= b; m[1][2]= 0; m[1][3]= 0; m[2][0]= 0; m[2][1]= 0; m[2][2]= 1; m[2][3]= 0; m[3][0]= 0; m[3][1]= 0; m[3][2]= 0; m[3][3]= 1; matrix(l,m,n); /* 正規化マトリックス × 拡大縮小マトリックス */ l[0][0]= 1; l[0][1]= 0; l[0][2]= 0; l[0][3]= 0; l[1][0]= 0; l[1][1]= 1; l[1][2]= 0; l[1][3]= 0; l[2][0]= 0; l[2][1]= 0; l[2][2]= 1; l[2][3]= 0; l[3][0]= x0; l[3][1]= y0; l[3][2]= z0; l[3][3]= 1; matrix(n,l,m); /* × 移動マトリックス */ n[0][0]= cos(w); n[0][1]= sin(w); n[0][2]= 0; n[0][3]= 0; n[1][0]= -sin(w); n[1][1]= cos(w); n[1][2]= 0; n[1][3]= 0; n[2][0]= 0; n[2][1]= 0; n[2][2]= 1; n[2][3]= 0; n[3][0]= 0; n[3][1]= 0; n[3][2]= 0; n[3][3]= 1; matrix(m,n,l); /* × z軸の回転マトリックス */ m[0][0]= 1; m[0][1]= 0; m[0][2]= 0; m[0][3]= 0; m[1][0]= 0; m[1][1]= cos(u); m[1][2]= sin(u); m[1][3]= 0; m[2][0]= 0; m[2][1]= -sin(u); m[2][2]= cos(u); m[2][3]= 0; m[3][0]= 0; m[3][1]= 0; m[3][2]= 0; m[3][3]= 1; matrix(l,m,n); /* × x軸の回転マトリックス */ l[0][0]= cos(v); l[0][1]= 0; l[0][2]= sin(v); l[0][3]= 0; l[1][0]= 0; l[1][1]= 1; l[1][2]= 0; l[1][3]= 0; l[2][0]= -sin(v); l[2][1]= 0; l[2][2]= cos(v); l[2][3]= 0; l[3][0]= 0; l[3][1]= 0; l[3][2]= 0; l[3][3]= 1; matrix(n,l,m); /* × y軸の回転マトリックス */ n[0][0]= 1; n[0][1]= 0; n[0][2]= 0; n[0][3]= 0; n[1][0]= 0; n[1][1]= 1; n[1][2]= 0; n[1][3]= 0; n[2][0]= 0; n[2][1]= 0; n[2][2]= -1; n[2][3]= 0; n[3][0]= 0; n[3][1]= 0; n[3][2]= t; n[3][3]= 1; matrix(m,n,l); /* × 視点座標変換マトリックス */ m[0][0]= 1; m[0][1]= 0; m[0][2]= 0; m[0][3]= 0; m[1][0]= 0; m[1][1]= 1; m[1][2]= 0; m[1][3]= 0; m[2][0]= 0; m[2][1]= 0; m[2][2]= 1/s; m[2][3]= 1/s; m[3][0]= 0; m[3][1]= 0; m[3][2]= -1; m[3][3]= 0; matrix(l,m,n); /* × 透視変換マトリックス */ l[0][0]= xs; l[0][1]= 0; l[0][2]= 0; l[0][3]= 0; l[1][0]= 0; l[1][1]= -xs; l[1][2]= 0; l[1][3]= 0; l[2][0]= 0; l[2][1]= 0; l[2][2]= 1; l[2][3]= 0; l[3][0]= 0; l[3][1]= 0; l[3][2]= 0; l[3][3]= 1; matrix(n,l,m); /* × 正規化逆マトリックス */ k1=(float)(m[0][3]); k2=(float)(m[1][3]); k3=(float)(m[3][3]); k4=(float)(m[0][0]); k5=(float)(m[1][0]); k6=(float)(m[3][0]); k7=(float)(m[0][1]); k8=(float)(m[1][1]); k9=(float)(m[3][1]); k[0]=k7*k2-k8*k1; k[1]=k5*k1-k4*k2; k[2]=k4*k8-k7*k5; k[3]=k8*k3-k9*k2; k[6]=k9*k1-k7*k3; k[4]=k6*k2-k5*k3; k[7]=k4*k3-k6*k1; k[5]=k5*k9-k8*k6; k[8]=k7*k6-k4*k9; } /*--- matrix --- マトリックス計算 --------------------------------------------- l: 入力マトリックス1 m: 入力マトリックス2 n: 出力マトリックス -----------------------------------------------------------------------------*/ void matrix(double l[4][4], double m[4][4], double n[4][4]) { int i, j, k; double p; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { p = 0; for (k = 0; k < 4; k++) p = p + l[i][k]*m[k][j]; n[i][j] = p; } } }