SpringBoot集成OpenCV进行图像处理

一、环境部署

  • Windows
  1. OpenCV官网下载安装包
    OpenCV官网
    OpenCV官网
  2. 安装完毕后,在opencv\build\java复制jar包,后续导入依赖时使用
  3. opencv\build\java\x64opencv\build\java\x86复制dll文件,将dll文件复制到C:\Windows\System32文件夹
  • Linux 以Centos为例
  1. 安装依赖
yum install  gcc  gcc-c++
yum install cmake*
yum install gtk2-devel
yum install ant
  1. 在官网下载OpenCV源码,上传至Linux服务器并解压
    在这里插入图片描述
  2. 进入解压后的OpenCV源码目录,创建编译目录
cd /opencv4.4.0
mkdir build
cd build
  1. 生成makefile(/makefile目录更换为自定义的文件夹)
cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=/makefile ..

.. 代表在父目录执行

  1. 编译、安装
make
make install
  1. 安装后产生的文件
opencv-4.4.0/build/lib/libopencv_java440.so
opencv-4.4.0/build/bin/opencv-440.jar

jar包和Windows下生成的一样;so包则是Linux所特有,对应于Windows的dll文件
7. 将libopencv_java440.so复制到 /usr/lib 文件夹
8. Linux下编译安装完成后会默认部署OpenJDK11环境在服务器上,影响服务器原Java环境,只需要手动卸载OpenJDK即可,原Java环境会重新生效

二、导入依赖

  1. 在SpringBoot项目的resources文件夹新建 /lib/opencv 文件夹,将 jar 包复制进去
  2. 项目不要集成spring-boot-devtools工具,会影响dll库文件导入
  3. 添加依赖
		<!-- OpenCV -->
        <dependency>
            <groupId>org</groupId>
            <artifactId>opencv</artifactId>
            <scope>system</scope>
            <systemPath>${project.basedir}\src\main\resources\lib\opencv\opencv-440.jar</systemPath>
            <version>4.4.0</version>
        </dependency>

三、使用

  1. 新建MatUtil,将图片Base64(去掉Base64文件头)转为Mat对象
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * @author Tang_J on 2022/4/20 下午 02:00
 * @Description TODO
 **/
public class MatUtil {

    /**
     * Base64 编码转换为 BufferedImage
     *
     * @param base64 图片Base64
     * @return BufferedImage
     */
    public static BufferedImage base64ToBufferedImage(String base64) {
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            byte[] buffer = decoder.decodeBuffer(base64);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);
            return ImageIO.read(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Mat 转换成 byte[]
     *
     * @param mat Mat对象
     * @return byte[]
     */
    public static byte[] toByteArray(Mat mat) {
        MatOfByte mob = new MatOfByte();
        Imgcodecs.imencode(".jpg", mat, mob);
        return mob.toArray();
    }

    /**
     * byte[] 转 图片Base64
     *
     * @param bytes byte[]
     * @return Base64
     */
    public static String byteArray2Base64(byte[] bytes) {
        return DatatypeConverter.printBase64Binary(bytes);
    }

    /**
     * Mat 转 图片Base64
     *
     * @param mat Mat
     * @return 图片Base64
     */
    public static String mat2Base64(Mat mat) {
        return byteArray2Base64(toByteArray(mat));
    }

    /**
     * Mat 转换成 BufferedImage
     *
     * @param mat Mat
     * @return BufferedImage
     */
    public static BufferedImage toBufferedImage(Mat mat) throws IOException {
        byte[] buffer = toByteArray(mat);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);
        return ImageIO.read(inputStream);
    }

    /**
     * Base64 转换成 Mat
     *
     * @param base64 图片Base64
     * @return Mat
     */
    public static Mat base642Mat(String base64) {
        return bufImg2Mat(base64ToBufferedImage(base64), BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);
    }

