ゆるゆるプログラミング

・画像の180°回転

ここでは、画像の中心座標を基準に画像を180°回転するソースコードを解説します。

以下がそのソースコード例です。

Rotation180.java
001:    import java.awt.image.BufferedImage;
002:    import java.io.File;
003:    import javax.imageio.ImageIO;
004:    import java.io.IOException;
005:    
006:    public class Rotation180 {
007:    	public static void main( String[] args ) {
008:    		// 結果格納フラグ
009:    		boolean result;
010:    		// ファイル名
011:    		String inname, outname;
012:    		// 画像格納クラス
013:    		BufferedImage img = null;
014:    
015:    		// 入力した引数が2つ以上かを調べる
016:    		if ( 2 > args.length ) {
017:    			// 入力した引数が2つ未満の場合、使用方法を表示する
018:    			System.out.println( "Rotation180 [入力JPEG名]  [出力JPEG名]" );
019:    			return;
020:    		}
021:    
022:    		// 入力JPEG名をinnameに代入(拡張子".jpg"省略なし)
023:    		inname  = args[ 0 ];
024:    		// 出力JPEG名をoutnameに代入(拡張子".jpg"省略なし)
025:    		outname = args[ 1 ];
026:    
027:    		try {
028:    			// inname(入力JPEG)を読み込んでimgにセット
029:    			img = ImageIO.read( new File( inname ) );
030:    		} catch (Exception e) {
031:    			// inname(入力JPEG)の読み込みに失敗したときの処理
032:    			 e.printStackTrace();
033:    			return;
034:    		}
035:    
036:    		// 画像の色の持ち方をチェック
037:    		if ( BufferedImage.TYPE_3BYTE_BGR != img.getType() )
038:    		{
039:    			System.out.println( "対応していないカラーモデルです!("
040:    									 + inname +")" );
041:    			return;
042:    		}
043:    
044:    		// 変数を宣言
045:    		int x, y;		// ピクセル座標
046:    		int xs, ys;		// 画像中心座標で点対称のピクセル座標
047:    		int width, height;	// 画像サイズ
048:    		int size;		// 画像の全ピクセル数
049:    		int sizeh;		// 画像の半分のピクセル数(小数点以下切捨て)
050:    		int proccount;		// 処理したピクセル数
051:    		int color1, color2;	// 色
052:    
053:    		// 画像サイズの取得
054:    		width = img.getWidth();
055:    		height= img.getHeight();
056:    
057:    		// 画像の全ピクセル数
058:    		size = width * height;
059:    
060:    		// 画像の全ピクセル数の半分(小数点以下切捨て)
061:    		sizeh = size / 2;
062:    
063:    		// 処理したピクセル数を0にする
064:    		proccount = 0;
065:    
066:    		// 回転処理
067:    		for ( y = 0; y < height; ++ y ) {
068:    			for ( x = 0; x < width; ++ x ) {
069:    				// 画像中心座標を基準に(x,y)の点対称となる(xs,ys)を計算
070:    				xs = width  - 1 - x;
071:    				ys = height - 1 - y;
072:    
073:    				// (x,y)の色を取得
074:    				color1 = img.getRGB( x, y );
075:    
076:    				// (xs,ys)の色を取得
077:    				color2 = img.getRGB( xs, ys );
078:    
079:    				// color2を(x,y)に設定
080:    				img.setRGB( x, y, color2 );
081:    
082:    				// color1を(xs,ys)に設定
083:    				img.setRGB( xs, ys, color1 );
084:    
085:    				// 処理したピクセル数に1を足す
086:    				++ proccount;
087:    
088:    				// 画像の半分を処理したら処理を終了
089:    				if ( proccount == sizeh ) break;
090:    			}
091:    			// 画像の半分を処理したら処理を終了
092:    			if ( proccount == sizeh ) break;
093:    		}
094:    
095:    		try {
096:    			// imgをoutname(出力JPEG)に保存
097:    			result = ImageIO.write( img, "jpeg", new File( outname ) );
098:    		} catch ( Exception e ) {
099:    			// outname(出力JPEG)の保存に失敗したときの処理
100:    			e.printStackTrace();
101:    			return;
102:    		}
103:    
104:    		// 正常に終了
105:    		System.out.println( "正常に終了しました" );
106:    	}
107:    }

