package org.hipi.opencv;
import org.hipi.image.PixelArray;
import org.hipi.image.RasterImage;
import org.hipi.util.ByteUtils;
import org.apache.hadoop.mapreduce.RecordReader;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
/**
* Various static helper methods which facilitate conversion between HIPI and OpenCV image
* representations.
*/
public class OpenCVUtils {
private static int[][] openCVTypeLUT = new int[][]
{{opencv_core.CV_8UC1, opencv_core.CV_8UC2, opencv_core.CV_8UC3, opencv_core.CV_8UC4},
{opencv_core.CV_16UC1, opencv_core.CV_16UC2, opencv_core.CV_16UC3, opencv_core.CV_16UC4},
{opencv_core.CV_16SC1, opencv_core.CV_16SC2, opencv_core.CV_16SC3, opencv_core.CV_16SC4},
{opencv_core.CV_32SC1, opencv_core.CV_32SC2, opencv_core.CV_32SC3, opencv_core.CV_32SC4},
{opencv_core.CV_32FC1, opencv_core.CV_32FC2, opencv_core.CV_32FC3, opencv_core.CV_32FC4},
{opencv_core.CV_64FC1, opencv_core.CV_64FC2, opencv_core.CV_64FC3, opencv_core.CV_64FC4}};
/**
* Returns the OpenCV data type which is associated with a particular {@link PixelArray} data type
* and number of bands.
*
* @return integer representation of OpenCV data type
*/
public static int generateOpenCVType(int pixelArrayDataType, int numBands) {
int depthIndex = -1;
switch(pixelArrayDataType) {
case PixelArray.TYPE_BYTE:
depthIndex = 0;
break;
case PixelArray.TYPE_USHORT:
depthIndex = 1;
break;
case PixelArray.TYPE_SHORT:
depthIndex = 2;
break;
case PixelArray.TYPE_INT:
depthIndex = 3;
break;
case PixelArray.TYPE_FLOAT:
depthIndex = 4;
break;
case PixelArray.TYPE_DOUBLE:
depthIndex = 5;
break;
default:
break;
}
int channelIndex = numBands - 1;
if(depthIndex < 0 || depthIndex >= openCVTypeLUT.length) {
return -1;
}
if(channelIndex < 0 || channelIndex >= openCVTypeLUT[0].length) {
return -1;
}
return openCVTypeLUT[depthIndex][channelIndex];
}
/**
* Converts an input {@link RasterImage} into an {@link Mat}.
*
* @return {@link Mat} of same data type and dimensions as input image
* @throws IllegalArgumentException
*/
public static Mat convertRasterImageToMat(RasterImage image) throws IllegalArgumentException {
// Check for invalid input
if(image == null) {
throw new IllegalArgumentException("Input RasterImage is null.");
}
if(image.getWidth() <= 0 || image.getHeight() <= 0) {
throw new IllegalArgumentException("Input RasterImage has invalid dimensions: "
+ "[" + image.getWidth() + "," + image.getHeight() + "]");
}
if(image.getNumBands() <= 0 || image.getNumBands() > 4) {
throw new IllegalArgumentException("Input RasterImage has invalid number of bandsY: "
+ "[" + image.getNumBands() + "]");
}
// Generate opencv data type based on input pixel array data type / number of bands
int pixelArrayDataType = image.getPixelArray().getDataType();
int numBands = image.getNumBands();
int openCVType = generateOpenCVType(pixelArrayDataType, numBands);
if(openCVType == -1) {
throw new IllegalArgumentException("Invalid PixelArray data type: "
+ "[" + pixelArrayDataType + "] and / or RasterImage numBands: [" + numBands + "]");
}
// Create output mat
Mat mat = new Mat(image.getHeight(), image.getWidth(), openCVType);
// Access raster image data
byte[] data = image.getPixelArray().getByteArray();
// Transfer data into mat
int depth = opencv_core.CV_MAT_DEPTH(mat.type());
switch(depth) {
case opencv_core.CV_8U:
case opencv_core.CV_8S:
((ByteBuffer)mat.createBuffer()).put(data);
break;
case opencv_core.CV_16U:
case opencv_core.CV_16S:
((ShortBuffer)mat.createBuffer()).put(ByteUtils.byteArrayToShortArray(data));
break;
case opencv_core.CV_32S:
((IntBuffer)mat.createBuffer()).put(ByteUtils.byteArrayToIntArray(data));
break;
case opencv_core.CV_32F:
((FloatBuffer)mat.createBuffer()).put(ByteUtils.byteArrayToFloatArray(data));
break;
case opencv_core.CV_64F:
((DoubleBuffer)mat.createBuffer()).put(ByteUtils.byteArrayToDoubleArray(data));
break;
default:
throw new IllegalArgumentException("Unsupported matrix depth [" + depth + "].");
}
return mat;
}
}