生而自由

自由而无用的灵魂

OpenCV for Java环境搭建

前言

众所周知OpenCV是一个基于C/C++开发的功能强大的计算机视觉开源框架,官方提供了Windows(含Java封装库)、Android、iOS这几种环境下的已编译好的库。

一般情况下如果想在桌面操作系统中使用OpenCV,可以直接使用C/C++调用编译好的动态/静态库。
如果想要通过Java来使用OpenCV,可以先将相关功能用C/C++开发后编译为JNI库、再由Java程序调用(IPC、RPC方式在此不讨论)。 也可以直接使用OpenCV的Java封装库(封装了对OpenCV的JNI调用),这样可以直接用Java进行OpenCV相关的开发,后面这种方式对于大多数Java开发同学来说更为友好,效率上也没有太大的差别。

但官方只提供了Windows下的Java封装库,Linux、MacOS下的Java封装库就要自己动手丰衣足食了,想要在Java后端开发中使用OpenCV,就得自己编译下Linux(服务器使用)、MacOS(本机开发使用)下的Java封装库和对应的OpenCV动态链接库了。

编译及结果

OpenCV 2.4.x 版本的Java封装库编译官方文档在:https://docs.opencv.org/2.4/doc/tutorials/introduction/desktop_java/java_dev_intro.html 。

编译过程也比较简单不再赘述,这里直接提供编译好的Jar包和动态库。 注意编译机器上的Java版本都是Java8,编出来的Jar包低版本的Java可能不能使用(没有测试过)。

Linux版本

如果应用要部署到服务器上,那当然只能用Linux版本的动态库和Jar包了。Jar包可以通过该url获取(尽量保证长期有效):http://cdn.spirithy.com/code/opencv2413-java/linux/opencv-2413.jar

so动态链接库可以通过该url获取(尽量保证长期有效,方便直接用Docker的ADD指令):http://cdn.spirithy.com/code/opencv2413-java/linux/libopencv_java2413.so

MacOS

Mac下是使用的XCode自带的CLang来编译的,Jar包可以通过该url获取(尽量保证长期有效):http://cdn.spirithy.com/code/opencv2413-java/macos/opencv-2413.jar但请注意,经测试MacOS下直接用Linux的Jar包也是完全OK的、证明两个平台下的Jar包其实是没有区别的,所以直接用opencv-java-x86_64-linux的Jar包更方便。

dylib动态链接库可以通过该url获取(尽量保证长期有效):http://cdn.spirithy.com/code/opencv2413-java/macos/libopencv_java2413.dylib 。

使用

上面编译出来的动态链接库中已经包含了OpenCV的所有函数,所以Java应用在使用时只需要依赖这一个动态链接库、及Java封装库即可,非常的方便。

在项目中引入jar包

直接引入上述的Maven依赖即可,MacOS、Linux下都可以用opencv-java-x86_64-linux的Jar包。

依赖动态库

需要在Java参数中指定OpenCV动态库所在的目录的路径,这样才能加载到动态链接库。

本机环境(MacOS)

例如在MacOS下进行开发,在Idea中,“Run”-“Edit Configurations”-“VM options”,加入以下参数即可指定动态库的目录。

-Djava.library.path=/Users/xxxx/opencv2413-java/macos

服务器环境

需要将动态库部署到服务器上,或者添加到Docker镜像中,然后需要在启动Java应用时用”-Djava.library.path”指定动态库目录。 具体实现这里也没有实践过需要读者自行尝试。

代码编写

Java使用OpenCV的封装库,和在C/C++中使用OpenCV,在代码上是稍有不同的,但基本可以把代码“平移过来”。

需要额外注意的只有一点:在Java进程中、使用OpenCV之前需要显式地加载动态库。 所以如果是Spring boot应用可以在Application.java的静态代码块中执行加载。示例如下:

public class Application {

    //加载OpenCV动态链接库
    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args)...
    }
}

代码示例

下面提供一个从C++代码人工转换过来的Java使用OpenCV的示例,功能为“从一张白底图片中抠出包含主要内容的最小图片”,也就是“抠图片中的物体”,代码比较简单而且应该还有需要调优的地方。

package com.xxxx;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Rect;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

/**
 * @author Spirit
 */
public class Sample {

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void getSplitedPicture(String dirPath, String fileName) {
        Mat image = Highgui.imread(dirPath + fileName);

        Mat imageBackup = image.clone();

        //灰度
        Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2GRAY);

        //二值
        double[] data = image.get(0, 0);
        int thres = (int)(data[0] - 5);

        Imgproc.threshold(image, image, thres, 255, Imgproc.THRESH_BINARY);

        //反色
        Core.bitwise_not(image, image);

        //检测轮廓
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(image, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

        //查找最大区域
        double maxArea = 0;
        int maxAreaIndex = -1;
        for(int i=0; i<contours.size(); i++)
        {
            double tmparea = Math.abs(Imgproc.contourArea(contours.get(i)));

            if(tmparea > maxArea)
            {
                maxArea = tmparea;
                maxAreaIndex = i;
            }
        }

        //裁剪
        if (maxAreaIndex > 0) {
            Rect rect = Imgproc.boundingRect(contours.get(maxAreaIndex));

            Mat result = imageBackup.submat(rect);

            Highgui.imwrite(dirPath + fileName.substring(0, fileName.lastIndexOf(".")) + "_result.jpg", result);
        }
    }

    public static void main(String[] args) {
        getSplitedPicture("/Users/xxxx/Downloads/", "cup.jpeg");
    }
}

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注