简介
由于项目需求在hadoop集群上处理图像,使用Selective Search算法来获取object proposal,但是目前SS算法核心是由C来编写,看不到具体实现。所以考虑将SS移植到Centos中使用eclipse+java来调用。
基于JNI制作.so
1.制作.h文件
打开centos上的eclipse新建一个工程名字为selectiveSearch,然后在src下建立包com.JNI,并新建一个类
package com.JNI;
import org.opencv.*;//这句话应该可以不需要
public class JNISelectiveSearch {
public JNISelectiveSearch(String libraryName){
System.loadLibrary(libraryName);
}
public JNISelectiveSearch(){
System.loadLibrary("SelectiveSearch");
}
public native int[] selectivesearch(long matAddrInRGBA, float sigma, float l, int min_size, int region_nums);//参数l应该为k,我自己写错了
}
然后cd到src文件夹下,使用如下命令:
javah com.JNI.JNISelectiveSearch
然后可以在src文件夹下看到相应的.h文件。
2.编写SelectiveSearchForJNI.cpp
#include <jni.h>
#include "com_JNI_JNISelectiveSearch.h"
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/legacy/compat.hpp>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include "image.h"
#include "misc.h"
#include "pnmfile.h"
#include "generate_bounding_boxes.h"
#include "type_convert.h"
using namespace std;
using namespace cv;
JNIEXPORT jintArray JNICALL Java_com_JNI_JNISelectiveSearch_selectivesearch
(JNIEnv *env, jobject obj, jlong addrInRGB, jfloat jsigma, jfloat jk, jint jmin_size, jint jregion_nums)
{
Mat *pMatInRGB = (Mat*) addrInRGB;
Mat img;
img = *pMatInRGB;
float sigma = (float)jsigma;
float k = (float)jk;
int min_size = (int)jmin_size;
int region_nums = (int)jregion_nums;
// read image
if(img.empty())
{
cout<<"C++中读取图片为空!"<<endl;
return 0;
}
// convert to image type
image<rgb>* imginput = matToImage(img);
int* BB = generate_bounding_boxes(imginput, sigma, k, min_size, ®ion_nums);
jint arrayLength = region_nums*4;
jintArray regionXY = env->NewIntArray(arrayLength);
jint num[1];
for(int i=0;i<arrayLength;i++)
{
int xyRAM = BB[i];
num[0] = xyRAM;
env->SetIntArrayRegion(regionXY,i,1,num);
}
delete imginput;
printf("selectivesearch成功!\n");
return regionXY;
}
3.编译.so
将com_JNI_JNISelectiveSearch.h、SelectiveSearchForJNI.cpp和相应的头文件至同一个文件夹,由于使用了opencv等库,所以进行编译的时候使用-I添加相应依赖:
上面命令太长了我不知道怎么编辑出来,所以截图进行展示吧,可以看到水印也是我自己的,所以是原创没有抄袭。
eclipse中调用该.so
这里只是简单举例怎么使用上面生成的.so文件,在hadoop集群上使用需要使用GDAL读取内存中虚拟出来的图片然后转换成opencv格式(该方法在我之前的博客中写过,可以直接使用)。
话不多说,还在之前eclipse建立的工程中再新建一个类main.java
package com.JNI;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.*;
public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
JNISelectiveSearch open = new JNISelectiveSearch("SelectiveSearch");
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
String filename = "/home/hadoop/Desktop/000001.jpg";
Mat image = Highgui.imread(filename);
if (image==null||image.empty()) {
System.out.println("读取图像失败,图像为空");
return;
}
System.out.println("读取图片成功!");
int[] points = open.selectivesearch(image.getNativeObjAddr(), 1, 200, 200, 1000);
System.out.println(points.length);
System.out.println("It is a hard work!");
}
}