文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

OpenCV 2.4.4 支持桌面 Java 应用开发,其接口和 Android 开发几乎相同。本文主要介绍如何使用 OpenCV 创建首个 Java 应用,我们可以使用 Apache Ant 或者 Simple Build Tool (SBT) 来构建这个应用。

如果你想使用 Eclipse 开发,可以参考 Using OpenCV Java with Eclipse. 在阅读完此文后你还可以继续阅读 Introduction into Android Development 教程.

本文中我们要做什么?

在这篇文章中,我们将完成以下几项工作:

  • 获取 OpenCV 对桌面 Java 开发的支持
  • 创建一个 Ant 或者 SBT 项目
  • 使用 Java 或者 Scala 编写一个简单的 OpenCV 应用
第 1 段(可获 2 积分)

本文中介绍的内容跟 OpenCV 仓库中 samples/java 目录下的是一样的,因此,如果你无所适从的化可以参考一下这些已有的示例。

获取适当版本的 OpenCV

OpenCV 从 2.4.4 版本开始提供对桌面 Java 开发的支持。

下载

最简单的方式是从 OpenCV SourceForge 页面 下载 2.4.4 或者更新版本的压缩包。

注意事项

Windows 用户可以找到预先编译好的二进制包,这些包在下载文件里的 opencv/build/java 目录中。其他操作系统需要自行从源码中构建。

另外一种方法是从 OpenCV git 仓库 克隆代码,我们还需要 JDK 才能构建 OpenCV 的 Java 绑定包。推荐使用 Oracle JDK 6/7、Apache Ant 以及 Python 2.6 或者更新版本。

第 2 段(可获 2 积分)

构建

现在我们开始构建 OpenCV:

git clone git://github.com/Itseez/opencv.git
cd opencv
git checkout 2.4
mkdir build
cd build

生成 Makefile 或者 MS Visual Studio 的解决方案,或者是其他你希望用来构建的脚本:

cmake -DBUILD_SHARED_LIBS=OFF ..

或者

cmake -DBUILD_SHARED_LIBS=OFF -G "Visual Studio 10" ..

注意

OpenCV 使用静态库来构建 (-DBUILD_SHARED_LIBS=OFF 参数)  Java 绑定动态库是完全足够的,不需要依赖其他 OpenCV 库,因为已经包含了所有的 OpenCV 代码。

检查 CMake 的输出并确保 Java 是 "To be built" 的模块之一。如果没有的话可能是缺少了依赖。可以从 CMake 的输出结果中去诊断相关的问题:

第 3 段(可获 2 积分)

注意

如果 CMake 找不到 Java 的话,请检查  JAVA_HOME 环境变量是否指向已安装的 Java 虚拟机。

export JAVA_HOME=/usr/lib/jvm/java-6-oracle
cmake -DBUILD_SHARED_LIBS=OFF ..

现在启动构建:

make -j8

或者

msbuild /m OpenCV.sln /t:Build /p:Configuration=Release /v:m

构建完毕后将会创建一个包含了 OpenCV Java 接口的 jar 文件 (bin/opencv-244.jar) 以及一个本地动态链接库,包含了 OpenCV 相关内容 (lib/libopencv_java244.so 或者 bin/Release/opencv_java244.dll). 我们将在接下来使用到这些文件。

第 4 段(可获 2 积分)

使用 Ant 的 Java 示例

注意

