Commit 30fc2ba2 authored by hvernier's avatar hvernier

remove bioformat and replace with gdal

parent 67008235
package multiCube.tools.image;
import java.util.Hashtable;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.Driver;
import org.gdal.gdal.gdal;
......@@ -84,7 +86,10 @@ public class InfoImage {
* Sensor id
*/
private String sensorId;
/**
* MetaData
*/
private Hashtable metaData;
/**
* Image id
*/
......@@ -131,7 +136,8 @@ public class InfoImage {
this.sizeX = hDataset.getRasterXSize();
this.sizeY = hDataset.getRasterYSize();
this.numberOfBands = hDataset.getRasterCount();
this.metaData = hDataset.GetMetadata_Dict();
hDataset.GetGCPs();
/* Report Projection */
this.projectionName = hDataset.GetProjectionRef();
SpatialReference hSRS = new SpatialReference(this.projectionName);
......@@ -332,6 +338,18 @@ public class InfoImage {
return driverName;
}
public double[] getGeoTransforme() {
return adfGeoTransform;
}
public String getProjection() {
return projectionName;
}
public Hashtable getMetaData() {
return metaData;
}
public static double[] getGetGeoTransformeValue(double[] adfGeoTransform, double x, double y) {
double dfGeoX, dfGeoY;
double[] result = new double[2];
......
package multiCube.tools.image.reader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Arrays;
import loci.formats.FormatException;
import loci.formats.FormatTools;
import loci.formats.ImageReader;
/**
* <p>
* Wrapper au dessus des fonctions de lecture d'image de la libraire
* bio-formats qui permet de lire les images par tuile.
* <p>
*
* @author Baptiste LAFABREGUE
*
*/
public class ImageReaderWrapper {
ImageReader reader = null;
int currentImageIndex = 0;
public ImageReaderWrapper() {
reader = new ImageReader();
}
/**
* <p>
* Definit l'image a utiliser
* <p>
*
* @param path
* le chemin d'acces de l'image
*
* @throws FormatException
* @throws IOException
*/
public void setImage(String path) throws FormatException, IOException {
reader.setId(path);
}
/**
* <p>
* Renvoi un tableau de byte qui contient pour chaque coordonnee contient sa
* valeur sous la forme d'un tableau de byte pour une vue donnee de l'image.
* Format : byte[x][y][pixels]
*
* A noter que si les pixels font n bytes, les n premiers bytes seront pour la bande 1,
* les n suivant pour la bande 2, ect ..
* <p>
*
* @param x
* l'absisse du coin haut-gauche de la vue
* @param y
* l'ordonnee du coin haut-gauche de la vue
* @param w
* la largeur de la vue
* @param h
* la hauteur de la vue
* @return le tableau de byte contenant les valeus de la vue
*
* @throws IOException
* si il y a eu un probleme en lisant le fichier
* @throws FormatException
* si il y a eu un probleme en parsant les metadata du fichier
*/
public byte[][][] getPixels(int x, int y, int w, int h) throws FormatException, IOException {
byte[] rawData = reader.openBytes(currentImageIndex, x, y, w, h);
int channelCount = reader.getRGBChannelCount();
int pixelSize = reader.getBitsPerPixel()/8;
// test si on a bien le nombre attendu de pixels
if(rawData.length != w * h * channelCount * pixelSize) {
throw new IndexOutOfBoundsException("La taille du tableau de byte renvoye n'est pas celle attendue.");
}
int channelGap = rawData.length / channelCount;
byte[][][] result = new byte[w][h][channelCount*pixelSize];
int index = 0;
for(int j = 0 ; j < h ; j++) {
for(int i = 0 ; i < w ; i++) {
for(int c = 0 ; c < channelCount ; c++) {
for(int p = 0 ; p < pixelSize ; p++) {
result[i][j][c*pixelSize+p] = rawData[index+channelGap*c+p];
}
}
index++;
}
}
return result;
}
/**
* <p>
* Renvoi un tableau de byte qui contient pour chaque coordonnee sa
* valeur sous la forme d'un byte pour une vue donnee de l'image.
* L'image ne doit avoir qu'une seul bande avec un byte par pixel.
* Format : byte[x][y]
*
* <p>
*
* @param x
* l'absisse du coin haut-gauche de la vue
* @param y
* l'ordonnee du coin haut-gauche de la vue
* @param w
* la largeur de la vue
* @param h
* la hauteur de la vue
* @return le tableau de byte contenant les valeus de la vue
*
* @throws IOException
* si il y a eu un probleme en lisant le fichier
* @throws FormatException
* si il y a eu un probleme en parsant les metadata du fichier ou si
* l'image ne verifie pas les conditions d'une bande a 1 byte pixels
*/
public byte[][] get1BytePixels(int x, int y, int w, int h) throws FormatException, IOException {
int pixelSize = reader.getBitsPerPixel()/8;
int channelCount = reader.getRGBChannelCount();
if (pixelSize != 1 || channelCount != 1) {
throw new FormatException("The function get1BitPixels can only be called on images with "+
"only one chanel of one byte pixels.");
}
// test si on a bien qu'un seul byte par pixel et une seule bande sinon l'algorithme
byte[] rawData = reader.openBytes(currentImageIndex, x, y, w, h);
// test si on a bien le nombre attendu de pixels
if(rawData.length != w * h * channelCount * pixelSize) {
throw new IndexOutOfBoundsException("La taille du tableau de byte renvoye n'est pas celle attendue.");
}
byte[][] result = new byte[w][h];
int index = 0;
for(int j = 0 ; j < h ; j++) {
for(int i = 0 ; i < w ; i++) {
result[i][j] = rawData[index];
index++;
}
}
return result;
}
/**
* <p>
* Renvoi le nombre de bytes composant la valeur
* <p>
*
* @return le nombre de butes par pixel
*/
public int getBytesPerPixel() {
return reader.getBitsPerPixel()/8;
}
/**
* <p>
* Renvoi l'index d'image actuellement utilise
* <p>
*
* @return l'index d'image utilise
*/
public int getCurrentImageIndex() {
return currentImageIndex;
}
/**
* <p>
* Modifie l'image qui sera utilise pour les prochaines operations
* <p>
*
* @param currentImageIndex
* l'index de l'image a utiliser
*/
public void setCurrentImageIndex(int currentImageIndex) {
if (reader.getImageCount() < currentImageIndex) {
throw new IndexOutOfBoundsException("There are just " + reader.getImageCount() +
" images in the file " + reader.getCurrentFile());
}
this.currentImageIndex = currentImageIndex;
}
/**
* <p>
* Renvoi le nombre de pixel en largeur de l'image
* <p>
*
* @return la largeur de l'image
*/
public int getImageWidth() {
return reader.getSizeX();
}
/**
* <p>
* Renvoi le nombre de pixel en hauteur de l'image
* <p>
*
* @return la hauteur de l'image
*/
public int getImageHeight() {
return reader.getSizeY();
}
/**
* <p>
* Renvoi le nombre de bande de l'image
* <p>
*
* @return le nombre de bande
*/
public int getChannelCount() {
return reader.getRGBChannelCount();
}
/**
* <p>
* Renvoi le type de pixel de l'image
* INT8 = 0;
* UINT8 = 1;
* INT16 = 2;
* UINT16 = 3;
* INT32 = 4;
* UINT32 = 5;
* FLOAT = 6;
* DOUBLE = 7;
* BIT = 8;
* <p>
*
* @return le type de pixel
*/
public int getPixelType() {
return reader.getPixelType();
}
/**
* <p>
* Renvoi la valeur entiere d'un pixel. Cette fonction utilise les n premiers
* byte du tableau pour lire l'entier, avec n le nombre de de byte par pixel de l'image
* <p>
*
* @param pixel
* le pixel sous forme de tableau de byte
* @return la valeur en int du pixel
* @throws IOException
* @throws FormatException
* si le format de pixel ne peut etre caste vers int (double, float)
*/
public int getPixelValue(byte[] pixel) throws IOException, FormatException {
int pixelType = reader.getPixelType();
switch(pixelType) {
case(FormatTools.BIT) :
return pixel[0];
case(FormatTools.INT8) :
return pixel[0];
case(FormatTools.UINT8) :
return pixel[0] & 0xFF;
case(FormatTools.INT16) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 1))).readInt();
case(FormatTools.UINT16) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 1))).readUnsignedByte();
case(FormatTools.INT32) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 3))).readInt();
case(FormatTools.UINT32) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 3))).readUnsignedByte();
default :
throw new FormatException("The pixel format cannot be cast to int without ");
}
}
/**
* <p>
* Renvoi la valeur entiere d'un pixel. Cette fonction utilise les n premiers
* byte du tableau pour lire l'entier, avec n le nombre de de byte par pixel de l'image
* <p>
*
* @param pixel
* le pixel sous forme de tableau de byte
* @param pixelType
* le type de format du pixel
* @return la valeur en int du pixel
* @throws IOException
* @throws FormatException
* si le format de pixel ne peut etre caste vers int (double, float)
*/
static public int getPixelValue(byte[] pixel, int pixelType) throws IOException, FormatException {
switch(pixelType) {
case(FormatTools.BIT) :
return pixel[0];
case(FormatTools.INT8) :
return pixel[0];
case(FormatTools.UINT8) :
return pixel[0] & 0xFF;
case(FormatTools.INT16) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 1))).readInt();
case(FormatTools.UINT16) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 1))).readUnsignedByte();
case(FormatTools.INT32) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 3))).readInt();
case(FormatTools.UINT32) :
return new DataInputStream(new ByteArrayInputStream(
Arrays.copyOfRange(pixel, 0, 3))).readUnsignedByte();
default :
throw new FormatException("The pixel format cannot be cast to int without ");
}
}
}
package multiCube.tools.image.reader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Iterator;
import loci.formats.FormatException;
import loci.formats.FormatTools;
import loci.formats.ImageReader;
import multiCube.tools.util.exceptions.MethodNotImplementedException;
/**
* <p>
* Wrapper above the image reading library bio-formats
* that allows to read images in a stream fashion
* <p>
*
* @author Baptiste Lafabregue
*
*/
public class StreamedImageReaderWrapper extends ReaderWrapper {
/** */
private static final long serialVersionUID = 1L;
ImageReader reader = null;
/** Buffer that contains the current view */
private byte[] tile = null;
/**
* <p>
* Constructor
* By default the tiling is the one recommended by the bio-format library
* <p>
*
* @param path
* The image file path
*/
public StreamedImageReaderWrapper(String path) {
this.reader = new ImageReader();
try {
setImage(path);
} catch (FormatException | IOException e) {
e.printStackTrace();
}
}
/**
* <p>
* Constructor by copy
* By default the tiling is the one recommended by the bio-format library
* so not the one of the copied wrapper.
* <p>
*
* @param path
* The image file path
*/
public StreamedImageReaderWrapper(StreamedImageReaderWrapper wrapper) {
this.reader = new ImageReader();
try {
setImage(wrapper.reader.getCurrentFile());
this.extrema = wrapper.extrema;
setMaxRAM(wrapper.maxRAM);
} catch (FormatException | IOException e) {
e.printStackTrace();
}
}
/**
* <p>
* Constructor
* <p>
*
* @param path
* The image file path
* @param ram
* The memory dedicated to this wrapper in byte
* @throws IOException
* If the provided memory is not big enough to read the image
*/
public StreamedImageReaderWrapper(String path, int ram) throws IOException {
this.reader = new ImageReader();
try {
setImage(path);
} catch (FormatException | IOException e) {
e.printStackTrace();
}
setMaxRAM(ram);
}
/**
* <p>
* Set the image to use by the wrapper
* and initialize all file related attributes
* <p>
*
* @param path
* The image file path
* @throws IOException
* If there is a problem reading the file
* @throws FormatException
* If there is a problem parsing the image's metadata
*/
private void setImage(String path) throws FormatException, IOException {
this.reader.setId(path);
this.tile = null;
this.optimaleTileHeight = reader.getOptimalTileHeight();
this.optimaleTileWidth = reader.getOptimalTileWidth();
this.tileHeight = this.optimaleTileHeight;
this.tileWidth = this.optimaleTileWidth;
this.imageHeight = reader.getSizeY();
this.endY = imageHeight;
this.imageWidth = reader.getSizeX();
this.channelCount = reader.getRGBChannelCount();
this.bytesPerPixel = reader.getBitsPerPixel()/8;
this.pixelType = reader.getPixelType();
this.isInterLeaved = reader.isInterleaved();
this.isLittleEndian = reader.isLittleEndian();
}
@Override
public double[] getPixel(int x, int y) throws FormatException, IOException {
double[] result = new double[channelCount];
if(!isInImage(x,y)) {
return result;
}
if (!isInTile(x, y)) {
loadTile(x, y);
}
int index = x - tileX + (y - tileY) * currentTileWidth;
index *= bytesPerPixel;
int gap = channelGap;
ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN;
if (!isLittleEndian) {
byteOrder = ByteOrder.BIG_ENDIAN;
}
if(isInterLeaved) {
index *= channelCount;
gap = bytesPerPixel;
}
for(int c = 0 ; c < channelCount ; c++) {
// try {
switch (pixelType) {
case FormatTools.BIT:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).get() & 0xFF;
break;
case FormatTools.INT8:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).get();
break;
case FormatTools.UINT8:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).get() & 0xFF;
break;
case FormatTools.INT16:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getShort();
break;
case FormatTools.UINT16:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getShort() & 0xFFFF;
break;
case FormatTools.INT32:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getInt();
break;
case FormatTools.UINT32:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getInt() & 0xFFFFFFFFL;
break;
case FormatTools.FLOAT:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getFloat();
break;
case FormatTools.DOUBLE:
result[c] = ByteBuffer.wrap(Arrays.copyOfRange(tile, index+gap*c,
index+gap*c+bytesPerPixel)).order(byteOrder).getDouble();
break;
default :
result[c] = 0;
}
// } catch (ArrayIndexOutOfBoundsException e) {
// e.printStackTrace();
// System.out.println("channel : "+c+" index : "+index+" gap : "+gap+" requested pixel : "+x+","+y+
// " tile : "+tileX+","+tileY+" - "+currentTileWidth+","+currentTileHeight);
// }
}
return result;
}
@Override
public void loadTile(int x, int y) throws FormatException, IOException {
tileX = x - x % tileWidth;
tileY = y - y % tileHeight;
if (tileY < startY) {
tileY = startY;
}
if (tileX < startX) {
tileX = startX;
}
currentTileHeight = tileHeight;
if (endY > 0) {
if (currentTileHeight+tileY > endY)
currentTileHeight = endY - tileY;
} else {
if (currentTileHeight+tileY > imageHeight)
currentTileHeight = imageHeight - tileY;
}
currentTileWidth = tileWidth;
if (endX > -1) {
if (currentTileWidth+tileX > endX)
currentTileWidth = endX - tileX;
} else {
if (currentTileWidth+tileX > imageWidth)
currentTileWidth = imageWidth - tileX;
}
tile = reader.openBytes(0, tileX, tileY, currentTileWidth, currentTileHeight);
channelGap = tile.length / channelCount;
System.out.println("Tile of "+currentTileWidth+"x"+currentTileHeight+" - "+tileX+","+tileY+" for image of "+imageWidth+"x"+imageHeight);
}
@Override
public int getBytesPerPixel() {
if (bytesPerPixel == 0) {
bytesPerPixel = reader.getBitsPerPixel()/8;
}
return bytesPerPixel;
}
@Override
protected double[][] getExtrema() {
if(extrema == null) {
Iterator<double[]> iter = iterator();
// init min and max
double[] pixel0 = iter.next();
extrema = new double[2][pixel0.length];
for(int i = 0 ; i < pixel0.length ; i++) {
extrema[0][i] += pixel0[i];
extrema[1][i] += pixel0[i];
}
// get through the image
while(iter.hasNext()) {
double[] pixel = iter.next();
for(int i = 0; i < pixel.length ; i++) {
if (pixel[i] < extrema[0][i])
extrema[0][i] = pixel[i];
if (pixel[i] > extrema[1][i])
extrema[1][i] = pixel[i];
}
}
}
return extrema;
}
@Override
public Object clone() {
return new StreamedImageReaderWrapper(this);
}
@Override
public void flushMemory() throws MethodNotImplementedException {
this.tile = null;
}
@Override
public Iterator<double[]> iterator() {
return new StreamedIterator(this);
}
public Iterator<double[]> iterator(int start, int end) {
return new StreamedIterator(this, start, end);
}
// public static void main(String[] args) {
//
// String path = "/home/baptiste/Data/malaoui/evi_2013_2014.tif";
// StreamedImageReaderWrapper reader = new StreamedImageReaderWrapper(path);
//
// long allocatedMemory = (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
// long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;
// // we just tack the 2/3rd of the memory available;
// presumableFreeMemory *= 0.05;
//
// long memoryPerReader = presumableFreeMemory ;
// try {
// reader.setMaxRAM(memoryPerReader);
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// long startT = System.nanoTime();
// System.out.println("start at "+startT);
// double[][] extrema = reader.getExtrema();
// long endT = System.nanoTime();
// System.out.println("endat "+ endT + " total of "+ (endT - startT)/1000000l +"ms");
// System.out.println("extrema : "+Arrays.deepToString(extrema));
// }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment