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

2020/10/13 公開

・2値化 その2

フルカラー画像を2色だけで表現した2値画像に変換し、2値のBMP形式で保存する方法を説明します。

元の画像元の画像      2値画像2値画像

フルカラー画像が持つ画素の色RGBの値が、白と黒のどちらの色に近いかを自動判定し、その近い色で埋めて画像を作成します。

ここで紹介する方法は、BufferedImageクラスで2値の画像を作成し、setRGBメソッドフルカラー画像RGB値を格納していくものです。

BufferedImageクラスで作成した2値画像カラーマップは黒(R=G=B=0)と白(R=G=B=255)の2色となります。この2つの色は、後で変えることもできます。

この2値画像に任意のRGB値を格納すると、自動的に2色のうちの近いほうの色を選んでくれます。これにより簡単に2値の画像を作成することができます。

2値化した画像は、2値のBMP形式で保存するようにしています。

以下は、上記内容のJavaソースコード例です。

Binarization2.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 Binarization2 {
007:    	public static void main( String[] args ) {
008:    		// ファイル名
009:    		String inname, outname;
010:    		// 画像格納クラス
011:    		BufferedImage img = null;
012:    
013:    		// 入力した引数が2つ以上かを調べる
014:    		if ( 2 > args.length ) {
015:    			// 入力した引数が2つ未満の場合、使用方法を表示する
016:    			System.out.println(
017:    				 "Binarization2 [入力JPEG名]  [出力BMP名]" );
018:    			return;
019:    		}
020:    
021:    		// 入力JPEG名をinnameに代入(拡張子".jpg"省略なし)
022:    		inname  = args[ 0 ];
023:    		// 出力BMP名をoutnameに代入(拡張子".bmp"省略なし)
024:    		outname = args[ 1 ];
025:    
026:    		// JPEG画像の読み込み
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:    		// 2値化
045:    		int x, y;
046:    		int width, height;
047:    		int color, r, g, b;
048:    		int newcolor;
049:    		BufferedImage img2 = null;
050:    
051:    		// 画像サイズの取得
052:    		width = img.getWidth();
053:    		height= img.getHeight();
054:    
055:    		// 1ビットカラーの画像を作成
056:    		try {
057:    			img2 = new BufferedImage( width, height,
058:    					BufferedImage.TYPE_BYTE_BINARY );
059:    		} catch ( Exception e ) {
060:    			// 画像作成に失敗したときの処理
061:    			e.printStackTrace();
062:    			return;
063:    		}
064:    
065:    		// 2値化処理
066:    		for ( y = 0; y < height; ++ y ) {
067:    			for ( x = 0; x < width; ++ x ) {
068:    				// (x,y)の色を取得
069:    				color = img.getRGB( x, y );
070:    
071:    				// 色をr,g,bに分解
072:    				r = ( color >> 16 ) & 0xff;
073:    				g = ( color >> 8 ) & 0xff;
074:    				b = color & 0xff;
075:    
076:    				// r,g,bの色を合成
077:    				newcolor = ( r << 16 ) + ( g << 8 ) + b;
078:    
079:    				// 合成した色を(x,y)に設定
080:    				img2.setRGB( x, y, newcolor );
081:    			}
082:    		}
083:    
084:    		// 2値のBMPで保存
085:    		try {
086:    			boolean result;
087:    			// imgをoutname(出力BMP)に保存
088:    			result = ImageIO.write( img2, "bmp", new File( outname ) );
089:    		} catch ( Exception e ) {
090:    			// outname(出力BMP)の保存に失敗したときの処理
091:    			e.printStackTrace();
092:    			return;
093:    		}
094:    
095:    		// 正常に終了
096:    		System.out.println( "正常に終了しました" );
097:    	}
098:    }

Binarization2を実行

java Binarization2 indexcolor-full.jpg binarization2.bmp

1つ目の引数で渡したJPEGファイルグレースケール画像に変換し、2つ目の引数で指定したBMPファイル名で保存します。

実行結果

・元の画像(indexcolor-full.jpg.jpg)

元画像

・変換後の2値のBMP画像(binarization2.bmp)

2値のBMP画像

画像が、白と黒の2色で表現されました。作成したBMP形式画像非圧縮ですが、ビットの深さが1(2色を表す)なのでサイズは、比較的小さくなっています。

