Java 图像处理(一)
曾几何时,Java图像处理已经被认为是太过鸡肋,就连Java的创始公司,在java图像处理方面也是浅尝辄止,可能相比较C++,Java在这方面的处理,确实差强人意。
不过Java类库中有一个叫JAI的库,全程是javaadvancedimage—Java高级预想处理,其实个人觉得这个库非常丰富,奈何JAI只发行了2个版本就停止维护了,
到现在也没有找到源码,资料更是少的可怜。鉴于上述原因,本人将开始记录JAI以及Java二维图像相关知识,本文主要介绍Java图像的主要类以及图像基础知识。
Java中我们对图像的操纵一般使用BufferImage,比如我们一般会使用一下方法,将一个图片文件读取到bufferimage
BufferedImageimage=ImageIO.read(newFile("D:\Gis开发\数据\影像数据\tiff\china.tif"));这个是将已经存在的图片文件,读取到BufferedImage中,其实大家都知道图像之所以会呈现出各种颜色,无外乎就是像素值、颜色模型、样本模型这三个重要参数来体现的。其实Java的图像类
BufferedImage也无外乎这三个重要参数。比如我们通过BufferedImage构造参数就可以发现,其中一个构造参数是publicBufferedImage(ColorModelcm,WritableRasterraster,booleanisRasterPremultiplied,Hashtableproperties)这个构造参数中,ColorModel是颜色模型,raster是栅格数据,它是由像素值和样本模型构成的,这个我们可以通过它的构造函数看到
protectedWritableRaster(SampleModelsampleModel,DataBufferdataBuffer,Pointorigin)其中sampleModel是样例模型,dataBuffer是像素值数组。
下面介绍以上三个要素:
ColorModelJava中ColorModel的实现类主要有ComponentColorModel、IndexColorModel等,我们先来看看ComponentColorModel构造函数
publicComponentColorModel(ColorSpacecolorSpace,booleanhasAlpha,booleanisAlphaPremultiplied,inttransparency,inttransferType)其中colorSpace很重要,颜色空间其实决定了最终这些像素值是如何呈现在我们硬件上的,比如我们的电脑显示器,印刷等。
比如常见以下颜色空间:
RGB彩色模型@NativepublicstaticfinalintTYPE_RGB=5;灰度模型@NativepublicstaticfinalintTYPE_GRAY=6CMYK彩色模型@NativepublicstaticfinalintTYPE_CMYK=9;比如我们通常的彩色图是用 TYPE_RGB,创建灰度图用TYPE_GRAY,以及TYPE_CMYK颜色模型。
hasAlpha:是否有透明通道,比如常见的png(32),就有alpha通道
isAlphaPremultiplied: 这是处理透明的一个参数(相对深奥,后面会详细研究)
transparency: 透明类型 其中1表示完全不透明 2表示完全透明或不透明 3表示介于两者之间,也就是透明度可调(一般选择3)
transferType: 就是像素的数据类型,跟下面的dataType我认为是一样的
SampleModelJava中sampleModel的实现类主要有ComponentSampleModel以及它的子类PixelInterleavedSampleModel,我们来看看它的构造函数publicComponentSampleModel(intdataType,intw,inth,intpixelStride,intscanlineStride,intbandOffsets[])其中datatype:数据类型,即就是像素值的表示单位,比如常见的RGB三通道,使用TYPE_BYTE来表示,即就是每个通道8位,用0-255来表示,常见的DEM地形数据,也会直接使用TYPE_SHORT或者TYPE_FLOAT来定义。
w: 图片宽度
h: 图片高度
pixelStride:像素步幅,其实就是我们的像素在宽和高方向的间隔设置,通常设置为1,表示每个像素都会填充一个值,如果设置为2,则表示每2个位置设置一个像素值,这样其中的databuffer数组就会相应的缩减。
scanlineStride: 线性步幅,如果pixelStride为1,则scanlineStride为width。
bandOffsets:波段偏移量,一般都是0,比如RGB数据,一般都是newint[]{0,0,0}
像素值像素值其实就是表示颜色的数字,这里提示一点,比如RGB数据,如果数据类型是TYPE_BYTE,如果图片是10x10大小,则这个DataBufferByte的数组大小就是10*10*3。
下面我们来自定义一个图片:
byte[]rasterBuffer=newbyte[10*10*3];DataBufferBytedataBuffer=newDataBufferByte(rasterBuffer,10*10*3);ColorSpacespace=ColorSpace.getInstance(ColorSpace.CS_GRAY);ComponentSampleModelsampleModle=newComponentSampleModel(DataBuffer.TYPE_BYTE,10,10,1,10*3,newint[]{0,1,2});int[]bits={8,8,8};ComponentColorModelcolorModel=newComponentColorModel(space,bits,false,false,Transparency.TRANSLUCENT,DataBuffer.TYPE_BYTE);WritableRasterraster=Raster.createWritableRaster(sampleModle,dataBuffer,newPoint(0,0));BufferedImageimage=newBufferedImage(colorModel,raster,false,null);其实在日常开发中,我们经常会遇到ComponentColorModel,但是偶尔也会遇到IndexColorModel,这两个颜色模型有什么区别呢?
自己找了一个这样的数据,解析后发现,如下操作
从这个输出可以看出,图像的是IndexColorModel和普通ComponentColorModel是一样的,唯一不同的是rgb的数组大小不一样,下面我们来看看对应的samplemodel
可以看出虽然colorModel有3通道,但实际samplemodel的band只有一个,也就是说实际只有一个samplebands
这也就解是了原本按照三通道的样本,该数据的databuffer应该是7162*5968*3 而实际它的databuffer的size只有
7162*5968,也就是上图中的data的size大小,这跟我们平时看到的ComponentColorModel的data不一样,也就是用一位byte就表示了三个通道的颜色分量。
扩展
一般对于图像显示而言,我们拿到每个通道的颜色分量,其实还是需要转为显示器等输出设备可以识别的,这个我们可以通过ColorModel的getRGB()方法,我们来看下这个方法
publicintgetRGB(intpixel){if(numComponents>1){thrownewIllegalArgumentException("Morethanonecomponentperpixel");}if(signed){thrownewIllegalArgumentException("Componentvalueissigned");}return(getAlpha(pixel)
Java OCR 图像智能字符识别技术,可识别中文
http://blog.csdn.net/zhoushuyan/article/details/5948289
验证码的OCR方式识别http://ykf.iteye.com/blog/212431
几天一直在研究OCR技术,据我了解的情况,国内最专业的OCR软件只有2家,清华TH-OCR和汉王OCR,看了很多的OCR技术发现好多对英文与数字的支持都很好,可惜很多都不支持中文字符。Asprise-OCR,Tesseract3.0以前的版本,都不支持中文,其实我用了下Asprise-OCR算是速度比较的快了,可惜他鄙视中文,这个没有办法,正好这段时间知名的开源OCR引擎Tesseract3.0版本发布了,他给我们带来的好消息就是支持中文,相关的下载项目网站是:http://code.google.com/p/tesseract-ocr
虽然速度不是很客观可是毕竟人家开始支持中文也算是不错的,一个英文的语言包大概是1.8M,中文简体的语言包是39.5M,中文繁体的语言包是53M,这样就知道为什么识别中文慢的原因了
package com.ocr;
import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
/**
*
* 图像过滤,增强OCR识别成功率
*
*/
public class ImageFilter{
private BufferedImage image;
private int iw, ih;
private int[] pixels;
public ImageFilter(BufferedImageimage){
this.image =image;
iw =image.getWidth();
ih =image.getHeight();
pixels = new int[iw * ih];
}
/** 图像二值化 */
public BufferedImagechangeGrey(){
PixelGrabberpg= new PixelGrabber(image.getSource(),0,0, iw, ih, pixels,0,iw);
try {
pg.grabPixels();
} catch (InterruptedExceptione){
e.printStackTrace();
}
// 设定二值化的域值,默认值为100
int grey=100;
// 对图像进行二值化处理,Alpha值保持不变
ColorModelcm=ColorModel.getRGBdefault();
for (int i=0;igrey){
red=255;
} else {
red=0;
}
if (cm.getGreen(pixels[i])>grey){
green=255;
} else {
green=0;
}
if (cm.getBlue(pixels[i])>grey){
blue=255;
} else {
blue=0;
}
pixels[i]=alpha=green6){
green=green6;
} else {
green=green4;
}
}
} else {
if (green4>green6){
green=green4;
} else {
if (green5>green6){
green=green6;
} else {
green=green5;
}
}
}
// int blue2=cm.getBlue(pixels[(i-1)* iw +j]);
int blue4=cm.getBlue(pixels[i* iw +j-1]);
int blue5=cm.getBlue(pixels[i* iw +j]);
int blue6=cm.getBlue(pixels[i* iw +j+1]);
// int blue8=cm.getBlue(pixels[(i+1)* iw +j]);
// 水平方向进行中值滤波
if (blue4>=blue5){
if (blue5>=blue6){
blue=blue5;
} else {
if (blue4>=blue6){
blue=blue6;
} else {
blue=blue4;
}
}
} else {
if (blue4>blue6){
blue=blue4;
} else {
if (blue5>blue6){
blue=blue6;
} else {
blue=blue5;
}
}
}
pixels[i* iw +j]=alpha