JAVA實現圖片二值化

    哎,項目要實現JAVA的圖像二值化。糾結呀,在我影像中java對圖像處理並不怎麼好用,但是沒辦法,成本要控制,只能拿出我們最大的法寶Google。沒想到Google了一下,java集成的圖像處理並沒有我相像的那麼難用,經過不斷地嘗試,項目也成功進入測試階段,現將二值化方面信息拿出來和大家共享,也請大家指正。

 

一、首先說一下javax.imageio.ImageIO吧。

JDk版本

java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b06)
Java HotSpot(TM) Client VM (build 1.6.0_02-b06, mixed mode, sharing)

 

ImageIO可以處理的圖像類型。

System.out.println(Arrays.asList(ImageIO.getReaderFormatNames()));

輸出:[jpg, BMP, bmp, JPG, wbmp, jpeg, png, PNG, JPEG, WBMP, GIF, gif]

看可以看到JDK1.6通過ImageIO可以加載以上類型的圖片。

二、通過BufferedImage來處理圖片。

BufferedImage bi=ImageIO.read(new File("D:/Test/binary/test.jpg"));//通過imageio將圖像載入
		int h=bi.getHeight();//獲取圖像的高
		int w=bi.getWidth();//獲取圖像的寬
		int rgb=bi.getRGB(0, 0);//獲取指定座標的ARGB的像素值

 可以看出通過BufferedImage 就可以輕鬆的獲取圖像的尺寸。

int BufferedImage.getRGB(x,y).獲取到的是ARGB,最前面多了一個透明度。將返回的int轉爲16進制後,0-1透明度,2-3是R,4-5是G,6-7是B。

三、具體二值化的算法。

1、首先獲取每個像素點的灰度值。目前使用簡單的(R+G+B)/3

2、然後選定一個閥值。

3、將一個像素點灰度值和它周圍的8個灰度值相加再除以9,然後和閥值比較。大於閥值的則置爲255,小於則是0

 

四、廢話少說,具體代碼如下。

package image.binary;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class BinaryTest {
	
	public static void main(String[] args) throws IOException {
		BufferedImage bi=ImageIO.read(new File("D:/Test/binary/test.jpg"));//通過imageio將圖像載入
		int h=bi.getHeight();//獲取圖像的高
		int w=bi.getWidth();//獲取圖像的寬
		int rgb=bi.getRGB(0, 0);//獲取指定座標的ARGB的像素值
		int[][] gray=new int[w][h];
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				gray[x][y]=getGray(bi.getRGB(x, y));
			}
		}
		
		BufferedImage nbi=new BufferedImage(w,h,BufferedImage.TYPE_BYTE_BINARY);
		int SW=160;
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				if(getAverageColor(gray, x, y, w, h)>SW){
					int max=new Color(255,255,255).getRGB();
					nbi.setRGB(x, y, max);
				}else{
					int min=new Color(0,0,0).getRGB();
					nbi.setRGB(x, y, min);
				}
			}
		}
		
		ImageIO.write(nbi, "jpg", new File("D:/Test/binary/二值化後_無壓縮.jpg"));
	}

	public static int getGray(int rgb){
		String str=Integer.toHexString(rgb);
		int r=Integer.parseInt(str.substring(2,4),16);
		int g=Integer.parseInt(str.substring(4,6),16);
		int b=Integer.parseInt(str.substring(6,8),16);
		//or 直接new個color對象
		Color c=new Color(rgb);
		r=c.getRed();
	    	g=c.getGreen();
		b=c.getBlue();
		int top=(r+g+b)/3;
		return (int)(top);
	}
	
	/**
	 * 自己加周圍8個灰度值再除以9,算出其相對灰度值
	 * @param gray
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @return
	 */
	public static int  getAverageColor(int[][] gray, int x, int y, int w, int h)
    {
        int rs = gray[x][y]
                      	+ (x == 0 ? 255 : gray[x - 1][y])
			            + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
			            + (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1])
			            + (y == 0 ? 255 : gray[x][y - 1])
			            + (y == h - 1 ? 255 : gray[x][y + 1])
			            + (x == w - 1 ? 255 : gray[x + 1][ y])
			            + (x == w - 1 || y == 0 ? 255 : gray[x + 1][y - 1])
			            + (x == w - 1 || y == h - 1 ? 255 : gray[x + 1][y + 1]);
        return rs / 9;
    }

}

