Javaプログラミング学習サイト ゆるゆるプログラミング

2020/11/11 公開

・正確な割合のノイズ画像

乱数を使って指定サイズのノイズ画像を作る方法を解説します。ノイズが発生する割合をパーセントで指定することで、ノイズの密度を調整することができるようにします。

ここでは、ノイズピクセルの数が

 (幅ピクセル数×高さピクセル数)× 発生する割合(%)÷100

になる方法を説明します。(小数点以下は切捨て)

まず、指定した幅ピクセルと高さピクセル画像を作成します。

次に、上記の式でノイズピクセル数を計算し、画像の上部をノイズ数の黒色ピクセルで埋めます。(下図の左)

最後に、画像の全てのピクセルの色を乱数を使って入れ替えます。(下図の右)

ノイズ画像作成の元画像(30%)

この処理によって、ノイズピクセルの割合を正確にすることができます。

以下が、ノイズ画像を作成するJavaソースコード例です。

Noise3.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 Noise3 {
007:    	public static void main( String[] args ) {
008:    		// 変数宣言
009:    		int w, h;		// 画像の幅・高さ
010:    		double noiserate;	// ノイズの割合
011:    		String outname;	// 出力ファイル名
012:    		BufferedImage img = null;	// 画像格納クラス
013:    
014:    		// 入力した引数が4以上かを調べる
015:    		if ( 4 > args.length ) {
016:    			// 入力した引数が4未満の場合、使用方法を表示する
017:    			System.out.println( 
018:    				"Noise3 [出力PNG名][幅][高][ノイズの割合%]" );
019:    			return;
020:    		}
021:    
022:    		try {
023:    			// 引数を変換し、画像サイズに代入
024:    			w  =  Integer.valueOf( args[ 1 ] );
025:    			h  =  Integer.valueOf( args[ 2 ] );
026:    			// 引数を変換し、ノイズの割合に代入
027:    			noiserate = Double.valueOf( args[ 3 ] );
028:    		}
029:    		catch( NumberFormatException ne )
030:    		{
031:    			System.out.println( "引数が不正です" );
032:    			return;
033:    		}
034:    
035:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
036:    		outname = args[ 0 ];
037:    
038:    		// 新しい画像を作成
039:    		// 24ビットカラーの画像を作成
040:    		try {
041:    			img = new BufferedImage( w, h,
042:    						 BufferedImage.TYPE_INT_RGB );
043:    		} catch ( Exception e ) {
044:    			// 画像作成に失敗したときの処理
045:    			e.printStackTrace();
046:    			return;
047:    		}
048:    
049:    		// ノイズ画像の作成
050:    		int x, y, noisecount;
051:    		int sx, sy;
052:    		int r, g, b, color;
053:    		int color1, color2;
054:    
055:    		// ノイズ数を正確に計算
056:    		noisecount = (int)( (double)( h * w ) * noiserate / 100.0 );
057:    
058:    		// ノイズ画像の元になる画像を作成
059:    		for ( y = 0; y < h; ++ y ) {
060:    			for ( x = 0; x < w; ++ x ) {
061:    				// ノイズ色を決定
062:    				if ( 1 <= noisecount ) {
063:    					// ノイズとして黒色を設定
064:    					r = 0;
065:    					g = 0;
066:    					b = 0;
067:    					-- noisecount;
068:    				}
069:    				else {
070:    					// ノイズでない白色を設定
071:    					r = 255;
072:    					g = 255;
073:    					b = 255;
074:    				}
075:    
076:    				// r,g,bの色を合成
077:    				color = ( r << 16 ) + ( g << 8 ) + b;
078:    
079:    				// 合成した色を(x,y)に設定
080:    				img.setRGB( x, y, color );
081:    			}
082:    		}
083:    
084:    		// 全ピクセルをランダムに並び替え
085:    		for ( y = 0; y < h; ++ y ) {
086:    			for ( x = 0; x < w; ++ x ) {
087:    				// sxに0~w-1の乱数を格納
088:    				sx = (int)( Math.random() * (double)w ); 
089:    
090:    				// syに0~h-1の乱数を格納
091:    				sy = (int)( Math.random() * (double)h ); 
092:    
093:    				// (x,y)と(sx,sy)の色を入れ替える
094:    				color1 = img.getRGB( x, y );
095:    				color2 = img.getRGB( sx, sy );
096:    				img.setRGB( x, y, color2 );
097:    				img.setRGB( sx, sy, color1 );
098:    			}
099:    		}
100:    
101:    
102:    		// 画像をPNG出力
103:    		try {
104:    			// imgをoutname(出力PNG)に保存
105:    			boolean result;
106:    			result = ImageIO.write( img, "PNG", new File( outname ) );
107:    		} catch ( Exception e ) {
108:    			// outname(出力PNG)の保存に失敗したときの処理
109:    			e.printStackTrace();
110:    			return;
111:    		}
112:    
113:    		// 正常に終了
114:    		System.out.println( "正常に終了しました" );
115:    	}
116:    }

