今回はjavaで射影変換をするプログラムを作りました。射影変換の説明自体はまた今度にしたいと思います。
プログラムの機能としては
Enterキー:初期化する
→、←キー:y軸周りに回転する
↑、↓キー:x軸周りに回転する
s、xキー:z軸周りに回転する
z、aキー:ズーム、縮小する
g、hキー:右、左に平行移動する
r、vキー:上、下に平行移動する
一例ですが、実行結果は以下の通りになります。
図1:実行結果
プログラムの機能としては
Enterキー:初期化する
→、←キー:y軸周りに回転する
↑、↓キー:x軸周りに回転する
s、xキー:z軸周りに回転する
z、aキー:ズーム、縮小する
g、hキー:右、左に平行移動する
r、vキー:上、下に平行移動する
一例ですが、実行結果は以下の通りになります。
図1:実行結果
import java.awt.Container; import java.awt.Graphics; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import javax.swing.JComponent; import javax.swing.JFrame; public class ProjectiveTrMain extends JFrame{ final int window_size_w = 1900; final int window_size_h = 1000; public static void main(String[] args){ ProjectiveTrMain frame = new ProjectiveTrMain(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } public ProjectiveTrMain(){ ProjectiveTr panel = new ProjectiveTr(); Container contentPane = getContentPane(); contentPane.add(panel); setSize(window_size_w, window_size_h); } } class ProjectiveTr extends JComponent{ BufferedImage src = null; //原画像 BufferedImage dst = null; //出力画像 int xangle = 0; //x軸周りの回転角度 int yangle = 0; //y軸周りの回転角度 int zangle = 0; //z軸周りの回転角度 final int focus = 500; //焦点距離(pixel) int[] tr = {100,100, focus}; //平行移動ベクトル int width = 0; //原画像の横幅 int height = 0; //原画像の縦幅 public ProjectiveTr(){ //画像の読み込み src = imgRead("C:/Picture/ExperimentImg/F1010017.jpg"); width = src.getWidth(); height = src.getHeight(); addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e) { int keycode = e.getKeyCode(); switch(keycode){ //画像を初期位置に戻す case KeyEvent.VK_ENTER: xangle = 0; yangle = 0; zangle = 0; tr[2] = focus; System.out.println("RESET"); rendering(xangle, yangle, zangle); break; //画像を拡大する case KeyEvent.VK_Z: tr[2] -= 10; rendering(xangle, yangle, zangle); break; //画像を縮小する case KeyEvent.VK_A: tr[2] += 10; rendering(xangle, yangle, zangle); break; //z軸周りに正の方向に回転 case KeyEvent.VK_S: zangle++; if(zangle >= 180){ zangle = 180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); break; //z軸周りに正の方向に回転 case KeyEvent.VK_X: zangle--; if(zangle <= -180){ zangle = -180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); break; //画像を右に平行移動 case KeyEvent.VK_G: tr[0] += 10; rendering(xangle, yangle, zangle); break; //画像を左に平行移動 case KeyEvent.VK_H: tr[0] -= 10; rendering(xangle, yangle, zangle); break; //画像を上に平行移動 case KeyEvent.VK_V: tr[1] += 10; rendering(xangle, yangle, zangle); break; //画像を下に平行移動 case KeyEvent.VK_R: tr[1] -= 10; rendering(xangle, yangle, zangle); break; //x軸周りに正の方向に回転 case KeyEvent.VK_UP: xangle++; if(xangle >= 180){ xangle = 180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); break; //x軸周りに負の方向に回転 case KeyEvent.VK_DOWN: xangle--; if(xangle <= -180){ xangle = -180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); break; //y軸周りに正の方向に回転 case KeyEvent.VK_RIGHT: yangle++; if(yangle >= 180){ yangle = 180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); //System.out.println("Pressed RIGHT key"); break; //y軸周りに負の方向に回転 case KeyEvent.VK_LEFT: yangle--; if(yangle <= -180){ yangle = -180; } System.out.println("xangle = " + xangle + " yangle = " + yangle + " zangle = " + zangle); rendering(xangle, yangle, zangle); //System.out.println("Pressed LEFT key"); break; } } }); setFocusable(true); rendering(xangle, yangle, zangle); } //画像の読み込み public static BufferedImage imgRead(String filepath){ System.out.println(filepath); File file = new File(filepath); try { BufferedImage img = ImageIO.read(file); return img; }catch(Exception e){ System.err.println("File can't read or broken"); } return null; } //行列の積を計算 double[][] matMul(double[][] mat1, double[][] mat2){ if(mat1[0].length != mat2.length){ return null; } double[][] multiMat = new double[mat1.length][mat2[0].length]; for(int y = 0; y < mat1.length ; y++){ for(int x = 0 ; x < mat2[0].length; x++){ double sum = 0; for(int z = 0; z < mat1[0].length; z++){ sum += mat1[y][z] * mat2[z][x]; } multiMat[y][x] = sum; } } return multiMat; } //回転行列を計算する public double[][] rotate(double[][] mat3d, double thetaX, double thetaY, double thetaZ){ double sin_theta = Math.sin(Math.toRadians(thetaX)); double cos_theta = Math.cos(Math.toRadians(thetaX)); double Rx[][] = { { 1 , 0 , 0 }, { 0 , cos_theta , -sin_theta }, {0 , sin_theta , cos_theta } }; sin_theta = Math.sin(Math.toRadians(thetaY)); cos_theta = Math.cos(Math.toRadians(thetaY)); double Ry[][] = { { cos_theta , 0 , sin_theta }, { 0 ,1 , 0 }, {-sin_theta , 0 , cos_theta } }; sin_theta = Math.sin(Math.toRadians(thetaZ)); cos_theta = Math.cos(Math.toRadians(thetaZ)); double Rz[][] = { { cos_theta , -sin_theta , 0 }, { sin_theta , cos_theta , 0 }, {0 , 0 , 1 } }; double[][] R; R = matMul(Rx , Ry); R = matMul(R , Rz); mat3d = matMul(R , mat3d); return mat3d; } //行列を表示 public void dispMat(double[][] mat){ for(int i = 0; i < mat.length; i++){ for(int j = 0; j < mat[0].length; j++){ System.out.print(mat[i][j] + "\t"); } System.out.println(); } System.out.println(); } //画像を射影変換する public void rendering(double xtheta, double ytheta, double ztheta){ double[][] cmat = { {1,0, 0}, {0,1, 0}, {0, 0, 1}, }; BufferedImage bufimg = src; dst = new BufferedImage(3000, 3000, BufferedImage.TYPE_INT_RGB); int z = 100; cmat = rotate(cmat, xtheta, ytheta, ztheta); dispMat(cmat); int hw = width / 2; int hh = height / 2; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ //射影変換の計算部分 double dstX = focus * (cmat[0][0]*(x - hw) + cmat[0][1] * (y - hh) + cmat[0][2] * z + tr[0]) / (cmat[2][0] * (x - hw) + cmat[2][1]*(y - hh) + cmat[2][2] * z + tr[2]) + hw; double dstY = focus * (cmat[1][0]*(x - hw) + cmat[1][1] * (y - hh) + cmat[1][2] * z + tr[1]) / (cmat[2][0] * (x - hw) + cmat[2][1]*(y - hh) + cmat[2][2] * z + tr[2]) + hh; try{ dst.setRGB((int)dstX, (int)dstY, bufimg.getRGB(x, y)); }catch(Exception e){ } } } repaint(); } public void paintComponent(Graphics g){ g.fillRect(0, 0, width, height); g.drawImage(dst, 0, 0, this); } }