org.integratedmodelling.utils.image.processing.ImageData Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (C) 2007, 2014:
*
* - Ferdinando Villa
* - integratedmodelling.org
* - any other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite,
* meant to enable modular, collaborative, integrated
* development of interoperable data and model components. For
* details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Affero General Public License
* Version 3 or any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* The license is also available at: https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.utils.image.processing;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.MemoryImageSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
/**
* ImageData contains either true color rgb(8x8x8) data or 8-bit gray-level data
* @author Di Zhong (Columbia University)
*/
public class ImageData extends Object implements Cloneable {
private static byte[] grayPallete = null;
private ColorModel clrmdl; // support two models: Direct(32) and Index(8)
/**
* pixel array used for color image
*/
protected int[] ipels = null;
/**
* pixel array used for gray-level image
*/
protected byte[] bpels = null;
/**
* number of rows (height)
*/
protected int irow;
/**
* number of columns (width)
*/
protected int icol;
static {
grayPallete = new byte[256];
for (int i = 0; i < 256; i++)
grayPallete[i] = (byte) i;
}
/**
* Create ImageData from an integer array using DirectColor model
* @param pmap The integer array
* @param r height (or row)
* @param c width (or column)
*/
public ImageData(int[] pmap, int r, int c) {
ipels = pmap;
irow = r;
icol = c;
clrmdl = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
}
/**
* Create ImageData from a byte array using IndexColor(8) model
* @param pmap The integer array
* @param r height (or row)
* @param c width (or column)
*/
public ImageData(byte[] pmap, int r, int c) {
bpels = pmap;
irow = r;
icol = c;
clrmdl = new IndexColorModel(8, 256, grayPallete, grayPallete, grayPallete);
}
/**
* Load ImageData from a local file or URL;
* Input formats: GIF, JPEG, PPM, PGM; Output formats: PPM, PGM
* @param filename The local file name or URL of an image
*/
public ImageData(String filename) throws IOException {
InputStream inchar;
URL url = null;
boolean isurl = false;
Dimension wh = new Dimension();
int t;
File f = new File(filename);
if (f.exists()) {
inchar = new FileInputStream(f);
t = ImageIO.getImageType(inchar);
inchar.close();
} else {
try {
url = new URL(filename);
inchar = url.openStream();
t = ImageIO.getImageType(inchar);
inchar.close();
isurl = true;
} catch (MalformedURLException e) {
throw new IOException("Cann't locate the image file!");
}
}
switch (t) {
case ImageIO.JPG_IMG:
case ImageIO.GIF_IMG:
if (isurl)
ipels = ImageIO.readGIF_JPG(url, wh);
else
ipels = ImageIO.readGIF_JPG(filename, wh);
irow = wh.height;
icol = wh.width;
clrmdl = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
break;
case ImageIO.PPM_IMG:
inchar = new FileInputStream(f);
ipels = ImageIO.readPPM(inchar, wh);
inchar.close();
irow = wh.height;
icol = wh.width;
clrmdl = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
break;
case ImageIO.PGM_IMG:
inchar = new FileInputStream(f);
bpels = ImageIO.readPGM(inchar, wh);
inchar.close();
irow = wh.height;
icol = wh.width;
clrmdl = new IndexColorModel(8, 256, grayPallete, grayPallete, grayPallete);
break;
}
}
/**
* Get java.awt.Image object
*/
public Image getImage() {
return getImage(1.0);
}
/**
* Get scaled java.awt.Image object
* @param s The scale factor
*/
public Image getImage(double s) {
Image img = null;
if (clrmdl.getPixelSize() == 32)
img = Toolkit.getDefaultToolkit()
.createImage(new MemoryImageSource(icol, irow, clrmdl, ipels, 0, icol));
else {
img = Toolkit.getDefaultToolkit()
.createImage(new MemoryImageSource(icol, irow, clrmdl, bpels, 0, icol));
}
if (s > 0 && s != 1.0) {
int detW = (int) (0.5 + s * icol);
int detH = (int) (0.5 + s * irow);
return img.getScaledInstance(detW, detH, Image.SCALE_FAST);
/*
ImageFilter filter=new ReplicateScaleFilter(detW, detH) ;
ImageProducer producer=new FilteredImageSource(img.getSource(),filter);
return Toolkit.getDefaultToolkit().createImage(producer) ;
*/
} else
return img;
}
/**
* Scale the image
* @param s the scale (should be >0)
*/
public void scale(double s) {
if (s <= 0)
return;
Image img = getImage(s);
Dimension wh = new Dimension();
try {
ipels = ImageIO.readImage(img, wh);
} catch (IOException e) {
System.err.println("Scaling error: " + e.getMessage());
}
irow = wh.height;
icol = wh.width;
clrmdl = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
}
/**
* Save ImageData into a PPM file if it is a true color image
* @param fname The file name
*/
public void savePPM(String fname) throws IOException {
if (clrmdl.getPixelSize() == 32) {
FileOutputStream out = new FileOutputStream(fname);
ImageIO.savePPM(out, ipels, icol, irow);
out.close();
}
}
/**
* Save ImageData into a PGM file (convert to intensity for color image)
* @param fname The file name
*/
public void savePGM(String fname) throws IOException {
FileOutputStream out = new FileOutputStream(fname);
if (clrmdl.getPixelSize() == 32) {
byte[] imap = new byte[irow * icol];
for (int i = 0, ii = 0; i < irow; i++)
for (int j = 0; j < icol; j++, ii++)
imap[ii] = (byte) ((((ipels[ii] & 0xff0000) >> 16) * 222 + ((ipels[ii] & 0x00ff00) >> 8)
* 707 + ((ipels[ii] & 0xff)) * 71)
/ (float) 1000.0 + 0.5);
ImageIO.savePGM(out, imap, icol, irow);
} else {
ImageIO.savePGM(out, bpels, icol, irow);
}
out.close();
}
/**
* Get number of rows (width)
*/
public final int row() {
return irow;
}
/**
* Get number of columns (height)
*/
public final int col() {
return icol;
}
/**
* Get number of pixels (row*column)
*/
public final int size() {
return irow * icol;
}
/**
* Return true if it is a color image
*/
public final boolean isColor() {
return clrmdl.getPixelSize() == 32;
}
/**
* Get pixel value, make sure coords are valid and this is a color image
* @param x x-coordinate
* @param y y-coordinate
*/
public final int pc(int x, int y) {
return ipels[y * icol + x];
}
/**
* Get pixel value, make sure index is valid and this is a color image
* @param i scanline index
*/
public final int pc(int i) {
return ipels[i];
}
/**
* Set pixel value, make sure index is valid and this is a color image
* @param i scanline index
* @param v pixel value
*/
public final void spc(int i, int v) {
ipels[i] = v;
}
/**
* Set pixel value, make sure coords are valid and this is a color image
* @param x x-coordinate
* @param y y-coordinate
* @param v pixel value
*/
public final void spc(int x, int y, int v) {
ipels[y * icol + x] = v;
}
/**
* Get pixel value, make sure index is valid and it is a gray-level image
* @param i scanline index
*/
public final byte pg(int i) {
return bpels[i];
}
/**
* Get pixel value, make sure coords are valid and it is a gray-level image
* @param x x-coordinate
* @param y y-coordinate
*/
public final byte pg(int x, int y) {
return bpels[y * icol + x];
}
/**
* Set pixel value, make sure index is valid and this is a gray-level image
* @param i scanline index
* @param v pixel value
*/
public final void spg(int i, byte v) {
bpels[i] = v;
}
/**
* Set pixel value, make sure coords are valid and this is a gray-level image
* @param x x-coordinate
* @param y y-coordinate
* @param v pixel value
*/
public final void spg(int x, int y, byte v) {
bpels[y * icol + x] = v;
}
/**
* Convert to gray level image, return intensity map in 2-D float array
*/
public float[][] getIntensityMap() {
float[][] imap = new float[irow][icol];
if (isColor()) {
for (int i = 0, ii = 0; i < irow; i++)
for (int j = 0; j < icol; j++, ii++)
imap[i][j] = (((ipels[ii] & 0xff0000) >> 16) * 222
+ ((ipels[ii] & 0x00ff00) >> 8) * 707 + ((ipels[ii] & 0xff)) * 71)
/ (float) 1000.0;
} else {
for (int i = 0, ii = 0; i < irow; i++)
for (int j = 0; j < icol; j++, ii++)
imap[i][j] = (bpels[ii]);
}
return imap;
}
/**
* Convert to gray level image, return intensity map in 2-D float array
* @param bbox bounding box
*/
public float[][] getIntensityMap(Rectangle bbox) {
float[][] imap = new float[bbox.height][bbox.width];
if (isColor()) {
for (int i = 0, ii = bbox.y * icol; i < bbox.height; i++, ii += icol)
for (int j = 0; j < bbox.width; j++) {
int tmp = ii + j + bbox.x;
imap[i][j] = (((ipels[tmp] & 0xff0000) >> 16) * 222
+ ((ipels[tmp] & 0x00ff00) >> 8) * 707 + ((ipels[tmp] & 0xff)) * 71)
/ (float) 1000.0;
}
} else {
for (int i = 0, ii = bbox.y * icol; i < bbox.height; i++, ii += icol)
for (int j = 0; j < bbox.width; j++) {
imap[i][j] = (bpels[ii + j + bbox.x]);
}
}
return imap;
}
/**
* Convert to Luv iamge, return in 3-D float array
* @param bbox bounding box (null for whole frame)
*/
public float[][][] getLuvImage(Rectangle bbox) {
if (bbox == null)
bbox = new Rectangle(0, 0, icol, irow);
float[][][] imap = new float[bbox.height][bbox.width][3];
if (isColor()) {
for (int i = 0, ii = bbox.y * icol; i < bbox.height; i++, ii += icol)
for (int j = 0; j < bbox.width; j++) {
int tmp = ii + j + bbox.x;
ImageProc.rgb2luv(((ipels[tmp] & 0xff0000) >> 16), ((ipels[tmp]
& 0x00ff00) >> 8), ((ipels[tmp] & 0xff)), imap[i][j]);
}
} else {
for (int i = 0, ii = bbox.y * icol; i < bbox.height; i++, ii += icol)
for (int j = 0; j < bbox.width; j++) {
int tmp = ii + j + bbox.x;
ImageProc.rgb2luv((bpels[tmp]), (bpels[tmp]), (bpels[tmp]), imap[i][j]);
}
}
return imap;
}
/**
* Draws a line of given gray-level color from (x0,y0) to (x1,y1);
* implements the Bresenham's incremental midpoint algorithm;
* (adapted from J D Foley, A Van Dam, S K Feiner, J F Hughes
* "Computer Graphics Principles and practice", * 2nd ed, 1990);
* @param x0 x-coordinate of endpoint 1
* @param y0 y-coordinate of endpoint 1
* @param x1 x-coordinate of endpoint 2
* @param y1 y-coordinate of endpoint 2
* @param color gray-level; R,G and B are all set to "color" for color images
*/
public void drawline(int x0, int y0, int x1, int y1, byte color) {
int xmin, xmax; /* line coordinates */
int ymin, ymax;
int dir; /* scan direction */
int dx; /* distance along X */
int dy; /* distance along Y */
/* increments: East, North-East, South, South-East, North */
int incrE, incrNE, incrS, incrSE, incrN;
int d; /* the D */
int x, y; /* running coordinates */
int mpCase; /* midpoint algorithm's case */
int done; /* set to 1 when done */
xmin = x0;
xmax = x1;
ymin = y0;
ymax = y1;
dx = xmax - xmin;
dy = ymax - ymin;
if (dx * dx > dy * dy) /* horizontal scan */ {
dir = 0;
if (xmax < xmin) {
{
xmin ^= xmax;
xmax ^= xmin;
xmin ^= xmax;
} // Swap
{
ymin ^= ymax;
ymax ^= ymin;
ymin ^= ymax;
} // Swap
}
dx = xmax - xmin;
dy = ymax - ymin;
if (dy >= 0) {
mpCase = 1;
d = 2 * dy - dx;
} else {
mpCase = 2;
d = 2 * dy + dx;
}
incrNE = 2 * (dy - dx);
incrE = 2 * dy;
incrSE = 2 * (dy + dx);
} else {/* vertical scan */
dir = 1;
if (ymax < ymin) {
{
xmin ^= xmax;
xmax ^= xmin;
xmin ^= xmax;
} // Swap
{
ymin ^= ymax;
ymax ^= ymin;
ymin ^= ymax;
} // Swap
}
dx = xmax - xmin;
dy = ymax - ymin;
if (dx >= 0) {
mpCase = 1;
d = 2 * dx - dy;
} else {
mpCase = 2;
d = 2 * dx + dy;
}
incrNE = 2 * (dx - dy);
incrE = 2 * dx;
incrSE = 2 * (dx + dy);
}
/* start the scan */
x = xmin;
y = ymin;
done = 0;
int tclr = 0xff000000 | ((0xff & color) << 16) | ((0xff & color) << 8) | (0xff & color);
while (done == 0) {
if (x > 0 && x < icol && y > 0 && y < irow)
if (isColor())
ipels[y * icol + x] = tclr;
else
bpels[y * icol + x] = color;
/* move to the next point */
switch (dir) {
case 0: /* horizontal */
{
if (x < xmax) {
switch (mpCase) {
case 1:
if (d <= 0) {
d += incrE;
x++;
} else {
d += incrNE;
x++;
y++;
}
break;
case 2:
if (d <= 0) {
d += incrSE;
x++;
y--;
} else {
d += incrE;
x++;
}
break;
} /* mpCase */
} /* x