下面代码是 OpenCV 提供的示例,位于 opencv/samples/java/ant 目录.

  • 创建一个目录用来存放此示例项目.

  • 在这个目录下创建 build.xml 文件,内容如下:

    <project name="SimpleSample" basedir="." default="rebuild-run">
    
       <property name="src.dir"     value="src"/>
    
       <property name="lib.dir"     value="${ocvJarDir}"/>
       <path id="classpath">
           <fileset dir="${lib.dir}" includes="**/*.jar"/>
       </path>
    
       <property name="build.dir"   value="build"/>
       <property name="classes.dir" value="${build.dir}/classes"/>
       <property name="jar.dir"     value="${build.dir}/jar"/>
    
       <property name="main-class"  value="${ant.project.name}"/>
    
    
       <target name="clean">
           <delete dir="${build.dir}"/>
       </target>
    
       <target name="compile">
           <mkdir dir="${classes.dir}"/>
           <javac includeantruntime="false" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
       </target>
    
       <target name="jar" depends="compile">
           <mkdir dir="${jar.dir}"/>
           <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
               <manifest>
                   <attribute name="Main-Class" value="${main-class}"/>
               </manifest>
           </jar>
       </target>
    
       <target name="run" depends="jar">
           <java fork="true" classname="${main-class}">
               <sysproperty key="java.library.path" path="${ocvLibDir}"/>
               <classpath>
                   <path refid="classpath"/>
                   <path location="${jar.dir}/${ant.project.name}.jar"/>
               </classpath>
           </java>
       </target>
    
       <target name="rebuild" depends="clean,jar"/>
    
       <target name="rebuild-run" depends="clean,run"/>
    
    </project>

    注意

    该 XML 可继续用于构建其他的 Java 应用。它描述了通用目录结构以及编译目标和程序的运行。

    在其他项目使用该文件别忘记修改项目名(第一行)以及第十四行的主类名。OpenCV 的 jar 包和 jni 库路径作为 ${ocvJarDir} 参数指定(第 5 行)和第 37 行的 ${ocvLibDir} ,你可以直接指定这些路径。关键 build.xm 的详细说明请参考 Ant 文档 .

  • 接下来创建一个 src 目录,并新建 SimpleSample.java.

  • SimpleSample.java 代码如下:

    import org.opencv.core.Core;
    import org.opencv.core.Mat;
    import org.opencv.core.CvType;
    import org.opencv.core.Scalar;
    
    class SimpleSample {
    
      static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
    
      public static void main(String[] args) {
        System.out.println("Welcome to OpenCV " + Core.VERSION);
        Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
        System.out.println("OpenCV Mat: " + m);
        Mat mr1 = m.row(1);
        mr1.setTo(new Scalar(1));
        Mat mc5 = m.col(5);
        mc5.setTo(new Scalar(5));
        System.out.println("OpenCV Mat data:\n" + m.dump());
      }
    
    }
    
第 5 段(可获 2 积分)

使用 SBT 构建 Java 或 Scala 项目

现在我们改用 SBT 来创建一个简单的 Java 应用。这里只是简单介绍一下 SBT 的使用。我们正在使用 SBT 引入它足够简单而且功能强大。

首先现在并安装 SBT ,安装的介绍请阅读 这里.

接下来创建一个新目录用来存放应用源码(不要跟 opencv 放在一起),假设该目录为 JavaSample :

cd <somewhere outside opencv>
mkdir JavaSample

然后我们就可以创建一个 SBT 项目必须的文件:

第 6 段(可获 2 积分)
cd JavaSample
mkdir -p src/main/java # This is where SBT expects to find Java sources
mkdir project # This is where the build definitions live

现在用你喜欢的编辑器打开 project/build.scala 文件并粘贴如下内容:

import sbt._
import Keys._

object JavaSampleBuild extends Build {
  def scalaSettings = Seq(
    scalaVersion := "2.10.0",
    scalacOptions ++= Seq(
      "-optimize",
      "-unchecked",
      "-deprecation"
    )
  )

  def buildSettings =
    Project.defaultSettings ++
    scalaSettings

  lazy val root = {
    val settings = buildSettings ++ Seq(name := "JavaSample")
    Project(id = "JavaSample", base = file("."), settings = settings)
  }
}
第 7 段(可获 2 积分)

现在可以编辑 project/plugins.sbt 文件并粘贴如下内容。该代码用来启用 Eclipse 项目的自动生成功能:

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")

然后在 JavaSample 的目录下运行 sbt 命令来生成 Eclipse 项目:

sbt # Starts the sbt console
> eclipse # Running "eclipse" from within the sbt console

下面是运行该命令输入的结果:

你可以利用 Eclipse 的 Import ... -> Existing projects into workspace 来导入 SBT 项目。这一步是可选的,在这个例子中我们使用的是 SBT 来构建项目,因此,如果你选择使用 Eclipse 的话,在这里只是被当成文本编辑器而已。

第 8 段(可获 2 积分)

为了测试上述步骤是否成功,我们创建一个简单的 “Hello OpenCV” 应用。简单的创建一个文件 src/main/java/HelloOpenCV.java ,代码如下:

 public class HelloOpenCV {
   public static void main(String[] args) {
     System.out.println("Hello, OpenCV");
  }
}

现在可以在 sbt 控制台运行或者在命令行窗口执行如下 sbt 命令来运行这个程序:

sbt run

下图是运行结果:

运行 SBT 示例

现在我们将使用 OpenCV 创建一个简单的人脸识别应用。

首先创建一个 lib 目录,并将 OpenCV 的 jar 包拷贝其中。默认的 SBT 会自动添加 lib 目录下的 jar 包到 Java 库的搜索路径中。你只需要运行 sbt eclipse 来更新 Eclipse 项目。

第 9 段(可获 2 积分)
mkdir lib
cp <opencv_dir>/build/bin/opencv_<version>.jar lib/
sbt eclipse

接下来创建目录 src/main/resources 并下载 Lena 的图片到这个目录下:

确保图片名称为 lena.png。Java 程序可以在运行时读取资源目录下的文件。

接下来从 opencv/data/lbpcascades/ 拷贝 lbpcascade_frontalface.xml 文件到资源目录:

cp <opencv_dir>/data/lbpcascades/lbpcascade_frontalface.xml src/main/resources/

现在修改 src/main/java/HelloOpenCV.java 源码文件包含以下代码:

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.objdetect.CascadeClassifier;

//
// Detects faces in an image, draws boxes around them, and writes the results
// to "faceDetection.png".
//
class DetectFaceDemo {
  public void run() {
    System.out.println("\nRunning DetectFaceDemo");

    // Create a face detector from the cascade file in the resources
    // directory.
    CascadeClassifier faceDetector = new CascadeClassifier(getClass().getResource("/lbpcascade_frontalface.xml").getPath());
    Mat image = Highgui.imread(getClass().getResource("/lena.png").getPath());

    // Detect faces in the image.
    // MatOfRect is a special container class for Rect.
    MatOfRect faceDetections = new MatOfRect();
    faceDetector.detectMultiScale(image, faceDetections);

    System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));

    // Draw a bounding box around each face.
    for (Rect rect : faceDetections.toArray()) {
        Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
    }

    // Save the visualized detection.
    String filename = "faceDetection.png";
    System.out.println(String.format("Writing %s", filename));
    Highgui.imwrite(filename, image);
  }
}

public class HelloOpenCV {
  public static void main(String[] args) {
    System.out.println("Hello, OpenCV");

    // Load the native library.
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    new DetectFaceDemo().run();
  }
}
第 10 段(可获 2 积分)

注意 System.loadLibrary(Core.NATIVE_LIBRARY_NAME) 这个方法调用。该方法只能在进程中调用一次。如果没有调用则会出现 UnsatisfiedLink 错误,调用两次也会出错。

接下来使用 sbt run 来运行这个人脸检测应用:

sbt run

运行结果如下:

该命令会生成一个新的图片 faceDetection.png:

搞定啦!你现在有了一个 OpenCV 的简单 Java 应用。你可以在这个基础上继续你的其他需求开发。祝你好远!

第 11 段(可获 2 积分)

文章评论

coyee
这么好的文章居然没人评论,太过分啦啦啦 :grin: