ゆるゆるプログラミング

・放射状模様

画像サイズと線の本数と線の角度を指定することで、黒と白の放射状模様画像を作成します。ここで紹介するプログラムで出力する画像の形式はPNGファイルです。

放射状模様画像放射状模様

上の画像の例は、画像サイズ:256x256、線の本数:20、線の角度:10°で作成したものです。

Pattern_Radiation01.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 Pattern_Radiation01 {
007:    	// Math.atan2メソッドを利用し、角度の戻り値を0~2πにしたもの
008:    	private static double atan3( double y, double x )
009:    	{
010:    		// yが0以上の場合
011:    		if ( 0.0 <= y )
012:    			return Math.atan2( y, x );
013:    
014:    		// yが0未満の場合
015:    		return Math.atan2( y, x ) + 2.0 * Math.PI;
016:    	}
017:    
018:    
019:    	// メイン
020:    	public static void main( String[] args ) {
021:    		// 変数宣言
022:    		int    w, h;	// 画像サイズ
023:    		int    l_num;	// 本数
024:    		double l_deg;	// 線の角度
025:    		double w_deg;	// 白部分の角度
026:    		String outname;	// 出力ファイル名
027:    		BufferedImage img = null;	// 画像格納クラス
028:    
029:    		// 入力した引数が5以上かを調べる
030:    		if ( 5 > args.length ) {
031:    			// 入力した引数が5未満の場合、使用方法を表示する
032:    			System.out.println( 
033:    				"Pattern_Radiation01 [PNG名] [幅] [高] [線の本数] [線の角度]" );
034:    			return;
035:    		}
036:    
037:    		try {
038:    			// 引数を変換し、画像の幅と高さをwとhに代入
039:    			w =  Integer.valueOf( args[ 1 ] );
040:    			h =  Integer.valueOf( args[ 2 ] );
041:    
042:    			// 引数を変換し、線の本数l_numに代入
043:    			l_num = Integer.valueOf( args[ 3 ] );
044:    			if ( 1 > l_num ) {
045:    				System.out.println( "線の本数に1以上を指定!" );
046:    				return;
047:    			}
048:    
049:    			// 引数を変換し、線の角度l_degに代入
050:    			l_deg = Double.valueOf( args[ 4 ] );
051:    			if ( 0.0 >= l_deg ) {
052:    				System.out.println( "線の角度に0.0より大きい値を指定!" );
053:    				return;
054:    			}
055:    		}
056:    		catch( NumberFormatException ne )
057:    		{
058:    			System.out.println( "引数が不正です" );
059:    			return;
060:    		}
061:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
062:    		outname = args[ 0 ];
063:    
064:    		// 新しい画像を作成
065:    		// 24ビットカラーの画像を作成
066:    		try {
067:    			img = new BufferedImage( w, h,
068:    						 BufferedImage.TYPE_INT_RGB );
069:    		} catch ( Exception e ) {
070:    			// 画像作成に失敗したときの処理
071:    			e.printStackTrace();
072:    			return;
073:    		}
074:    
075:    		// 放射状模様 画像作成
076:    		int    x, y;
077:    		int    color, r, g, b;	// 計算した色
078:    		double mx, my;		// 画像の中心の座標
079:    		double deg, rad;	// (mx,my)を原点とした(x,y)の角度
080:    
081:    		// 画像の中心座標を計算		
082:    		mx = (double)( w - 1 ) / 2.0;
083:    		my = (double)( h - 1 ) / 2.0;
084:    
085:    		// 白部分の角度
086:    		w_deg = ( 360.0 - (double)l_num * l_deg ) / (double)l_num;
087:    
088:    		// 画像作成
089:    		for ( y = 0; y < h; ++ y ) {
090:    			for ( x = 0; x < w; ++ x ) {
091:    				// 角度(ラジアン)を計算
092:    				rad = atan3( (double)y - my, (double)x - my );
093:    
094:    				// ラジアンを度に変換
095:    				deg = rad * 180.0 / Math.PI;
096:    
097:    				// 判定式
098:    				if ( l_deg >= ( deg % ( l_deg + w_deg  ) ) )
099:    					r = g = b = 0;
100:    				else
101:    					r = g = b = 255;
102:    					
103:    				// rgbを合成
104:    				color = ( r << 16 ) + ( g << 8 ) + b;
105:    				// 色を設定
106:    				img.setRGB( x, y, color );
107:    			}
108:    		}
109:    
110:    		try {
111:    			// imgをoutname(出力PNG)に保存
112:    			boolean result;
113:    			result = ImageIO.write( img, "PNG", new File( outname ) );
114:    		} catch ( Exception e ) {
115:    			// outname(出力PNG)の保存に失敗したときの処理
116:    			e.printStackTrace();
117:    			return;
118:    		}
119:    
120:    		// 正常に終了
121:    		System.out.println( "正常に終了しました" );
122:    	}
123:    }