Noise3を実行

C:\talavax\javasample>java Noise3 noise3_50.png 256 256 50

2つ目と3つ目の引数ピクセル座標、4つ目の引数ノイズピクセルの発生率をパーセントで指定します。これらの引数からノイズ画像を作成し、1つ目の引数で指定したPNGファイル名で保存します。

この例では、ノイズピクセル発生率50%で、サイズ256x256のPNGファイル(noise3_50.png)を作成しています。

実行結果

ノイズ画像(50%)ノイズ画像(50%)

ノイズ発生率50%、幅256ピクセル、高さ256ピクセルノイズ画像が作成されました。黒色がノイズピクセルです。

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

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

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

006:    public class Noise3 {

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

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

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

008:    		// 変数宣言
009:    		int w, h;		// 画像の幅・高さ
010:    		double noiserate;	// ノイズの割合
011:    		String outname;	// 出力ファイル名
012:    		BufferedImage img = null;	// 画像格納クラス

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

014:    		// 入力した引数が4以上かを調べる
015:    		if ( 4 > args.length ) {
016:    			// 入力した引数が4未満の場合、使用方法を表示する
017:    			System.out.println( 
018:    				"Noise3 [出力PNG名][幅][高][ノイズの割合%]" );
019:    			return;
020:    		}

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

022:    		try {
023:    			// 引数を変換し、画像サイズに代入
024:    			w  =  Integer.valueOf( args[ 1 ] );
025:    			h  =  Integer.valueOf( args[ 2 ] );
026:    			// 引数を変換し、ノイズの割合に代入
027:    			noiserate = Double.valueOf( args[ 3 ] );
028:    		}
029:    		catch( NumberFormatException ne )
030:    		{
031:    			System.out.println( "引数が不正です" );
032:    			return;
033:    		}

与えられた引数をそれぞれ、ピクセル幅、、ピクセルの高さ、ノイズの割合を格納する変数に代入しています。

035:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
036:    		outname = args[ 0 ];

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

038:    		// 新しい画像を作成
039:    		// 24ビットカラーの画像を作成
040:    		try {
041:    			img = new BufferedImage( w, h,
042:    						 BufferedImage.TYPE_INT_RGB );
043:    		} catch ( Exception e ) {
044:    			// 画像作成に失敗したときの処理
045:    			e.printStackTrace();
046:    			return;
047:    		}

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

BufferedImageコンストラクタ

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

imgTypeで指定しているTYPE_INT_RGBは、整数ピクセルにパックされた 8 ビット RGB 色成分によるイメージを表します。これを指定することで24ビット画像を作成できます。

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

049:    		// ノイズ画像の作成
050:    		int x, y, noisecount;
051:    		int sx, sy;
052:    		int r, g, b, color;
053:    		int color1, color2;

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

055:    		// ノイズ数を正確に計算
056:    		noisecount = (int)( (double)( h * w ) * noiserate / 100.0 );

画像の幅と高さのピクセル数とノイズの割合からノイズピクセルの個数を計算し、結果をint型変数noisecountに代入しています。

058:    		// ノイズ画像の元になる画像を作成
059:    		for ( y = 0; y < h; ++ y ) {
060:    			for ( x = 0; x < w; ++ x ) {
061:    				// ノイズ色を決定
062:    				if ( 1 <= noisecount ) {
063:    					// ノイズとして黒色を設定
064:    					r = 0;
065:    					g = 0;
066:    					b = 0;
067:    					-- noisecount;
068:    				}
069:    				else {
070:    					// ノイズでない白色を設定
071:    					r = 255;
072:    					g = 255;
073:    					b = 255;
074:    				}
075:    
076:    				// r,g,bの色を合成
077:    				color = ( r << 16 ) + ( g << 8 ) + b;
078:    
079:    				// 合成した色を(x,y)に設定
080:    				img.setRGB( x, y, color );
081:    			}
082:    		}

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

このループの中で、noisecountが1以上であればノイズ色のピクセルを代入しています。ノイズ色を代入する毎に、noisecountから1ずつひいています。

084:    		// 全ピクセルをランダムに並び替え
085:    		for ( y = 0; y < h; ++ y ) {
086:    			for ( x = 0; x < w; ++ x ) {
087:    				// sxに0~w-1の乱数を格納
088:    				sx = (int)( Math.random() * (double)w ); 
089:    
090:    				// syに0~h-1の乱数を格納
091:    				sy = (int)( Math.random() * (double)h ); 
092:    
093:    				// (x,y)と(sx,sy)の色を入れ替える
094:    				color1 = img.getRGB( x, y );
095:    				color2 = img.getRGB( sx, sy );
096:    				img.setRGB( x, y, color2 );
097:    				img.setRGB( sx, sy, color1 );
098:    			}
099:    		}

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

このループの中で、画像座標(x,y)の色と、ランダムに発生した画像座標(sx,sy)の色を入れ替えています。

Math.randomメソッド

public static double Math.random()
■乱数を返します。

  パラメータ なし

  戻り値     0.0以上、1.0未満の乱数

102:    		// 画像をPNG出力
103:    		try {
104:    			// imgをoutname(出力PNG)に保存
105:    			boolean result;
106:    			result = ImageIO.write( img, "PNG", new File( outname ) );
107:    		} catch ( Exception e ) {
108:    			// outname(出力PNG)の保存に失敗したときの処理
109:    			e.printStackTrace();
110:    			return;
111:    		}

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

ImageIO.writeメソッド

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

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

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

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

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

以上です。

■関連コンテンツ

画像の色 画像の色について解説
画像ファイル形式 画像ファイル形式について解説
配列の並び替え 配列をランダムに並び替える方法を解説
コマンドライン引数 外部からの値を受け取る方法について解説
乱数を使ってノイズ画像を作成する方法について解説-画像

ノイズ画像

乱数を使ったノイズ画像の作成方法について解説しています。

乱数を使って画像にノイズを加える方法を解説-画像

画像にノイズを加える

乱数を使って画像にノイズを加える方法を解説しています。

光と色の3原色の考え方を解説-画像

光と色の3原色

光の3色(RGB)の混合と、インクの3色(CMY)の混合の考え方を説明しています。

画素について説明-画像

画素

画素とは、デジタル画像データを構成している色情報を持った点のことです。

繰り返し処理に使用するfor文について解説-画像

for文

繰り返し処理に使用するfor文をJavaのソースコードを使って説明しています。

Math.randomの使い方について解説-画像

乱数 random

Math.randomメソッドを使って乱数を発生する方法を解説します。指定範囲の乱数の発生方法も解説しています。

■新着情報

2022.07.07 外部プログラムの実行 exeファイル実行
2022.07.06 完全数 6=1+2+3

■広告

 

 

 

 

 

スッキリわかるJava入門第3版 [ 中山清喬 ]

価格:2,860円
(2021/6/18 14:32時点)
感想(6件)

 

 

 

 

Topへ