最近做一个基于移动终端(手机为例)的人脸识别系统,要用到我自己的matlab算法,所以就写此博客为读者介绍和分析一下Java Servlet中调用Matlab算法的过程和需要注意的一些细节问题。
一、封装Matlab算法
将自己写的Matlab算法在.m文件中写成一个function,然后通过javabuilder打包成Java Servlet 可以调用的jar包。前提是该版本的Matlab支持javabuilder。封装步骤如下:
(1)在matlab的command窗口中输入“deploytool"回车,就会弹出一个窗口
(2)在弹出窗口中Name栏输入工程名称,Location栏输入文件的位置,在Target 栏选择Java Package,确定后会在Matlab中的右边弹出一个窗口,点击Add class输入jar包中的类名,如“Test”
接着点击Add files 就可以添加你需要直接调用或间接调用的matlab方法。最后点击按钮创建jar包。没有报错就说明创建完成。
(3)jar创建完成后,会生成一个工程文件夹和一个prj文件,prj文件是工程文件,文件夹中包含两个文件夹:distrb和src。接着将distrb->XXX.jar和src->class->XXX(类名)->XXX.ctf放在同一目录下,并将XXX.jar的路径添加到classpath环境变量中。
注意事项:在导出jar包之前要保证自己的matlab已经安装好了MCRInstaller.exe。如果没有安装可以在matlab安装路径中找到并安装。我的MCRInstaller.exe文件路径是C:\Program Files\MATLAB\R2009b\toolbox\compiler\deploy\win32\MCRInstaller.exe
二、在eclipse中添加jar包
在web工程中导入jar包,将之前生成的XXX.jar包复制到WebContent->WEB-INFO下lib文件夹中,右键点击jar包->build path -> add to build path。然后在matlab安装路径中找到javabuilder.jar包并复制到WebContent->WEB-INFO下lib文件夹中,同样右键点击jar包->build path -> add to build path。我的。javabuilder.jar包的路径为:C:\Program Files\MATLAB\R2009b\toolbox\javabuilder\jar\javabuilder.jar。
jar 包添加成功以后就可以在Servlet中正常调用了。
注意事项:右键单击工程->build path->configure build path->library->add external jars添加jar包会提示找不到jar包,因为jar包没有复制到工程中。
可能出现的异常:报MCR.exe错误 ,说明在第一步中MCRInstaller.exe没有安装。如果报类找不到说明第二步中添加jar包的方式不对。
三、实例
此实例将说明Matblab函数中存在函数之间的调用,并且函数返回的是多个不同类型的参数组成的数组,实现Servlet与Matlab之间的各类型参数互传,图片传送等。
(1)Matlab函数编写
函数1:初始化一个大小的矩阵
function A = getSize(a,b,c,d)
A = [a,b;c,d];
函数2 :调用函数1 并传入参数类型有字符串,整型。
function [name,number,size] = imgInfo(name1,number1,a,b,c,d)
name = name1;
number = number1;
size = getSize(a,b,c,d);
end
(2)将以上方法打成jar包,步骤参照封装Matlab算法部分。
(3)在Servlet中调用上述封装的Matlab方法
导入jar包之后,包中内容如下
(4)Servlet中主程序调用
核心代码如下
MWCharArray s = null;
MWNumericArray number = null;
MWNumericArray size = null;
try {
MyTest myTest = new MyTest();
s = new MWCharArray("Hello world!");
Object[] result = myTest.imgInfo(3, s,1,12,13,14,15);
number = new MWNumericArray(result[1],MWClassID.INT32);
size = new MWNumericArray(result[2]);
System.out.println(result[0].toString());
System.out.println(number);
System.out.println(size);
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
MWArray.disposeArray(s);
MWArray.disposeArray(number);
MWArray.disposeArray(size);
}
(5)输出结果
(6)程序分析
Matlab第一个函数是初始化一个二维数组,第二个函数是测试输入输出不同类型的参数。输出的第一个参数是字符串,第二个是整型,第三个是矩阵。
MWnumericArray是Java和Matlab之间的中间变量转换类型。
a、传字符串时用MWCharArray,传整型、Double、Float、int等类型及其相应矩阵时用MWNumericArray。传类、方法等结构体是用MWStructArray。
b、调用Matlab函数返回值都用Object[]接收,任何类型都可以。
c、myTest.imgInfo(3, s,1,12,13,14,15);函数的第一个参数表示返回值的个数,相应的输入参数类型要转换成对应的中间类型,整型可以不用转换。
d、程序调用完成最后要释放所有资源
(7)用第三方包进行图片传送
package binary_magic;
import java.util.ArrayList;
import ij.IJ;
import ij.ImagePlus;
import ij.process.ImageProcessor;
import imgbinary2.*;
import com.mathworks.toolbox.javabuilder.MWArray;
importcom.mathworks.toolbox.javabuilder.MWClassID;
importcom.mathworks.toolbox.javabuilder.MWNumericArray;
public class magic {
ImagePlus img,binimg;
ImageProcessor ip;
public void binary2(ImagePlus img,) {
this.img=img;
int w=img.getWidth();
int h=img.getHeight();
ImagePlus img1=IJ.createImage("newimage","",w,h,1);
ip=img1.getProcessor();
ArrayList<Object> tempList= new ArrayList<Object>();
MWNumericArray n = null;
Binary binMagic = null; /* Stores magic */
try {
n= new MWNumericArray(Double.valueOf(3), MWClassID.DOUBLE);
System.out.println("Magic square of order " +n.toString());
binMagic = new Binary();
/**
* made ImagePlus
**/
Object Obimg[]=null;
int num=0;
Obimg=binMagic.bianry(1,);
int[] k=((MWNumericArray)Obimg[0]).getDimensions();
// IJ.log("width2="+k[1]+", height2="+k[0]);
for(int i=0;i<k[1];i++){
int offset=i*k[0];
for(int j=0;j<k[0];j++){
int pos=offset+j;
num=((MWNumericArray)Obimg[0]).getInt(pos+1);
//IJ.log("************"+num);
if(num==0){
ip.putPixel(i, j, num);
}
else{
ip.putPixel(i, j, 255);
}
}
}
binimg=new ImagePlus("binary",ip);
binimg.show();
/**
* end
**/
}catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
System.out.println("Exception: " + e.toString());
}finally {
MWArray.disposeArray(n);
// if (binMagic != null)
// binMagic.dispose();
}
}
public ImagePlus reBinary(){
return binimg;
}
}
小结:本实例是参数图像处理项目写的一个小例子,实际项目算法程度复杂,调用传参过程多,在后续文章中再给出。