Skip to content

Commit

Permalink
First cut of C interfaces.
Browse files Browse the repository at this point in the history
  • Loading branch information
etrain committed May 4, 2015
1 parent eaf9d82 commit 6a9cecc
Show file tree
Hide file tree
Showing 6 changed files with 647 additions and 0 deletions.
73 changes: 73 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

VLFEATDIR=$(TMPDIR)/vlfeat
ENCEVALDIR=$(TMPDIR)/enceval

VLFEATURL = "http://www.vlfeat.org/download/vlfeat-0.9.20-bin.tar.gz"
ENCEVALURL = "http://www.robots.ox.ac.uk/~vgg/software/enceval_toolkit/downloads/enceval-toolkit-1.1.tar.gz"

CC = g++
CFLAGS = -O2

#Auto-detect architecture
Darwin_x86_64_ARCH := maci64
Linux_x86_64_ARCH := glnxa64

UNAME := $(shell uname -sm)
VLARCH ?= $($(shell echo "$(UNAME)" | tr \ _)_ARCH)

VLFEATOBJ = $(VLFEATDIR)/vlfeat-0.9.20/bin/$(VLARCH)/objs

#Set dynamic lib extension for architecture
Darwin_x86_64_EXT := jnilib
Linux_x86_64_EXT := so

SOEXT ?= $($(shell echo "$(UNAME)" | tr \ _)_EXT)

#Set java extension for architecture
Darwin_x86_64_JAVA := darwin
Linux_x86_64_JAVA := linux

JAVAEXT ?= $($(shell echo "$(UNAME)" | tr \ _)_JAVA)

SRCDIR := src/main/cpp

ODIR = $(TMPDIR)/obj
LDIR = lib

_OBJ = siftExtractor.o fisherExtractor.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))

_EVDEPS = gmm.o fisher.o stat.o simd_math.o
EVDEPS = $(patsubst %,$(ENCEVALDIR)/%,$(_EVDEPS))

VLDEPS = $(shell find $(VLFEATOBJ) -type f -name '*.o')

all: $(LDIR)/libImageEncoders.$(SOEXT)

$(VLFEATDIR):
mkdir -p $(VLFEATDIR)
wget $(VLFEATURL) -O $(VLFEATDIR)/vlfeat.tgz
cd $(VLFEATDIR) && tar zxvf $(VLFEATDIR)/vlfeat.tgz

$(ENCEVALDIR):
mkdir -p $(ENCEVALDIR)
wget $(ENCEVALURL) -O $(ENCEVALDIR)/enceval.tgz
cd $(ENCEVALDIR) && tar zxvf enceval.tgz

vlfeat: $(VLFEATDIR)
make -C $(VLFEATDIR)/vlfeat-0.9.20 ARCH=$(VLARCH) bin-all

$(ENCEVALDIR)/%.o: $(ENCEVALDIR)/lib/gmm-fisher/%.cxx
$(CC) -c -o $@ $< $(CFLAGS)

$(ODIR)/%.o: $(SRCDIR)/%.cxx $(ENCEVALDIR) $(VLFEATDIR)
$(CC) -I$(ENCEVALDIR)/lib/gmm-fisher -I$(VLFEATDIR)/vlfeat-0.9.20 -I$(JAVA_HOME)/include/ -I$(JAVA_HOME)/include/$(JAVAEXT) -c -o $@ $< $(CFLAGS)

$(LDIR)/libImageEncoders.$(SOEXT): $(OBJ) $(EVDEPS) vlfeat
$(CC) -dynamiclib -o $@ $(OBJ) $(EVDEPS) $(VLDEPS) $(CFLAGS)

.PHONY: clean vlfeat

clean:
rm -f $(LDIR)/libImageEncoder.$(SOEXT)
rm -rf $(VLFEATDIR) $(ENCEVALDIR) $(ODIR)
Binary file added lib/libImageEncoders.jnilib
Binary file not shown.
217 changes: 217 additions & 0 deletions src/main/cpp/fisherExtractor.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/** @internal
** @file FisherExtractor.cxx
** @author Evan Sparks
** @brief JNI Wrapper for enceval GMM and Fisher Vector
**/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <iostream>
#include <fstream>

#include <gmm.h>
#include <fisher.h>

#include "fisher_handle.h"
#include "siftExtractor.h"