相對較簡單,將一個jpg圖片二值化後產生一個無壓縮的jpg文件。

 

 五、壓縮

有些時候是需要將二值化後的圖片進行壓縮的,然後轉成tiff格式的文件,以減少存儲成本。但是jdk1.6的imageIO還沒有加入TIFF格式的圖像處理,那麼可以使用輔助的包了。

1、jai-imageio包。目前發佈的最新版本爲1.1,1.2還在開發中。。

http://download.java.net/media/jai-imageio/builds/release/1_0_01/jai_imageio-1_0_01-windows-i586-jar.zip
2、解壓後就兩個jar包和一個dll。dll丟進PATH中,jar包放入工程,則我們就可以做壓縮咯。

System.out.println(Arrays.asList(ImageIO.getWriterFormatNames()));

 看看,加入jar後的Imageio:

 [raw, tif, jpeg, JFIF, WBMP, jpeg-lossless, jpeg-ls, PNM, JPG, wbmp, PNG, JPEG, jpeg 2000, tiff, BMP, JPEG2000, RAW, JPEG-LOSSLESS, jpeg2000, GIF, TIF, TIFF, bmp, jpg, pnm, png, jfif, JPEG 2000, gif, JPEG-LS]

是不是可以處理的格式更強大了呢。。

 

3、壓縮的全部代碼。。

package image.binary;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;

import com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriterSpi;

public class BinaryTest {
	
	public static void main(String[] args) throws IOException {
		BufferedImage bi=ImageIO.read(new File("D:/Test/binary/test.jpg"));//通過imageio將圖像載入
		int h=bi.getHeight();//獲取圖像的高
		int w=bi.getWidth();//獲取圖像的寬
		int[][] gray=new int[w][h];
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				gray[x][y]=getGray(bi.getRGB(x, y));
			}
		}
		
		BufferedImage nbi=new BufferedImage(w,h,BufferedImage.TYPE_BYTE_BINARY);
		int SW=160;
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				if(getAverageColor(gray, x, y, w, h)>SW){
					int max=new Color(255,255,255).getRGB();
					nbi.setRGB(x, y, max);
				}else{
					int min=new Color(0,0,0).getRGB();
					nbi.setRGB(x, y, min);
				}
			}
		}
		
		TIFFImageWriterSpi tiffws=new TIFFImageWriterSpi();
		ImageWriter writer=tiffws.createWriterInstance();
		ImageWriteParam param=writer.getDefaultWriteParam();
		param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		param.setCompressionType("CCITT T.6");
		param.setCompressionQuality(0.8f);
		File outFile=new File("D:/Test/binary/二值化後_有壓縮.tiff");
		ImageOutputStream ios=ImageIO.createImageOutputStream(outFile);
		writer.setOutput(ios);
		writer.write(null,new IIOImage(nbi, null, null), param);
	}

	public static int getGray(int rgb){
		String str=Integer.toHexString(rgb);
		int r=Integer.parseInt(str.substring(2,4),16);
		int g=Integer.parseInt(str.substring(4,6),16);
		int b=Integer.parseInt(str.substring(6,8),16);
		//or 直接new個color對象
		Color c=new Color(rgb);
		r=c.getRed();
	    g=c.getGreen();
		b=c.getBlue();
		int top=(r+g+b)/3;
		return (int)(top);
	}
	
	/**
	 * 自己加周圍8個灰度值再除以9,算出其相對灰度值
	 * @param gray
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @return
	 */
	public static int  getAverageColor(int[][] gray, int x, int y, int w, int h)
    {
        int rs = gray[x][y]
                      	+ (x == 0 ? 255 : gray[x - 1][y])
			            + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
			            + (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1])
			            + (y == 0 ? 255 : gray[x][y - 1])
			            + (y == h - 1 ? 255 : gray[x][y + 1])
			            + (x == w - 1 ? 255 : gray[x + 1][ y])
			            + (x == w - 1 || y == 0 ? 255 : gray[x + 1][y - 1])
			            + (x == w - 1 || y == h - 1 ? 255 : gray[x + 1][y + 1]);
        return rs / 9;
    }

}

六、總結。。

1、效率問題還可以滿足我們項目的要求,但是如果有同學想這樣用的話一定要實際測試一下效率哦。

2、以及處理的圖片效果。附件1.1版本的jai。

  • pic.zip (120.6 KB)
  • 下載次數: 103











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章