Pattern_Radiation01の実行例

java Pattern_Radiation01 pattern_radiation01.png 256 256 20 10

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

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」というパッケージにあるクラスを、このプログラム内で使うために記述します。この記述により、BufferedImageクラスImageIOクラスが利用できるようになります。

006:    public class Pattern_Radiation01 {

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

007:    	// Math.atan2メソッドを利用し、角度の戻り値を0~2πにしたもの
008:    	private static double atan3( double y, double x )
009:    	{
010:    		// yが0以上の場合
011:    		if ( 0.0 <= y )
012:    			return Math.atan2( y, x );
013:    
014:    		// yが0未満の場合
015:    		return Math.atan2( y, x ) + 2.0 * Math.PI;
016:    	}

引数xとyから角度(ラジアン)を0~2πの範囲で求めるメソッドです。

詳しくはこちらを参照してください。「逆三角関数 atan3」

019:    	// メイン
020:    	public static void main( String[] args ) {

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

021:    		// 変数宣言
022:    		int    w, h;	// 画像サイズ
023:    		int    l_num;	// 本数
024:    		double l_deg;	// 線の角度
025:    		double w_deg;	// 白部分の角度
026:    		String outname;	// 出力ファイル名
027:    		BufferedImage img = null;	// 画像格納クラス

このプログラムで使う変数を宣言しています。

029:    		// 入力した引数が5以上かを調べる
030:    		if ( 5 > args.length ) {
031:    			// 入力した引数が5未満の場合、使用方法を表示する
032:    			System.out.println( 
033:    				"Pattern_Radiation01 [PNG名] [幅] [高] [線の本数] [線の角度]" );
034:    			return;
035:    		}

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

037:    		try {
038:    			// 引数を変換し、画像の幅と高さをwとhに代入
039:    			w =  Integer.valueOf( args[ 1 ] );
040:    			h =  Integer.valueOf( args[ 2 ] );
041:    
042:    			// 引数を変換し、線の本数l_numに代入
043:    			l_num = Integer.valueOf( args[ 3 ] );
044:    			if ( 1 > l_num ) {
045:    				System.out.println( "線の本数に1以上を指定!" );
046:    				return;
047:    			}
048:    
049:    			// 引数を変換し、線の角度l_degに代入
050:    			l_deg = Double.valueOf( args[ 4 ] );
051:    			if ( 0.0 >= l_deg ) {
052:    				System.out.println( "線の角度に0.0より大きい値を指定!" );
053:    				return;
054:    			}
055:    		}
056:    		catch( NumberFormatException ne )
057:    		{
058:    			System.out.println( "引数が不正です" );
059:    			return;
060:    		}
061:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
062:    		outname = args[ 0 ];

与えられた引数をそれぞれ、作成する画像の幅/高さ、線の本数/角度、出力PNG名を格納する変数に代入しています。画像の幅/高さ/線の本数は、Integerクラスを使ってint型に変換しています。線の角度は、Doubleクラスを使ってdouble型に変換しています。

064:    		// 新しい画像を作成
065:    		// 24ビットカラーの画像を作成
066:    		try {
067:    			img = new BufferedImage( w, h,
068:    						 BufferedImage.TYPE_INT_RGB );
069:    		} catch ( Exception e ) {
070:    			// 画像作成に失敗したときの処理
071:    			e.printStackTrace();
072:    			return;
073:    		}

BufferedImageクラスコンストラクタで、新しいBufferedImageを構築しています。

BufferedImageコンストラクタ

BufferedImage( int width, int height, int imageType )
■新しい BufferedImage を構築します。
  パラメータ width     : 構築する画像の横ピクセル
        height    : 構築する画像の縦ピクセル
        imageType : 構築する画像のイメージ形式

075:    		// 放射状模様 画像作成
076:    		int    x, y;
077:    		int    color, r, g, b;	// 計算した色
078:    		double mx, my;		// 画像の中心の座標
079:    		double deg, rad;	// (mx,my)を原点とした(x,y)の角度

画像作成で使う変数を宣言しています。

081:    		// 画像の中心座標を計算		
082:    		mx = (double)( w - 1 ) / 2.0;
083:    		my = (double)( h - 1 ) / 2.0;

画像の中心座標を計算しています。画像の座標の範囲は、左上(0,0)~右下(w-1,h-1)なので、(w-1)と(h-1)を2で割った値が画像の中心座標になります。

085:    		// 白部分の角度
086:    		w_deg = ( 360.0 - (double)l_num * l_deg ) / (double)l_num;

白の部分(線でない部分)の角度を計算しています。(線の本数×線の角度)を360から引いた値が白部分の合計の角度です。その角度を線の本数で割った値が白い部分の1つの角度として計算できます。

088:    		// 画像作成
089:    		for ( y = 0; y < h; ++ y ) {
090:    			for ( x = 0; x < w; ++ x ) {
091:    				// 角度(ラジアン)を計算
092:    				rad = atan3( (double)y - my, (double)x - my );
093:    
094:    				// ラジアンを度に変換
095:    				deg = rad * 180.0 / Math.PI;
096:    
097:    				// 判定式
098:    				if ( l_deg >= ( deg % ( l_deg + w_deg  ) ) )
099:    					r = g = b = 0;
100:    				else
101:    					r = g = b = 255;
102:    					
103:    				// rgbを合成
104:    				color = ( r << 16 ) + ( g << 8 ) + b;
105:    				// 色を設定
106:    				img.setRGB( x, y, color );
107:    			}
108:    		}

画像の中の全てのピクセルの座標(x,y)を参照するループをつくり、その座標の色が黒か白かを判定していきます。判定した色を(x,y)に代入していきます。

判定には、画像の中心座標(mx,my)と(x,y)を結んだ線とx軸との角度rad(ラジアン)をatan3メソッドで求め、その角度radを°単位に変換した角度deg(°)を使います。

求めた角度deg(°)を(線の角度+白部分の角度)で割った余りを求め、その値が線の角度以下であれば黒色とし、線の角度を超えていれば白色としています。

110:    		try {
111:    			// imgをoutname(出力PNG)に保存
112:    			boolean result;
113:    			result = ImageIO.write( img, "PNG", new File( outname ) );
114:    		} catch ( Exception e ) {
115:    			// outname(出力PNG)の保存に失敗したときの処理
116:    			e.printStackTrace();
117:    			return;
118:    		}

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

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

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

■関連コンテンツ

模様の描画 いろいろな模様の描画方法を紹介

■新着情報

2019.04.30 放射状模様 放射状模様の画像作成方法を紹介
2019.04.05 ストップウォッチ その1 単純なストップウォッチクラスの作り方を解説
2019.04.05 ストップウォッチ その2 ストップウォッチクラスの作り方を解説
2019.04.04 エッジ(境界)検出 カラー画像をN値化する方法について解説

■広告

法人向けのETC専用カード

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

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

 

 

 

 

 

 

 

Topへ