最近一直在開發一個用於自動發帖的工具,用HttpClient類比用戶端瀏覽器註冊發帖。但是碰到了圖形驗證碼的問題了,對單數位驗證碼,通過一些OCR引擎,如:tesseract,AspriseOCR很容易解決問題。但碰到如CSDN論壇這中圖形驗證碼就比較麻煩,必須先通過預先處理。使圖象二值化,黑白灰階,增加亮度。My Code如下:package myfilter;<br />import java.io.*;<br />import java.awt.image.*;<br />import java.awt.geom.AffineTransform;<br />import java.awt.color.ColorSpace;<br />import java.awt.image.ConvolveOp;<br />import java.awt.image.Kernel;<br />import java.awt.image.BufferedImage;<br />import javax.imageio.ImageIO;<br />import java.awt.Toolkit;<br />import java.awt.Image;</p><p>/**<br /> * <p>Title: Image Filter</p><br /> *<br /> * <p>Description: image processing by filters </p><br /> * <p>Copyright: Copyright (c) 2010</p><br /> *<br /> * @author gl74gs48@163.com<br /> * @since jdk1.5.0<br /> * @version 1.0<br /> */<br />public class MyImgFilter {<br /> BufferedImage image;<br /> private int iw, ih;<br /> private int[] pixels;</p><p> public MyImgFilter(BufferedImage image) {<br /> this.image = image;<br /> iw = image.getWidth();<br /> ih = image.getHeight();<br /> pixels = new int[iw * ih];</p><p> }</p><p> /** 映像二值化 */<br /> public BufferedImage changeGrey() {</p><p> PixelGrabber pg = new PixelGrabber(image.getSource(), 0, 0, iw, ih, pixels,0, iw);<br /> try {<br /> pg.grabPixels();<br /> } catch (InterruptedException e) {<br /> e.printStackTrace();<br /> }<br /> // 設定二值化的域值,預設值為100<br /> int grey = 100;<br /> // 對映像進行二值化處理,Alpha值保持不變<br /> ColorModel cm = ColorModel.getRGBdefault();<br /> for (int i = 0; i < iw * ih; i++) {<br /> int red, green, blue;<br /> int alpha = cm.getAlpha(pixels[i]);<br /> if (cm.getRed(pixels[i]) > grey) {<br /> red = 255;<br /> } else {<br /> red = 0;<br /> }<br /> if (cm.getGreen(pixels[i]) > grey) {<br /> green = 255;<br /> } else {<br /> green = 0;<br /> }<br /> if (cm.getBlue(pixels[i]) > grey) {<br /> blue = 255;<br /> } else {<br /> blue = 0;<br /> }<br /> pixels[i] = alpha << 24 | red << 16 | green << 8 | blue; //通過移位重新構成某一點像素的RGB值<br /> }<br /> // 將數組中的象素產生一個映像<br /> Image tempImg=Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(iw,ih, pixels, 0, iw));<br /> image = new BufferedImage(tempImg.getWidth(null),tempImg.getHeight(null), BufferedImage.TYPE_INT_BGR );<br /> image.createGraphics().drawImage(tempImg, 0, 0, null);<br /> return image;</p><p> }</p><p> /** 中值濾波 */<br /> public BufferedImage getMedian() {<br /> PixelGrabber pg = new PixelGrabber(image.getSource(), 0, 0, iw, ih,<br /> pixels,<br /> 0, iw);<br /> try {<br /> pg.grabPixels();<br /> } catch (InterruptedException e) {<br /> e.printStackTrace();<br /> }<br /> // 對映像進行中值濾波,Alpha值保持不變<br /> ColorModel cm = ColorModel.getRGBdefault();<br /> for (int i = 1; i < ih - 1; i++) {<br /> for (int j = 1; j < iw - 1; j++) {<br /> int red, green, blue;<br /> int alpha = cm.getAlpha(pixels[i * iw + j]);</p><p> // int red2 = cm.getRed(pixels[(i - 1) * iw + j]);<br /> int red4 = cm.getRed(pixels[i * iw + j - 1]);<br /> int red5 = cm.getRed(pixels[i * iw + j]);<br /> int red6 = cm.getRed(pixels[i * iw + j + 1]);<br /> // int red8 = cm.getRed(pixels[(i + 1) * iw + j]);</p><p> // 水平方向進行中值濾波<br /> if (red4 >= red5) {<br /> if (red5 >= red6) {<br /> red = red5;<br /> } else {<br /> if (red4 >= red6) {<br /> red = red6;<br /> } else {<br /> red = red4;<br /> }<br /> }<br /> } else {<br /> if (red4 > red6) {<br /> red = red4;<br /> } else {<br /> if (red5 > red6) {<br /> red = red6;<br /> } else {<br /> red = red5;<br /> }<br /> }<br /> }</p><p> int green4 = cm.getGreen(pixels[i * iw + j - 1]);<br /> int green5 = cm.getGreen(pixels[i * iw + j]);<br /> int green6 = cm.getGreen(pixels[i * iw + j + 1]);</p><p> // 水平方向進行中值濾波<br /> if (green4 >= green5) {<br /> if (green5 >= green6) {<br /> green = green5;<br /> } else {<br /> if (green4 >= green6) {<br /> green = green6;<br /> } else {<br /> green = green4;<br /> }<br /> }<br /> } else {<br /> if (green4 > green6) {<br /> green = green4;<br /> } else {<br /> if (green5 > green6) {<br /> green = green6;<br /> } else {<br /> green = green5;<br /> }<br /> }<br /> }</p><p> // int blue2 = cm.getBlue(pixels[(i - 1) * iw + j]);<br /> int blue4 = cm.getBlue(pixels[i * iw + j - 1]);<br /> int blue5 = cm.getBlue(pixels[i * iw + j]);<br /> int blue6 = cm.getBlue(pixels[i * iw + j + 1]);<br /> // int blue8 = cm.getBlue(pixels[(i + 1) * iw + j]);</p><p> // 水平方向進行中值濾波<br /> if (blue4 >= blue5) {<br /> if (blue5 >= blue6) {<br /> blue = blue5;<br /> } else {<br /> if (blue4 >= blue6) {<br /> blue = blue6;<br /> } else {<br /> blue = blue4;<br /> }<br /> }<br /> } else {<br /> if (blue4 > blue6) {<br /> blue = blue4;<br /> } else {<br /> if (blue5 > blue6) {<br /> blue = blue6;<br /> } else {<br /> blue = blue5;<br /> }<br /> }<br /> }<br /> pixels[i * iw +<br /> j] = alpha << 24 | red << 16 | green << 8 | blue;<br /> }<br /> }</p><p> // 將數組中的象素產生一個映像<br /> Image tempImg=Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(iw,ih, pixels, 0, iw));<br /> image = new BufferedImage(tempImg.getWidth(null),tempImg.getHeight(null), BufferedImage.TYPE_INT_BGR );<br /> image.createGraphics().drawImage(tempImg, 0, 0, null);<br /> return image;</p><p> }</p><p> public BufferedImage getGrey() {<br /> ColorConvertOp ccp=new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);<br /> return image=ccp.filter(image,null);<br /> }</p><p> //Brighten using a linear formula that increases all color values<br /> public BufferedImage getBrighten() {<br /> RescaleOp rop=new RescaleOp(1.25f, 0, null);<br /> return image=rop.filter(image,null);<br /> }<br /> //Blur by "convolving" the image with a matrix<br /> public BufferedImage getBlur() {<br /> float[] data = {<br /> .1111f, .1111f, .1111f,<br /> .1111f, .1111f, .1111f,<br /> .1111f, .1111f, .1111f, };<br /> ConvolveOp cop = new ConvolveOp(new Kernel(3, 3, data));<br /> return image=cop.filter(image,null);</p><p> }</p><p> // Sharpen by using a different matrix<br /> public BufferedImage getSharpen() {<br /> float[] data = {<br /> 0.0f, -0.75f, 0.0f,<br /> -0.75f, 4.0f, -0.75f,<br /> 0.0f, -0.75f, 0.0f};<br /> ConvolveOp cop = new ConvolveOp(new Kernel(3, 3, data));<br /> return image=cop.filter(image,null);<br /> }<br /> // 11) Rotate the image 180 degrees about its center point<br /> public BufferedImage getRotate() {<br /> AffineTransformOp atop=new AffineTransformOp(AffineTransform.getRotateInstance(Math.PI,image.getWidth()/2,image.getHeight()/2),<br /> AffineTransformOp.TYPE_NEAREST_NEIGHBOR);<br /> return image=atop.filter(image,null);<br /> }</p><p> public BufferedImage getProcessedImg()<br /> {<br /> return image;<br /> }</p><p> public static void main(String[] args) throws IOException {<br /> FileInputStream fin=new FileInputStream(args[0]);<br /> BufferedImage bi=ImageIO.read(fin);<br /> MyImgFilter flt=new MyImgFilter(bi);<br /> flt.changeGrey();<br /> flt.getGrey();<br /> flt.getBrighten();<br /> bi=flt.getProcessedImg();</p><p> String pname=args[0].substring(0,args[0].lastIndexOf("."));<br /> File file = new File(pname+".jpg");<br /> ImageIO.write(bi, "jpg", file);<br /> }</p><p>}
運行java myfilter.MyImgFilter t6.bmp,請確認圖片t6.bmp與myfilter目錄在同一目錄下。
順便說一下,在JDK1.5下,ImageIO可以輸出JPG,BMP,PNG三種格式圖片,但不支援GIF圖片輸出。
經處理後圖片的識別率大大提高。
部分代碼參考http://ykf.javaeye.com/blog/212431及《Java Examples In A Nutshell 3rd》