JNIEXPORT jfloatArray JNICALL Java_extLibrary_SIFTExtractor_calcAndGetFVs(
JNIEnv* env,
jobject obj,
jfloatArray means,
jint n_dim,
jint n_gauss,
jfloatArray covariances,
jfloatArray priors,
jfloatArray dsiftdescriptors)
{
printf("Calling 'calcAndGetFVs', starting...\n");
fflush(stdout);
// get C/C++ access to the JNI input data
jsize means_length = env->GetArrayLength(means);
jfloat* means_body = env->GetFloatArrayElements(means, 0);
jsize covar_length = env->GetArrayLength(covariances);
jfloat* covar_body = env->GetFloatArrayElements(covariances, 0);
jsize prior_length = env->GetArrayLength(priors);
jfloat* prior_body = env->GetFloatArrayElements(priors, 0);
jsize descs_length = env->GetArrayLength(dsiftdescriptors)/n_dim;
jfloat* descs_body = env->GetFloatArrayElements(dsiftdescriptors, 0);

printf("means : %i, covars %i, priors %i, descs %i, \n", means_length, covar_length, prior_length, descs_length);
printf("means : %i, covars %i, priors %i, descs %i, \n",
means_length/n_gauss, covar_length/n_gauss, prior_length, descs_length);
fflush(stdout);

float * fk = 0;
// malloc the result
jsize fvenc_length = 2 * n_dim * n_gauss;
fk = (float*) malloc( sizeof(float) * fvenc_length);
printf("Allocating result vector of size %d, n_dim %d, n_gauss %d\n", fvenc_length, n_dim, n_gauss);

if ( fk == NULL ) {
printf("Error allocating memory for the FVenc buffer\n");
fflush(stdout);
exit(-1);
}

// ## comput the fisher vector... #######
// *** This is all just part of the if("init") from the MEX *********************
// convert GMM field arrays to vectors
printf("input to vectors\n");
fflush(stdout);
std::vector<float*> mean(n_gauss);
std::vector<float*> variance(n_gauss);
for (int j = 0; j < n_gauss; ++j) {
mean[j] = &means_body[j*n_dim];
variance[j] = &covar_body[j*n_dim];
}
std::vector<float> coef(prior_body, prior_body + n_gauss);

// prepare a GMM model with data from the structure
gaussian_mixture<float> gmmproc(n_gauss,n_dim);
printf("make gmm\n");
fflush(stdout);
gmmproc.set(mean, variance, coef);

// construct a c++ struct with default parameter values
// in the Mex the settings are sent as a third variable, we stick to defaults.
fisher_param fisher_encoder_params;
fisher_encoder_params.alpha = 1.0f;
fisher_encoder_params.pnorm = 0.0f;

fisher_encoder_params.print();

// What is the role of this fhisher_handle.. can we perhaps keep it between calls.. (save time)?
printf("make handle \n");
fflush(stdout);
fisher_handle<float> fisher_encoder(gmmproc,fisher_encoder_params);
// initialise encoder with a GMM model (vocabulary)
printf(".. and set gmm model to handle \n");
fflush(stdout);
fisher_encoder.set_model(gmmproc);

// ************************************* end of if ("init") in the MEX **********

// *** else if ("encode") from the Mex *******************************************
// in the mex they get the fisher_handle we computed above sent.. so we can skip that :)
// MEXCODE: fisher_handle<float> *fisher_encoder = convertMat2Ptr<float>(prhs[1]);
// Next they get the matrix of descriptors to encode.. as a damm vector :(
// convert input vectors to c++ std::vector format
printf("descriptors to vector \n");
printf("descriptors length: %d\n", descs_length);
fflush(stdout);
std::vector<float*> x(descs_length);

for (int j = 0; j < descs_length; ++j) {
x[j] = &descs_body[j*n_dim];
}

bool weights = false;
// load in weights if specified
// do encoding

printf("encode without weights \n");
fflush(stdout);
fisher_encoder.compute(x, fk);

// ************************************* end of else if ("encode") in the Mex ****

jfloatArray result = env->NewFloatArray(fvenc_length);
if (result == NULL) {
printf("Error geting memory in the JNI for the result fisher vector\n");
fflush(stdout);
return NULL;
}
// get a pointer to the new array
printf("Copy to JNI return memory\n");
fflush(stdout);
env->SetFloatArrayRegion(result, 0, fvenc_length, fk);
printf("Calling free on fvenc\n");
fflush(stdout);

env->ReleaseFloatArrayElements(means, means_body, 0);
env->ReleaseFloatArrayElements(covariances, covar_body, 0);
env->ReleaseFloatArrayElements(priors, prior_body, 0);
env->ReleaseFloatArrayElements(dsiftdescriptors, descs_body, 0);
free(fk);
return result;
}


