一、通过JNI,将C写成的cuda编译成动态链接库
1、 写一个java类,类中包含一个native的函数,导入.so动态链接库,注意,linux中,SiftGPU其实指的是libSiftGPU.so。
package nfs.sil.image.sift.main;
import java.util.List;
import java.lang.reflect.*;
import java.util.ArrayList;
import net.semanticmetadata.lire.imageanalysis.sift.Feature;
public class FeatureExtractSIFT_GPU
{
static{
try{
System.loadLibrary("SiftGPU");
}
catch(UnsatisfiedLinkError e){
System.err.println("Cannot load SIFT library\n"+e.toString());
}
}
public FeatureExtractSIFT_GPU(){
// features = new ArrayList
();
}
public native void ExtractSIFT(String filename, List
features) throws Exception;
public native void ExtractSIFT(float[] data, int width, int height, List
feature) throws Exception;
public List
ExtractFeatures(float[] data, int width, int height){
List
features = new ArrayList
(); List
result = new ArrayList
(); try{ ExtractSIFT(data, width, height, features); }catch (Exception e){ e.printStackTrace(); return null; } for(int i = 0; i < features.size(); ++i){ float[] vec = features.get(i); Feature temp = new Feature(); temp.location = new float[2]; temp.location[0] = vec[0]; temp.location[1] = vec[1]; temp.scale = vec[2]; temp.descriptor = new float[128]; System.arraycopy(vec, 4, temp.descriptor, 0, 128); result.add(temp); } return result; } public List
ExtractFeatures(String filename){ List
features = new ArrayList
(); List
result = new ArrayList
(); try{ ExtractSIFT(filename类, features); }catch (Exception e){ e.printStackTrace(); return null; } for(int i = 0; i < features.size(); ++i){ float[] vec = features.get(i); Feature temp = new Feature(); temp.location = new float[2]; temp.location[0] = vec[0]; temp.location[1] = vec[1]; temp.scale = vec[2]; temp.descriptor = new float[128]; System.arraycopy(vec, 4, temp.descriptor, 0, 128); result.add(temp); } return result; } public static void main(String[] args){ String filename = "01.png"; System.out.println("compute 1!"); FeatureExtractSIFT_GPU t = new FeatureExtractSIFT_GPU(); try{ t.ExtractFeatures(filename); }catch (Exception e){ e.printStackTrace(); return; } System.out.println("compute success!"); } }
2、javac编译这个类生成.class文件,我直接用eclipse编译了。
3、在项目目录下的./bin文件目录下,使用如下命令,生成C++函数的头文件
javah -jni -classpath . nfs.sil.image.sift.main.FeatureExtractSIFT_GPU
在该目录下会出现一个nfs_sil_image_sift_main_FeatureExtractSIFT_GPU.h的头文件,文件内容如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class nfs_sil_image_sift_main_FeatureExtractSIFT_GPU */
#ifndef _Included_nfs_sil_image_sift_main_FeatureExtractSIFT_GPU
#define _Included_nfs_sil_image_sift_main_FeatureExtractSIFT_GPU
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: nfs_sil_image_sift_main_FeatureExtractSIFT_GPU
* Method: ExtractSIFT
* Signature: (Ljava/lang/String;Ljava/util/List;)V
*/
JNIEXPORT void JNICALL Java_nfs_sil_image_sift_main_FeatureExtractSIFT_1GPU_ExtractSIFT__Ljava_lang_String_2Ljava_util_List_2
(JNIEnv *, jobject, jstring, jobject);
/*
* Class: nfs_sil_image_sift_main_FeatureExtractSIFT_GPU
* Method: ExtractSIFT
* Signature: ([FIILjava/util/List;)V
*/
JNIEXPORT void JNICALL Java_nfs_sil_image_sift_main_FeatureExtractSIFT_1GPU_ExtractSIFT___3FIILjava_util_List_2
(JNIEnv *, jobject, jfloatArray, jint, jint, jobject);
#ifdef __cplusplus
}
#endif
#endif
4、实现nfs_sil_image_sift_main_FeatureExtractSIFT_GPU.cu,实现.h中的C++函数,
5、编译,生成动态链接库
先把所有的.cu文件用nvcc编译成.o文件
最后 gcc -Wall -rdynamic 'pkg-config --cflags opencv' -fopenmp -shared -L/home/OpenCV-2.4.3/lib -lopencv_core -lopencv_highgui -L/usr/local/cuda/lib -lcudart -o libSiftGPU.so $(ALL)
二、使用hadoop运行程序
注意,在需要运行的类中包含,将一些参数分析交给GenericOptionsParser做。
GenericOptionsParser parser = new GenericOptionsParser(conf, args);
String[]otherArgs = parser.getRemainingArgs();
运行命令
hadoop jar imageRetrieval.jar nfs.sil.image.sift.index.SiftHadoopImageIndexer -files libSiftGPU.so images index
-files意思是把libSiftGPU.so拷贝到工作机上。
另一个可行的办法是,手动将libSiftGPU.so拷贝到java.library.path所指向的文件夹下
咳咳,这种方法比较暴力~~