package org.hipi.tools.covar;
import org.hipi.image.FloatImage;
import org.hipi.image.HipiImageHeader;
import org.hipi.opencv.OpenCVMatWritable;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Mapper;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.Rect;
import org.bytedeco.javacpp.opencv_core.Scalar;
import java.io.IOException;
import java.net.URI;
import java.nio.FloatBuffer;
public class CovarianceMapper extends
Mapper<HipiImageHeader, FloatImage, IntWritable, OpenCVMatWritable> {
Mat mean; // Stores pre-computed mean
Mat gaussian; // Stores gaussian matrix computed in setup
@Override
public void setup(Context job) {
int N = Covariance.patchSize;
float sigma = Covariance.sigma;
/////
// Create mean mat using data from mean computation
/////
try {
// Access mean data on HDFS
String meanPathString = job.getConfiguration().get("hipi.covar.mean.path");
if(meanPathString == null) {
System.err.println("Mean path not set in configuration - cannot continue. Exiting.");
System.exit(1);
}
Path meanPath = new Path(meanPathString);
FSDataInputStream dis = FileSystem.get(job.getConfiguration()).open(meanPath);
// Populate mat with mean data
OpenCVMatWritable meanWritable = new OpenCVMatWritable();
meanWritable.readFields(dis);
mean = meanWritable.getMat();
} catch (IOException ioe) {
ioe.printStackTrace();
System.exit(1);
}
/////
// Create a normalized gaussian array for patch masking
/////
gaussian = new Mat(N, N, opencv_core.CV_32FC1, new Scalar(0.0));
FloatBuffer gaussianBuffer = gaussian.createBuffer();
// 'center' and 'denominator' precomputed for gaussian generation
int center = N / 2;
double denominator = 2 * sigma * sigma;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
gaussianBuffer.put(i * N + j, generate2DGaussianValue(i, j, center, denominator));
}
}
// compute euclidean distance of gaussian vector
double sumOfSquares = 0.0;
for(int i = 0; i < N * N; i++) {
sumOfSquares += gaussianBuffer.get(i) * gaussianBuffer.get(i);
}
double euclideanDistance = Math.sqrt(sumOfSquares);
if(euclideanDistance == 0) {
System.out.println("Invalid euclidean distance of gaussian vector [0]. Cannot continue.");
System.exit(1);
}
// normalize gaussian weighting matrix
gaussian = opencv_core.divide(gaussian, euclideanDistance).asMat();
}
// 2D Gaussian: f(i, j) = A * exp(-( (i - i0)^2 / (2 * iSigma^2) + (j - j0)^2 / (2 * jSigma^2) ))
// i0 == j0 == "center"
// iSigma == jSigma (sigma)
// A == 1
// i0 == j0 == "center"
// (2 * sigma^2) == "denominator"
private float generate2DGaussianValue(int i, int j, int center, double denominator) {
double termOne = ((double)((i - center) * (i - center))) / denominator;
double termTwo = ((double)((j - center) * (j - center))) / denominator;
return ((float)Math.exp(-(termOne + termTwo)));
}
@Override
public void map(HipiImageHeader header, FloatImage image, Context context) throws IOException,
InterruptedException {
/////
// Perform conversion to OpenCV
/////
Mat cvImage = new Mat(image.getHeight(), image.getWidth(), opencv_core.CV_32FC1);
// if unable to convert input FloatImage to grayscale Mat, skip image and move on
if(!Covariance.convertFloatImageToGrayscaleMat(image, cvImage)) {
System.out.println("CovarianceMapper is skipping image with invalid color space.");
return;
}
/////
// Create patches for covariance computation
/////
// Specify number of patches to use in covariance computation (iMax * jMax patches)
int iMax = 10;
int jMax = 10;
Mat[] patches = new Mat[iMax * jMax];
int N = Covariance.patchSize;
// Create mean-subtracted and gaussian-masked patches
for (int i = 0; i < iMax; i++) {
int x = (cvImage.cols() - N) * i / iMax;
for (int j = 0; j < jMax; j++) {
int y = (cvImage.rows() - N) * j / jMax;
Mat patch = cvImage.apply(new Rect(x, y, N, N)).clone();
opencv_core.subtract(patch, mean, patch);
opencv_core.multiply(patch, gaussian, patch);
patches[(iMax * i) + j] = patch;
}
}
/////
// Run covariance computation
/////
// Stores the (N^2 x N^2) covariance matrix patchMat*transpose(patchMat)
Mat covarianceMat = new Mat(N * N, N * N, opencv_core.CV_32FC1, new Scalar(0.0));
// Stores patches as column vectors
Mat patchMat = new Mat(N * N, patches.length, opencv_core.CV_32FC1, new Scalar(0.0));
// Create patchMat
for(int i = 0; i < patches.length; i++) {
patches[i].reshape(0, N * N).copyTo(patchMat.col(i));
}
// Compute patchMat*transpose(patchMat)
covarianceMat = opencv_core.multiply(patchMat, patchMat.t().asMat()).asMat();
context.write(new IntWritable(0), new OpenCVMatWritable(covarianceMat));
}
}