Rotation180を実行

C:\talavax\javasample>java Rotation180 sampleimage001_400x320.jpg rotation180.jpg

1つ目の引数で渡したJPEGファイル色反転し、2つ目の引数で指定したJPEGファイル名で保存します。

実行結果

・元の画像(sampleimage001_400x320.jpg)

元画像

・変換後の180°回転画像(Rotation180.jpg)

>180°回転画像

画像が180°回転しました。

ここからは、このソースコードを上から順番に解説していきます。

001:    import java.awt.image.BufferedImage;
002:    import java.io.File;
003:    import javax.imageio.ImageIO;
004:    import java.io.IOException;

Javaのクラスライブラリの中から「java.awt.image.BufferedImage」と「java.io.File」と「javax.imageio.ImageIO」と「java.io.IOException」というパッケージにあるクラスを、このプログラム内で使うために記述します。 この記述により、ImageIOクラスBufferedImageクラスが利用できるようになります。

006:    public class Rotation180 {

クラス名を、Rotation180としています。

007:    	public static void main( String[] args ) {

このmainメソッドからプログラムを実行します。

008:    		// 結果格納フラグ
009:    		boolean result;
010:    		// ファイル名
011:    		String inname, outname;
012:    		// 画像格納クラス
013:    		BufferedImage img = null;

このプログラムで使う変数を宣言しています。どのように使われているかは、後ろのソースコードで。

015:    		// 入力した引数が2つ以上かを調べる
016:    		if ( 2 > args.length ) {
017:    			// 入力した引数が2つ未満の場合、使用方法を表示する
018:    			System.out.println( "Rotation180 [入力JPEG名]  [出力JPEG名]" );
019:    			return;
020:    		}

1つ以上の引数が与えられたかをチェックし、1つ未満の場合に、使い方のメッセージを表示し、returnによってmainメソッドを抜けています。

022:    		// 入力JPEG名をinnameに代入(拡張子".jpg"省略なし)
023:    		inname  = args[ 0 ];
024:    		// 出力JPEG名をoutnameに代入(拡張子".jpg"省略なし)
025:    		outname = args[ 1 ];

与えられた引数をそれぞれ、入力JPEG名の変数(inname)、出力JPEG名の変数(outname)代入しています。

027:    		try {
028:    			// inname(入力JPEG)を読み込んでimgにセット
029:    			img = ImageIO.read( new File( inname ) );
030:    		} catch (Exception e) {
031:    			// inname(入力JPEG)の読み込みに失敗したときの処理
032:    			 e.printStackTrace();
033:    			return;
034:    		}

入力JPEG名の変数(inname)を読み込んで、BufferedImageクラスのimgに格納しています。この処理には、ImageIOクラスreadメソッドを使います。

ImageIO.readメソッド

public static BufferedImage read( File input ) throws IOException
■Fileオブジェクトを復元した結果をBufferedImageに格納します。

  パラメータ input : Fileオブジェクト

  戻り値     inputを復元したBufferedImageaを返します。

try { ~ } catchは、失敗する可能性がある処理を波括弧で囲み、その処理に失敗したときにcatch { ~ }の波括弧で囲まれた処理を実行するということです。この場合は、JPEGファイル名が不正であったり、存在していなかったり、フォーマットが違っているなどが原因で処理が失敗する可能性があります。処理が失敗するとreturnによってmainメソッドを抜けるようにしています。

036:    		// 画像の色の持ち方をチェック
037:    		if ( BufferedImage.TYPE_3BYTE_BGR != img.getType() )
038:    		{
039:    			System.out.println( "対応していないカラーモデルです!("
040:    									 + inname +")" );
041:    			return;
042:    		}

BufferedImageクラスgetTypeメソッドで画像のイメージ型を取得しています。

BufferedImage.getTypeメソッド

public static int getType()
■イメージ型を返します。
  パラメータ なし

  戻り値     BufferedImage のイメージ型を返します。

044:    		// 変数を宣言
045:    		int x, y;		// ピクセル座標
046:    		int xs, ys;		// 画像中心座標で点対称のピクセル座標
047:    		int width, height;	// 画像サイズ
048:    		int size;		// 画像の全ピクセル数
049:    		int sizeh;		// 画像の半分のピクセル数(小数点以下切捨て)
050:    		int proccount;		// 処理したピクセル数
051:    		int color1, color2;	// 色

画像の回転で使う変数を宣言しています。

053:    		// 画像サイズの取得
054:    		width = img.getWidth();
055:    		height= img.getHeight();

widthに画像の幅(ピクセル)、heightに画像の高さ(ピクセル)を代入しています。

066:    		// 回転処理
067:    		for ( y = 0; y < height; ++ y ) {
068:    			for ( x = 0; x < width; ++ x ) {

画像の中の全てのピクセルの座標を参照するループをつくり、その座標を取得しています。具体的には、変数yを0~height-1、変数xを0~width-1に変化させています。

069:    				// 画像中心座標を基準に(x,y)の点対称となる(xs,ys)を計算
070:    				xs = width  - 1 - x;
071:    				ys = height - 1 - y;

画像の中心座標を基準に、(x,y)の点対称となる(xs,ys)を計算しています。

073:    				// (x,y)の色を取得
074:    				color1 = img.getRGB( x, y );
075:    
076:    				// (xs,ys)の色を取得
077:    				color2 = img.getRGB( xs, ys );

ピクセル座標(x,y)の色を変数color1に代入し、点対称のピクセル座標(xs,ys)の色を変数color2に代入しています。

079:    				// color2を(x,y)に設定
080:    				img.setRGB( x, y, color2 );
081:    
082:    				// color1を(xs,ys)に設定
083:    				img.setRGB( xs, ys, color1 );

(x,y)と(xs,ys)の色を入れ替えます。具体的には、ピクセル座標(x,y)にcolor2を設定、ピクセル座標(x,y)にcolor1を設定しています。

085:    				// 処理したピクセル数に1を足す
086:    				++ proccount;

色の入れ替え処理をした回数をカウントしています。

088:    				// 画像の半分を処理したら処理を終了
089:    				if ( proccount == sizeh ) break;
090:    			}
091:    			// 画像の半分を処理したら処理を終了
092:    			if ( proccount == sizeh ) break;
093:    		}

色の入れ替え処理回数が、元の画像のピクセル数の半分になったときにxのループ、yのループの両方をbreak文で抜けています。ピクセル数の半分を超えて処理を行うと、色の入れ替えを行った座標に対して、再度入れ替え処理が行われ、元の色に戻ってしまうためです。興味があったらbreak文を外して試してください。

095:    		try {
096:    			// imgをoutname(出力JPEG)に保存
097:    			result = ImageIO.write( img, "jpeg", new File( outname ) );
098:    		} catch ( Exception e ) {
099:    			// outname(出力JPEG)の保存に失敗したときの処理
100:    			e.printStackTrace();
101:    			return;
102:    		}

BufferedImageクラスのimgのメモリ内のデータを、出力JPEG名の変数(outname)に格納されているファイル名で保存します。この場合は、JPEGファイル名が不正であったり、保存先のHDDなどが存在していなかったり、空き容量が少ないなどが原因で処理が失敗する可能性があります。

ImageIO.wrireメソッド

public static boolean write( RenderedImage im, String formatName, File output ) throws IOException
■BufferedImageを画像ファイルに保存します。

  パラメータ RenderedImage : 保存するRenderedImage
                  formatName     : 画像ファイルのフォーマット(png/jpeg/bmp/gifなど)
                  output             : Fileオブジェクト

  戻り値     保存に成功するとtrue、失敗するとfalseを返します。

104:    		// 正常に終了
105:    		System.out.println( "正常に終了しました" );

全ての処理が正常終了すると、ここまで処理が実行されます。

■関連コンテンツ

画像の色 画像の色について解説
画像ファイル形式 画像ファイル形式について解説
for文 繰り返し処理に使用するfor文について解説

■新着情報

2017.11.17 N値化 カラー画像をN値化する方法について解説
2017.11.16 最も近い値の取得 指定値に最も近い配列の値を取得する方法を解説
2017.10.02 アルファ値(透過) アルファ値(透過)について

■広告

法人向けのETC専用カード

~約8,000名の受講生と80社以上の導入実績~ 企業向けプログラミング研修ならCodeCamp

日本最大級ショッピングサイト!お買い物なら楽天市場

Topへ