JNIEXPORT jfloatArray JNICALL Java_extLibrary_SIFTExtractor_computeGMM(
JNIEnv * env,
jobject obj,
jint n_gauss,
jint n_dim,
jfloatArray gmm_samples)
{
//For now this returns everything as one big fat array. This is absolutely disgusting.

//Get samples from Java.
jsize n_samples = env->GetArrayLength(gmm_samples)/n_dim;
jfloat* samples_body = env->GetFloatArrayElements(gmm_samples, 0);

//Copy to C vectors. We assume things come at us sample at a time.
std::vector<float*> samples(n_samples);
for (int i = 0; i < n_samples; ++i) {
samples[i] = &samples_body[i*n_dim];
}

//Create a default empty gmm parameter set.
em_param gmm_params;
gaussian_mixture<float> gmmproc(gmm_params, n_gauss, n_dim);

//We don't yet accept initial means/variances/coefs yet.
int seed = 42;
//int seed = time(NULL);
gmmproc.random_init(samples, seed);

//Run EM.
gmmproc.em(samples);

//Copy final stuff back out.
int meanResSize = n_gauss*n_dim;
int varResSize = n_gauss*n_dim;
int coefResSize = n_gauss;
int totalResSize = meanResSize + varResSize + coefResSize;

//Allocate output arrays.
float* meanRes = (float *) malloc(meanResSize*sizeof (float)); //array of size(ndim,ngauss)
float* varRes = (float *) malloc(varResSize*sizeof (float)); //array of size(ndim,ngauss)
float* coefRes = (float *) malloc(coefResSize*sizeof (float)); //array of size(ndim)

for (int j = 0; j < n_gauss; ++j) {
float* componentmean = gmmproc.get_mean(j);
float* componentvariance = gmmproc.get_variance(j);

for (int i = 0; i < n_dim; ++i) {
printf("%d,", i);
fflush(stdout);
meanRes[i+j*n_dim] = componentmean[i];
varRes[i+j*n_dim] = componentvariance[i];
}

coefRes[j] = gmmproc.get_mixing_coefficients(j);
}

//Copy the results back to Java land.
jfloatArray result = env->NewFloatArray(totalResSize);
env->SetFloatArrayRegion(result, 0, meanResSize, meanRes);
env->SetFloatArrayRegion(result, meanResSize, varResSize, varRes);
env->SetFloatArrayRegion(result, meanResSize+varResSize, coefResSize, coefRes);

//Cleanup structs created;
free(meanRes);
meanRes = NULL;

free(varRes);
varRes = NULL;

free(coefRes);
coefRes = NULL;

return result;
}
30 changes: 30 additions & 0 deletions src/main/cpp/fisher_handle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

/// \Class fisher_handle fisher_handle.h "fisher_handle.h"
///
/// \brief
///
/// \version 1.0
/// \author Ken Chatfield
/// \date 08/07/2011

#ifndef __FISHER_HANDLE_H
#define __FISHER_HANDLE_H

#include <fisher.h>
#include <gmm.h>
#include <stdint.h>

#define CLASS_HANDLE_SIGNATURE 0xa5a50f0f
template<class T> class fisher_handle: public fisher<T>
{
public:
fisher_handle(gaussian_mixture<T> &gmm, fisher_param params): fisher<T>(params) { signature = CLASS_HANDLE_SIGNATURE; gmmproc = &gmm; }
~fisher_handle() { signature = 0; }
bool isValid() { return (signature == CLASS_HANDLE_SIGNATURE); }
gaussian_mixture<T>* getGmmPtr() { return gmmproc; }
private:
uint32_t signature;
gaussian_mixture<T> *gmmproc;
};

#endif
Loading

0 comments on commit 6a9cecc

Please sign in to comment.