    /**
     * BufferedImage 转换成 Mat
     *
     * @param original 要转换的BufferedImage
     * @param imgType  bufferedImage的类型 如 BufferedImage.TYPE_3BYTE_BGR
     * @param matType  转换成mat的type 如 CvType.CV_8UC3
     *                 https://wenku.baidu.com/view/3cd5e54b5bfafab069dc5022aaea998fcc2240a1.html
     */
    public static Mat bufImg2Mat(BufferedImage original, int imgType, int matType) {
        if (original == null) {
            throw new IllegalArgumentException("original == null");
        }
        // Don't convert if it already has correct type
        if (original.getType() != imgType) {
            // Create a buffered image
            BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);
            // Draw the image onto the new buffer
            Graphics2D g = image.createGraphics();
            try {
                g.setComposite(AlphaComposite.Src);
                g.drawImage(original, 0, 0, null);
                original = image;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                g.dispose();
            }
        }
        byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
        Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
        mat.put(0, 0, pixels);
        return mat;
    }

}

  1. OpenCVUtil,图片处理工具类,在此工具类中编写更多图片处理方法;@Component注册为组件使用,只需在项目启动时加载一次OpenCV库
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import static org.opencv.imgproc.Imgproc.*;

@Component
@Scope(value = "singleton")
public class OpenCVUtil {

	/**
     * 日志组件可根据自己项目更换
     */
    private static final Logger logger = LoggerFactory.getLogger(OpenCVUtil.class);

	/**
     * 1.什么是java.awt.headless模式
     * java.awt.headless是J2SE的一种模式,用于在缺失显示屏、鼠标或者键盘时的系统配置。对于后端服务来讲,很多都是需要将这个属性设置为true的。
     * 2.什么时候使用java.awt.headless模式
     * 对于开发者来讲常常需要在该模式下工作。因为服务器(如提供Web服务的)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的、键盘和的主机)。
     */
    static {
        try {
            // 解决awt报错问题
            logger.info("启动headless mode...");
            System.setProperty("java.awt.headless", "true");
            logger.info("动态库路径:{}", System.getProperty("java.library.path"));
            logger.info("开始加载OpenCV库...");
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
            logger.info("load success");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 图片清晰度增强
     * 使用高斯滤波器,高斯滤镜可减少图像中的噪声并使它看起来更好(或更高分辨率)
     * http://www.srcmini.com/70014.html
     *
     * @param base64 图片Base64
     */
    public String imageDefinitionEnhance(String base64) {
        logger.info("图片清晰度增强");
        Mat source = MatUtil.base642Mat(base64);
        Mat destination = new Mat(source.rows(), source.cols(), source.type());
        GaussianBlur(source, destination, new Size(0, 0), 10);
        Core.addWeighted(source, 1.5, destination, -0.5, 0, destination);
        return MatUtil.mat2Base64(destination);
    }

    /**
     * 图片对比度增强
     * 使用直方图均衡
     * http://www.srcmini.com/70010.html
     *
     * @param base64 图片Base64
     */
    public String imageContrastEnhance(String base64) {
        logger.info("图片对比度增强");
        Mat source = MatUtil.base642Mat(base64);
        cvtColor(source, source, COLOR_BGR2GRAY);
        Mat destination = new Mat(source.rows(), source.cols(), source.type());
        equalizeHist(source, destination);
        return MatUtil.mat2Base64(destination);
    }

    /**
     * 图片无损放大
     * 使用高斯金字塔
     * https://blog.csdn.net/datouniao1/article/details/108535563
     *
     * @param base64 图片Base64(去文件头)
     */
    public String imageQualityEnhance(String base64) {
        logger.info("图片无损放大");
        Mat source = MatUtil.base642Mat(base64);
        Mat destination = new Mat();
        pyrUp(source, destination);
        return MatUtil.mat2Base64(destination);
    }

}

四、注意事项

  1. 项目不要集成spring-boot-devtools
  2. 使用System.loadLibrary(Core.NATIVE_LIBRARY_NAME) 加载库,才能在部署到服务器后依旧可以动态加载库;网上的文章都是直接加载dll文件的方法
  3. Java使用OpenCV处理图片教程

如有建议或疑问欢迎指出!

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值