それでは、このソースコードを順番に見ていきましょう。

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 Binarization2 {

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

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

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

008:    		// ファイル名
009:    		String inname, outname;
010:    		// 画像格納クラス
011:    		BufferedImage img = null;

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

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

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

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

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

026:    		// JPEG画像の読み込み
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:    		// 2値化
045:    		int x, y;
046:    		int width, height;
047:    		int color, r, g, b;
048:    		int newcolor;
049:    		BufferedImage img2 = null;

2値化で使う変数を宣言しています。

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

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

055:    		// 1ビットカラーの画像を作成
056:    		try {
057:    			img2 = new BufferedImage( width, height,
058:    					BufferedImage.TYPE_BYTE_BINARY );
059:    		} catch ( Exception e ) {
060:    			// 画像作成に失敗したときの処理
061:    			e.printStackTrace();
062:    			return;
063:    		}

フルカラーと同じ大きさの新しい2値画像を作成しています。色の種類BufferedImage.TYPE_BYTE_BINARYBufferedImageクラスを作成すると2値画像になります。

065:    		// 2値化処理
066:    		for ( y = 0; y < height; ++ y ) {
067:    			for ( x = 0; x < width; ++ x ) {
068:    				// (x,y)の色を取得
069:    				color = img.getRGB( x, y );

画像の中の全てのピクセルの座標を参照する変数xと変数yの多重ループをつくり、その座標色情報を取得しています。具体的には、変数yを0~height-1、変数xを0~width-1に変化させながら、BufferedImageクラスgetRGBメソッドで、(x,y)の色を変数colorに代入しています。

BufferedImage.getRGBメソッド

public static int getRGB( int x, int y )
■(x,y)で指定した画像座標の色情報を取得します。

  パラメータ x : 画像のx座標(単位ピクセル)
        y : 画像のy座標(単位ピクセル)

  戻り値     (x,y)の色情報

071:    				// 色をr,g,bに分解
072:    				r = ( color >> 16 ) & 0xff;
073:    				g = ( color >> 8 ) & 0xff;
074:    				b = color & 0xff;

変数colorに入っている色情報を赤(R)、緑(G)画、青(B)の成分に分解し、それぞれ変数a、b、cに代入しています。

色の分解方法の詳細はこちらを参照してください。「色をARGB値に分解」

076:    				// r,g,bの色を合成
077:    				newcolor = ( r << 16 ) + ( g << 8 ) + b;

色の成分を合成して、新しい色(変数newcolor)を作成しています。

079:    				// 合成した色を(x,y)に設定
080:    				img2.setRGB( x, y, newcolor );

新しい色(変数newcolor)を(x,y)に代入すると自動的に近い方の色が選択されます。

084:    		// 2値のBMPで保存
085:    		try {
086:    			boolean result;
087:    			// imgをoutname(出力BMP)に保存
088:    			result = ImageIO.write( img2, "bmp", new File( outname ) );
089:    		} catch ( Exception e ) {
090:    			// outname(出力BMP)の保存に失敗したときの処理
091:    			e.printStackTrace();
092:    			return;
093:    		}

BufferedImageクラスのimgのメモリ内のデータを、出力BMP名の変数(outname)に格納されているファイル名で保存します。この場合は、BMPファイル名が不正であったり、保存先の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を返します。

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

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

以上です。

■関連コンテンツ

カラーマップ 色番号に色を割り当て
画像の色 画像の色について解説
画像ファイル形式 画像ファイル形式について解説
N値化 カラー画像をN値化する方法について解説
カラー画像をグレースケールに変換する方法について解説-画像

グレースケール変換

カラー画像のRGB値の平均でグレースケールに変換する方法について解説しています。

より自然に見えるグレースケールに変換する方法を解説-画像

より自然なグレースケール変換

NTSC 加重平均法によるグレースケールに変換について解説しています。

カラー画像を2値化する方法について解説-画像

2値化

RGBの平均値と閾値を使ってカラー画像を2値化する方法を解説しています。

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

光と色の3原色

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

画素について説明-画像

画素

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

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

for文

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

for文の中にfor文-画像

多重ループ

for文などのループの中にループをいれたプログラムの構造、多重ループについて説明しています。

■新着情報

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

■広告

 

 

 

 

 

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

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

 

 

 

 

Topへ