Read Image as Double Array
You might think "We can use Raster#getPixel method if we would like to grab pixels, can't we?".Yes that's true. The key problem is the low performance because getPixel method internally call SampleModel and convert raw value to proper pixel value every method call.
So we should call Raster#getPixels method and grab all pixels one method call.
I have done similar stuffs in C# and posted on this blog.
On the other hand in Java, this is a bit messy because there are a lot of related classes - Raster, ImageIO, Reader, Writer, etc ;).
The simplest way I did is:
- read image as BufferedImage by ImageIO
- call BufferedImage#getRaster method
- call Raster#getPixels method
Here is an exmple code.
public static TemporalImage readImagePixelDoubleArray(InputStream is, int bitPerPixel) throws IOException{ BufferedImage image = ImageIO.read(is); Raster raster = image.getRaster(); int x = raster.getMinX(); int y = raster.getMinY(); int w = raster.getWidth(); int h = raster.getHeight(); double[] pixels = raster.getPixels(x, y, w, h, (double[])null); double[][] result = to2DimArray(bitPerPixel, pixels); return new TemporalImage(w, h, result); } private static double[][] to2DimArray(int bitPerPixel, double[] pixels) { int len = pixels.length / bitPerPixel; double[][] result = new double[bitPerPixel][len]; for(int dextIndex = 0; dextIndex < len; dextIndex++){ int offset = dextIndex * bitPerPixel; for(int b = 0; b < bitPerPixel; b++){ result[b][dextIndex] = pixels[offset + b]; } } return result; }
The following code is the class just used for holding double array in above example.
// simple holds double array, width, height. public class TemporalImage { private final int w; private final int h; private final double[][] data; public TemporalImage(int w, int h, double[][] data) { this.w = w; this.h = h; this.data = data; } public int getWidth() { return w; } public int getHeight() { return h; } public double[][] getData() { return data; } }
Write Image from Double Array
Write image from double array is almost reverse of reading image as double array.private static BufferedImage createBufferedImage(TemporalImage source, int bitPerPixel, int imageType) { BufferedImage image = new BufferedImage(source.getWidth(), source.getHeight(), imageType); WritableRaster raster = image.getRaster(); double[] ret = to1DimDoubleArray(bitPerPixel, source.getData()); raster.setPixels(0, 0, source.getWidth(), source.getHeight(), ret); return image; } private static double[] to1DimDoubleArray(int bitPerPixel, double[][] source) { int len = source[0].length; double[] ret = new double[len * bitPerPixel]; for (int i = 0, offset = 0; i < len; i++, offset = i * bitPerPixel) { for (int j = 0; j < bitPerPixel; j++) { ret[offset + j] = source[j][i]; } } return ret; }
Using Raster
I have tried to read image as double array by directly using Raster class. Something like:ImageReader reader = getImageReaderBySuffix(suffix); ImageInputStream imageIn= ImageIO.createImageInputStream(is); reader.setInput(imageIn, false, false);
The motivation is reducing memory and increase performance. (I think the creating BufferedImage object is waste of memory because we only need double array which contains pixel data).
However if we read image directly from raster, we need to give a proper ColorModel when it is instantiated.
Unfortunately I have not figured out how to do yet...of course I can refer what ImageIO does in ImageIO.read method.
Anyway I will keep investigating it :D
コメント