Skip to content
Snippets Groups Projects
Commit 91e4ce03 authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Clean and improve loader code.

Remove loadPlaneU16 from IPlaneLoader interface. At the same time add loadPlaneData method, which is more general.

Also we have implemented general loadVoxels in `BasicLoader` which uses the abstract loadPlaneData method.
parent bf5ca132
No related branches found
No related tags found
No related merge requests found
...@@ -2,6 +2,8 @@ package azgracompress.io.loader; ...@@ -2,6 +2,8 @@ package azgracompress.io.loader;
import azgracompress.data.V3i; import azgracompress.data.V3i;
import java.io.IOException;
public abstract class BasicLoader { public abstract class BasicLoader {
protected final V3i dims; protected final V3i dims;
...@@ -9,6 +11,15 @@ public abstract class BasicLoader { ...@@ -9,6 +11,15 @@ public abstract class BasicLoader {
this.dims = datasetDims; this.dims = datasetDims;
} }
/**
* Abstract method to load specified plane data.
*
* @param plane Zero based plane index.
* @return Plane data.
* @throws IOException when fails to load plane data for some reason.
*/
public abstract int[] loadPlaneData(final int plane) throws IOException;
/** /**
* Check whether the coordinates are inside voxel of dimension `dims`. * Check whether the coordinates are inside voxel of dimension `dims`.
* *
...@@ -63,4 +74,43 @@ public abstract class BasicLoader { ...@@ -63,4 +74,43 @@ public abstract class BasicLoader {
final int zChunkCount = (int) Math.ceil((double) datasetDims.getZ() / (double) voxelDims.getZ()); final int zChunkCount = (int) Math.ceil((double) datasetDims.getZ() / (double) voxelDims.getZ());
return (xChunkCount * yChunkCount * zChunkCount); return (xChunkCount * yChunkCount * zChunkCount);
} }
/**
* Load dataset into voxel data.
*
* @param voxelDim Single voxel dimensions.
* @return Voxel data arranged in arrays.
* @throws IOException When fails to load plane data.
*/
protected int[][] loadVoxelsImplGray16(final V3i voxelDim) throws IOException {
final int xVoxelCount = (int) Math.ceil((double) dims.getX() / (double) voxelDim.getX());
final int yVoxelCount = (int) Math.ceil((double) dims.getY() / (double) voxelDim.getY());
int[][] voxels = new int[calculateRequiredVoxelCount(dims, voxelDim)][(int) voxelDim.multiplyTogether()];
int dstZ, dstY, dstX, voxelX, voxelY, voxelZ, voxelIndex;
for (int srcZ = 0; srcZ < dims.getZ(); srcZ++) {
final int[] srcPlaneBuffer = loadPlaneData(srcZ);
dstZ = srcZ / voxelDim.getZ();
voxelZ = srcZ - (dstZ * voxelDim.getZ());
for (int srcY = 0; srcY < dims.getY(); srcY++) {
dstY = srcY / voxelDim.getY();
voxelY = srcY - (dstY * voxelDim.getY());
for (int srcX = 0; srcX < dims.getX(); srcX++) {
dstX = srcX / voxelDim.getX();
voxelX = srcX - (dstX * voxelDim.getX());
voxelIndex = (dstZ * (xVoxelCount * yVoxelCount)) + (dstY * xVoxelCount) + dstX;
voxels[voxelIndex][voxelDataIndex(voxelX, voxelY, voxelZ, voxelDim)] = srcPlaneBuffer[(srcY * dims.getX()) + srcX];
}
}
}
return voxels;
}
} }
package azgracompress.io.loader; package azgracompress.io.loader;
import azgracompress.data.ImageU16;
import azgracompress.data.V3i; import azgracompress.data.V3i;
import java.io.IOException; import java.io.IOException;
public interface IPlaneLoader { public interface IPlaneLoader {
ImageU16 loadPlaneU16(final int plane) throws IOException; int[] loadPlaneData(final int plane) throws IOException;
int[] loadPlanesU16Data(int[] planes) throws IOException; int[] loadPlanesU16Data(int[] planes) throws IOException;
int[] loadAllPlanesU16Data() throws IOException; int[] loadAllPlanesU16Data() throws IOException;
default int[][] loadVoxels(final V3i voxelDim) throws IOException { int[][] loadVoxels(final V3i voxelDim) throws IOException;
throw new IOException("NOT IMPLEMENTED");
}
} }
package azgracompress.io.loader; package azgracompress.io.loader;
import azgracompress.data.Chunk3D;
import azgracompress.data.ImageU16;
import azgracompress.data.V3i; import azgracompress.data.V3i;
import azgracompress.io.BufferInputData; import azgracompress.io.BufferInputData;
import azgracompress.io.InputData; import azgracompress.io.InputData;
import azgracompress.utilities.TypeConverter; import azgracompress.utilities.TypeConverter;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays; import java.util.Arrays;
public class ImageJBufferLoader implements IPlaneLoader { public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoader {
private final BufferInputData bufferInputData; private final BufferInputData bufferInputData;
public ImageJBufferLoader(BufferInputData bufferDataInfo) { public ImageJBufferLoader(BufferInputData bufferDataInfo) {
super(bufferDataInfo.getDimensions());
this.bufferInputData = bufferDataInfo; this.bufferInputData = bufferDataInfo;
// FIXME: Support more pixel types.
assert (this.bufferInputData.getPixelType() == InputData.PixelType.Gray16); assert (this.bufferInputData.getPixelType() == InputData.PixelType.Gray16);
} }
private int[] copyShortArray(short[] srcArray, int copyLen) {
int[] destArray = new int[copyLen];
for (int i = 0; i < copyLen; i++) {
destArray[i] = TypeConverter.shortToInt(srcArray[i]);
}
return destArray;
}
private void copyShortArrayIntoBuffer(short[] srcArray, int[] destBuffer, int destOffset, int copyLen) { private void copyShortArrayIntoBuffer(short[] srcArray, int[] destBuffer, int destOffset, int copyLen) {
for (int i = 0; i < copyLen; i++) { for (int i = 0; i < copyLen; i++) {
destBuffer[destOffset + i] = TypeConverter.shortToInt(srcArray[i]); destBuffer[destOffset + i] = TypeConverter.shortToInt(srcArray[i]);
...@@ -34,19 +25,9 @@ public class ImageJBufferLoader implements IPlaneLoader { ...@@ -34,19 +25,9 @@ public class ImageJBufferLoader implements IPlaneLoader {
} }
@Override @Override
public ImageU16 loadPlaneU16(int plane) throws IOException { public int[] loadPlaneData(final int plane) {
assert (plane >= 0);
switch (bufferInputData.getPixelType()) {
case Gray16: {
final int planePixelCount = bufferInputData.getDimensions().getX() * bufferInputData.getDimensions().getY();
final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(plane); final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(plane);
return new ImageU16(bufferInputData.getDimensions().getX(), return TypeConverter.shortArrayToIntArray(srcBuffer);
bufferInputData.getDimensions().getY(),
copyShortArray(srcBuffer, planePixelCount));
}
default:
throw new IOException("Unable to load unsupported pixel type.");
}
} }
@Override @Override
...@@ -54,13 +35,12 @@ public class ImageJBufferLoader implements IPlaneLoader { ...@@ -54,13 +35,12 @@ public class ImageJBufferLoader implements IPlaneLoader {
if (planes.length < 1) { if (planes.length < 1) {
return new int[0]; return new int[0];
} else if (planes.length == 1) { } else if (planes.length == 1) {
return loadPlaneU16(planes[0]).getData(); return loadPlaneData(planes[0]);
} else if (planes.length == bufferInputData.getDimensions().getZ()) { // Maybe? } else if (planes.length == bufferInputData.getDimensions().getZ()) { // Maybe?
return loadAllPlanesU16Data(); return loadAllPlanesU16Data();
} }
switch (bufferInputData.getPixelType()) { final int planePixelCount =
case Gray16: { bufferInputData.getDimensions().getX() * bufferInputData.getDimensions().getY();
final int planePixelCount = bufferInputData.getDimensions().getX() * bufferInputData.getDimensions().getY();
final long totalValueCount = (long) planePixelCount * (long) planes.length; final long totalValueCount = (long) planePixelCount * (long) planes.length;
if (totalValueCount > (long) Integer.MAX_VALUE) { if (totalValueCount > (long) Integer.MAX_VALUE) {
...@@ -78,15 +58,9 @@ public class ImageJBufferLoader implements IPlaneLoader { ...@@ -78,15 +58,9 @@ public class ImageJBufferLoader implements IPlaneLoader {
} }
return destBuffer; return destBuffer;
} }
default:
throw new IOException("Unable to load unsupported pixel type.");
}
}
@Override @Override
public int[] loadAllPlanesU16Data() throws IOException { public int[] loadAllPlanesU16Data() throws IOException {
switch (bufferInputData.getPixelType()) {
case Gray16: {
final V3i imageDims = bufferInputData.getDimensions(); final V3i imageDims = bufferInputData.getDimensions();
final long totalValueCount = imageDims.multiplyTogether(); final long totalValueCount = imageDims.multiplyTogether();
final int planePixelCount = imageDims.getX() * imageDims.getY(); final int planePixelCount = imageDims.getX() * imageDims.getY();
...@@ -104,145 +78,10 @@ public class ImageJBufferLoader implements IPlaneLoader { ...@@ -104,145 +78,10 @@ public class ImageJBufferLoader implements IPlaneLoader {
} }
return destBuffer; return destBuffer;
} }
default:
throw new IOException("Unable to load unsupported pixel type.");
}
}
@Override @Override
public int[][] loadVoxels(final V3i voxelDim) throws IOException { public int[][] loadVoxels(final V3i voxelDim) throws IOException {
assert (bufferInputData.getPixelType() == InputData.PixelType.Gray16); return loadVoxelsImplGray16(voxelDim);
final V3i dims = bufferInputData.getDimensions();
final int xVoxelCount = (int) Math.ceil((double) dims.getX() / (double) voxelDim.getX());
final int yVoxelCount = (int) Math.ceil((double) dims.getY() / (double) voxelDim.getY());
final int voxelSize = (int) voxelDim.multiplyTogether();
final int voxelCount = Chunk3D.calculateRequiredChunkCount(bufferInputData.getDimensions(), voxelDim);
int[][] voxels = new int[voxelCount][voxelSize];
int dstZ, dstY, dstX;
// THIS IS WRONG
// FIXME
for (int srcZ = 0; srcZ < dims.getZ(); srcZ++) {
final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(srcZ);
dstZ = srcZ / voxelDim.getZ();
for (int srcY = 0; srcY < dims.getY(); srcY++) {
dstY = srcY / voxelDim.getY();
for (int srcX = 0; srcX < dims.getX(); srcX++) {
dstX = srcX / voxelDim.getX();
final int voxelIndex = (dstZ * (xVoxelCount * yVoxelCount)) + (dstY * xVoxelCount) + dstX;
final int indexInsideVoxel = ((srcZ % voxelDim.getZ()) * (voxelDim.getX() * voxelDim.getY())) +
((srcY % voxelDim.getY()) * voxelDim.getX()) +
(srcX % voxelDim.getX());
voxels[voxelIndex][indexInsideVoxel] = srcBuffer[(srcY * bufferInputData.getDimensions().getX()) + srcX];
// System.out.printf("SRC: [%d;%d;%d] -> %d_[%d]\n", srcX, srcY, srcZ, voxelIndex, indexInsideVoxel);
}
}
}8
return voxels;
}
/**
* Copy this chunk data to chunk vector.
*
* @param vector Chunk vector.
* @param qVectorDims Dimensions of the vector.
* @param chunkXOffset Chunk X offset
* @param chunkYOffset Chunk Y offset.
* @param chunkZOffset Chunk Z offset.
*/
private void copyDataToVector(int[] vector,
final V3i qVectorDims,
final int chunkXOffset,
final int chunkYOffset,
final int chunkZOffset) {
int srcZ;
for (int z = 0; z < qVectorDims.getZ(); z++) {
srcZ = chunkZOffset + z;
fillVoxelFromPlane(vector, qVectorDims, srcZ, z, chunkXOffset, chunkYOffset);
}
}
private void fillVoxelFromPlane(int[] vector,
final V3i qVectorDims,
final int srcZ,
final int z,
final int chunkXOffset,
final int chunkYOffset) {
if (srcZ >= bufferInputData.getDimensions().getZ())
return;
final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(srcZ);
final int width = bufferInputData.getDimensions().getX();
int srcX, srcY;
for (int y = 0; y < qVectorDims.getY(); y++) {
srcY = chunkYOffset + y;
for (int x = 0; x < qVectorDims.getX(); x++) {
srcX = chunkXOffset + x;
final int dstIndex = index(x, y, z, qVectorDims);
vector[dstIndex] = isInside(srcX, srcY, srcZ) ? srcBuffer[(srcY * width) + srcX] : 0;
}
}
}
private boolean isInside(final int x, final int y, final int z) {
return (((x >= 0) && (x < bufferInputData.getDimensions().getX())) && (y >= 0) &&
(y < bufferInputData.getDimensions().getY()) && (z >= 0) &&
(z < bufferInputData.getDimensions().getZ()));
}
/**
* Calculate the index inside data array.
*
* @param x Zero based x coordinate.
* @param y Zero based y coordinate.
* @param z Zero based z coordinate.
* @return Index inside data array.
*/
private int index(final int x, final int y, final int z) {
return index(x, y, z, bufferInputData.getDimensions());
}
/**
* Calculate the index inside array of dimensions specified by chunkDims.
*
* @param x Zero based x coordinate.
* @param y Zero based y coordinate.
* @param z Zero based z coordinate.
* @param chunkDims Chunk dimensions.
* @return Index inside chunk dimension data array.
*/
private int index(final int x, final int y, final int z, final V3i chunkDims) {
assert (x >= 0 && x < chunkDims.getX()) : "Index X out of bounds.";
assert (y >= 0 && y < chunkDims.getY()) : "Index Y out of bounds.";
assert (z >= 0 && z < chunkDims.getZ()) : "Index Z out of bounds.";
// NOTE(Moravec): Description of the following calculation
// plane index * plane pixel count
// | |
// V V
// planeOffset = chunkDims.getZ() * (chunkDims.getX() * chunkDims.getY())
// row * pixels in row
// | |
// V V
// rowOffset = y * chunkDims.getX();
// column
// |
// V
// colOffset = x;
return (z * (chunkDims.getX() * chunkDims.getY())) + (y * chunkDims.getX()) + x;
} }
} }
package azgracompress.io.loader; package azgracompress.io.loader;
import azgracompress.data.ImageU16;
import azgracompress.data.V3i; import azgracompress.data.V3i;
import azgracompress.io.FileInputData; import azgracompress.io.FileInputData;
import azgracompress.utilities.TypeConverter; import azgracompress.utilities.TypeConverter;
...@@ -11,24 +10,23 @@ import java.io.FileInputStream; ...@@ -11,24 +10,23 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
public class RawDataLoader implements IPlaneLoader { public final class RawDataLoader extends BasicLoader implements IPlaneLoader {
private final FileInputData inputDataInfo; private final FileInputData inputDataInfo;
public RawDataLoader(final FileInputData inputDataInfo) { public RawDataLoader(final FileInputData inputDataInfo) {
super(inputDataInfo.getDimensions());
this.inputDataInfo = inputDataInfo; this.inputDataInfo = inputDataInfo;
} }
@Override @Override
public ImageU16 loadPlaneU16(int plane) throws IOException { public int[] loadPlaneData(final int plane) throws IOException {
byte[] buffer; byte[] buffer;
final V3i rawDataDimension = inputDataInfo.getDimensions();
try (FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath())) { try (FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath())) {
final long planeSize = (long) rawDataDimension.getX() * (long) rawDataDimension.getY() * 2; final long planeSize = (long) dims.getX() * (long) dims.getY() * 2;
final long expectedFileSize = planeSize * rawDataDimension.getZ(); final long expectedFileSize = planeSize * dims.getZ();
final long fileSize = fileStream.getChannel().size(); final long fileSize = fileStream.getChannel().size();
if (expectedFileSize != fileSize) { if (expectedFileSize != fileSize) {
throw new IOException( throw new IOException(
"File specified by `rawFile` doesn't contains raw data for image of dimensions " + "File specified by `rawFile` doesn't contains raw data for image of dimensions " +
...@@ -45,10 +43,7 @@ public class RawDataLoader implements IPlaneLoader { ...@@ -45,10 +43,7 @@ public class RawDataLoader implements IPlaneLoader {
throw new IOException("Read wrong number of bytes."); throw new IOException("Read wrong number of bytes.");
} }
} }
return TypeConverter.unsignedShortBytesToIntArray(buffer);
return new ImageU16(rawDataDimension.getX(),
rawDataDimension.getY(),
TypeConverter.unsignedShortBytesToIntArray(buffer));
} }
@Override @Override
...@@ -56,7 +51,7 @@ public class RawDataLoader implements IPlaneLoader { ...@@ -56,7 +51,7 @@ public class RawDataLoader implements IPlaneLoader {
if (planes.length < 1) { if (planes.length < 1) {
return new int[0]; return new int[0];
} else if (planes.length == 1) { } else if (planes.length == 1) {
return loadPlaneU16(planes[0]).getData(); return loadPlaneData(planes[0]);
} }
final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY(); final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY();
...@@ -119,4 +114,9 @@ public class RawDataLoader implements IPlaneLoader { ...@@ -119,4 +114,9 @@ public class RawDataLoader implements IPlaneLoader {
return values; return values;
} }
@Override
public int[][] loadVoxels(V3i voxelDim) throws IOException {
return loadVoxelsImplGray16(voxelDim);
}
} }
package azgracompress.io.loader; package azgracompress.io.loader;
import azgracompress.ScifioWrapper; import azgracompress.ScifioWrapper;
import azgracompress.data.ImageU16;
import azgracompress.data.V3i; import azgracompress.data.V3i;
import azgracompress.io.FileInputData; import azgracompress.io.FileInputData;
import azgracompress.utilities.TypeConverter; import azgracompress.utilities.TypeConverter;
...@@ -11,7 +10,7 @@ import io.scif.Reader; ...@@ -11,7 +10,7 @@ import io.scif.Reader;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
public class SCIFIOLoader implements IPlaneLoader { public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
private final FileInputData inputDataInfo; private final FileInputData inputDataInfo;
private final Reader reader; private final Reader reader;
...@@ -24,29 +23,28 @@ public class SCIFIOLoader implements IPlaneLoader { ...@@ -24,29 +23,28 @@ public class SCIFIOLoader implements IPlaneLoader {
* @throws FormatException When fails to create SCIFIO reader. * @throws FormatException When fails to create SCIFIO reader.
*/ */
public SCIFIOLoader(final FileInputData inputDataInfo) throws IOException, FormatException { public SCIFIOLoader(final FileInputData inputDataInfo) throws IOException, FormatException {
super(inputDataInfo.getDimensions());
this.inputDataInfo = inputDataInfo; this.inputDataInfo = inputDataInfo;
this.reader = ScifioWrapper.getReader(this.inputDataInfo.getFilePath()); this.reader = ScifioWrapper.getReader(this.inputDataInfo.getFilePath());
} }
@Override @Override
public ImageU16 loadPlaneU16(int plane) throws IOException { public int[] loadPlaneData(final int plane) throws IOException {
byte[] planeBytes; byte[] planeBytes;
try { try {
planeBytes = reader.openPlane(0, plane).getBytes(); planeBytes = reader.openPlane(0, plane).getBytes();
} catch (FormatException e) { } catch (FormatException e) {
throw new IOException("Unable to open plane with the reader. " + e.getMessage()); throw new IOException("Unable to open plane with the reader. " + e.getMessage());
} }
final int[] data = TypeConverter.unsignedShortBytesToIntArray(planeBytes); return TypeConverter.unsignedShortBytesToIntArray(planeBytes);
return new ImageU16(inputDataInfo.getDimensions().toV2i(), data);
} }
@SuppressWarnings("DuplicatedCode")
@Override @Override
public int[] loadPlanesU16Data(int[] planes) throws IOException { public int[] loadPlanesU16Data(int[] planes) throws IOException {
if (planes.length < 1) { if (planes.length < 1) {
return new int[0]; return new int[0];
} else if (planes.length == 1) { } else if (planes.length == 1) {
return loadPlaneU16(planes[0]).getData(); return loadPlaneData(planes[0]);
} }
final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY(); final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY();
...@@ -105,4 +103,11 @@ public class SCIFIOLoader implements IPlaneLoader { ...@@ -105,4 +103,11 @@ public class SCIFIOLoader implements IPlaneLoader {
return values; return values;
} }
@Override
public int[][] loadVoxels(final V3i voxelDim) throws IOException {
return loadVoxelsImplGray16(voxelDim);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment