2

Java 图像处理(一) - 开放GIS

 2 years ago
source link: https://www.cnblogs.com/share-gis/p/15937945.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java 图像处理(一)

< 2022年4月 > 日 一 二 三 四 五 六 27 28 29 30 31 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 1 2 3 4 5 6 7

  曾几何时,Java图像处理已经被认为是太过鸡肋,就连Java的创始公司,在java图像处理方面也是浅尝辄止,可能相比较C++,Java在这方面的处理,确实差强人意。

不过Java类库中有一个叫JAI的库,全程是java advanced image—Java高级预想处理,其实个人觉得这个库非常丰富,奈何JAI只发行了2个版本就停止维护了,

到现在也没有找到源码,资料更是少的可怜。鉴于上述原因,本人将开始记录JAI以及Java 二维图像相关知识,本文主要介绍Java图像的主要类以及图像基础知识。

  Java中我们对图像的操纵一般使用BufferImage,比如我们一般会使用一下方法,将一个图片文件读取到bufferimage

BufferedImage image = ImageIO.read(new File("D:\\Gis开发\\数据\\影像数据\\tiff\\china.tif"));

        这个是将已经存在的图片文件,读取到BufferedImage中,其实大家都知道图像之所以会呈现出各种颜色,无外乎就是像素值、颜色模型、样本模型这三个重要参数来体现的。其实Java的图像类

BufferedImage也无外乎这三个重要参数。
比如我们通过BufferedImage构造参数就可以发现,其中一个构造参数是
public BufferedImage (ColorModel cm,
                      WritableRaster raster,
                      boolean isRasterPremultiplied,
                      Hashtable<?,?> properties)

 这个构造参数中,ColorModel是颜色模型,raster是栅格数据,它是由像素值和样本模型构成的,这个我们可以通过它的构造函数看到

protected WritableRaster(SampleModel sampleModel,
                         DataBuffer dataBuffer,
                         Point origin) 

其中sampleModel是样例模型,dataBuffer是像素值数组。

下面介绍以上三个要素:

  • ColorModel

Java中ColorModel的实现类主要有ComponentColorModel、IndexColorModel等,我们先来看看ComponentColorModel构造函数

public ComponentColorModel (ColorSpace colorSpace,
                                boolean hasAlpha,
                                boolean isAlphaPremultiplied,
                                int transparency,
                                int transferType) 

其中colorSpace很重要,颜色空间其实决定了最终这些像素值是如何呈现在我们硬件上的,比如我们的电脑显示器,印刷等。

比如常见以下颜色空间:

RGB彩色模型
@Native public static final int TYPE_RGB = 5; 
灰度模型
@Native public static final int TYPE_GRAY = 6
CMYK彩色模型
@Native public static final int TYPE_CMYK = 9;

比如我们通常的彩色图是用 TYPE_RGB,创建灰度图用TYPE_GRAY,以及TYPE_CMYK颜色模型。

hasAlpha:是否有透明通道,比如常见的png(32),就有alpha通道  

isAlphaPremultiplied:  这是处理透明的一个参数(相对深奥,后面会详细研究)

transparency:  透明类型    其中1表示完全不透明  2表示完全透明或不透明  3表示介于两者之间,也就是透明度可调(一般选择3)

transferType:   就是像素的数据类型,跟下面的dataType我认为是一样的

  • SampleModel
Java中sampleModel的实现类主要有ComponentSampleModel以及它的子类PixelInterleavedSampleModel,我们来看看它的构造函数
public ComponentSampleModel(int dataType,
                                int w, int h,
                                int pixelStride,
                                int scanlineStride,int bandOffsets[])

其中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数据,一般都是new int[] {0,0,0}

像素值其实就是表示颜色的数字,这里提示一点,比如RGB数据,如果数据类型是TYPE_BYTE,如果图片是10x10大小,则这个DataBufferByte的数组大小就是10*10*3。

下面我们来自定义一个图片:

byte[] rasterBuffer = new byte[10*10*3];
DataBufferByte dataBuffer = new DataBufferByte(rasterBuffer, 10*10*3);
ColorSpace space = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ComponentSampleModel sampleModle = new ComponentSampleModel(DataBuffer.TYPE_BYTE,10, 10, 1, 10*3, new int[] {0,1,2});
int[] bits = {8,8,8};
ComponentColorModel colorModel = new ComponentColorModel(space, bits, false, false, Transparency.TRANSLUCENT,DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createWritableRaster(sampleModle,dataBuffer,new Point(0,0));
BufferedImage image = new BufferedImage(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()方法,我们来看下这个方法

public int getRGB(int pixel) {
if (numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (signed) {
throw new
IllegalArgumentException("Component value is signed");
}

return (getAlpha(pixel) << 24)
| (getRed(pixel) << 16)
| (getGreen(pixel) << 8)
| (getBlue(pixel) << 0);
}

 可以看出是通过三通道的分量的位运算获得最后的像素值,而IndexColorModel的getRGB()我们来看下

final public int getRGB(int pixel) {
        return rgb[pixel & pixel_mask];
    }

明显只有一个像素来计算最后的整数像素值。

总结

好了今天就简单介绍Java图像处理的基础操作,后续还将持续介绍一些实用的图像处理方法,下一篇将介绍Java中图像的放射变换,欢迎大家持续关注。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK