java+opencv实现图像矫正,并解决中文文件名报错问题,同时兼容windows、linux两个环境

前言

java+opencv实现图像矫正,并解决中文文件名报错问题,同时兼容windows、linux两个环境

一、实现效果

矫正前效果图:
矫正前
矫正后效果:
矫正后

二、前期准备

需要引入对应环境#的.dll(windows)与.so(linux)文件,将文件下载到本地,拷贝文件路径替换代码中对应的路径,下载文件资源地址(包含一张测试图片):https://pan.baidu.com/s/1O9WKeD9KU6qEYLYSvbfBjg
提取码:38uv

二、代码部分

1.引入库

直接引入javacv依赖会很臃肿,精简一下只引入opencv部分即可;如需要javacv其他依赖包,根据实际情况引入。
pom依赖:

<dependency>
	<groupId>org.bytedeco</groupId>
	<artifactId>opencv</artifactId>
	<version>4.5.1-1.5.5</version>
</dependency>

2.代码

图像矫正功能代码组成为工具类(RectifyImageUtil)+入参对象(Image)
Image代码如下:

import lombok.Data;
import java.io.Serializable;

/**
 * 图像信息
 * @Date 2023/3/24 9:42
 */
@Data
public class Image implements Serializable {
    /**
     * 写入图片路径
     */
    private String imgUrlInput;
    /**
     * 输出图片路径(如果为空,将覆盖写入图片路径)
     */
    private String imgUrlOut;
    /**
     * 左上x
     */
    private float ltX;
    /**
     * 左上y
     */
    private float ltY;
    /**
     * 右上x
     */
    private float rtX;
    /**
     * 右上y
     */
    private float rtY;
    /**
     * 左下x
     */
    private float lbX;
    /**
     * 左下y
     */
    private float lbY;
    /**
     * 右下x
     */
    private float rbX;
    /**
     * 右下y
     */
    private float rbY;
    /**
     * 图像宽
     */
    private float imgWidth;
    /**
     * 图像高
     */
    private float imgHeight;
}

RectifyImageUtil代码如下:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import javax.imageio.ImageIO;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author lqt
 * @date 2023/3/24 9:48
 * @version 1.0
 */
@Slf4j
public class RectifyImageUtil {

    // 根据服务器环境动态加载依赖 (只支持windows与linux)
    static {
        String os = System.getProperty("os.name");
        log.info("当前环境" + os);
        if (os != null && os.toLowerCase().startsWith("windows")) {
            //Windows操作系统
            // todo 替换本地 .dll文件路径 (例如:D:\\data\\windows\\x64\\opencv_java460.dll)
            System.load("(.dll文件本地路径)\\opencv_java460.dll");
        } else if (os != null && os.toLowerCase().startsWith("linux")) {
            //Linux操作系统
            // todo 部署服务器修改.so文件路径 (例如:/data/so/libopencv_java460.so)
            System.load("(.so文件服务器路径)/libopencv_java460.so");
        }
    }

    public static void main(String[] args) {
        Image img = new Image();
        img.setImgUrlInput("(测试图片路径,可以使用网片链接中的图片测试)\\qiaoba_副本.png");
        img.setImgUrlOut("(输出图片路径)\\qiaoba_中文2.png");
        // 以下数值是网盘链接图片的测试数据,如果有自己图片和数据直接替换
        img.setLtX(71.5f);
        img.setLtY(112);
        img.setRtX(298.5f);
        img.setRtY(113);
        img.setLbX(53.5f);
        img.setLbY(573);
        img.setRbX(306.5f);
        img.setRbY(624);
        img.setImgWidth(600);
        img.setImgHeight(800);
        boolean flag = rectifyImage(img);
        log.info("操作:" + flag);
    }

    /**
    * 图像矫正
    * @date 2023/3/24 10:10
    * @param img 矫正信息
    * @return boolean
    * @author lqt
    */
    public static boolean rectifyImage(Image img){
        try {
            if(StringUtils.isEmpty(img.getImgUrlInput())){
                return false;
            }
            File file = new File(img.getImgUrlInput());
            if(!file.exists()){
                return false;
            }
            Mat src = imRead(img.getImgUrlInput());
            Mat dst = new Mat();
            // 输入图像
            Point[] pt1 = new Point[4];
            pt1[0]=new Point(img.getLtX(),img.getLtY());
            pt1[1]=new Point(img.getRtX(),img.getRtY());
            pt1[2]=new Point(img.getLbX(),img.getLbY());
            pt1[3]=new Point(img.getRbX(),img.getRbY());

            //输出图像
            Point[] pt2 = new Point[4];
            pt2[0]=new Point(0,0);
            pt2[1]=new Point(img.getImgWidth(),0);
            pt2[2]=new Point(0,img.getImgHeight());
            pt2[3]=new Point(img.getImgWidth(),img.getImgHeight());

            MatOfPoint2f mop1 = new MatOfPoint2f(pt1);
            MatOfPoint2f mop2 = new MatOfPoint2f(pt2);

            Mat perspectiveMat = Imgproc.getPerspectiveTransform(mop1, mop2);
            Imgproc.warpPerspective(src,dst,perspectiveMat,new Size(img.getImgWidth(),img.getImgHeight()));
            // 输出图像路径为空,覆盖输入图像
            imWrite(dst,StringUtils.isEmpty(img.getImgUrlOut()) ? img.getImgUrlInput() : img.getImgUrlOut());
        }catch (Exception e){
            log.info("图像矫正异常:", e);
            return false;
        }
        return true;
    }

    /**
     * 读取图像
     * @param filePath 文件路径,可以包含中文
     * @return Mat
     * @author lqt
     */
    public static Mat imRead(String filePath){
        Mat mat = null;
        try {
            //使用java2D读取图像
            BufferedImage image = ImageIO.read(new FileInputStream(filePath));
            BufferedImage convertToRgbFormatImage = convertToRgbFormat(image);
            byte[] data = ((DataBufferByte) convertToRgbFormatImage.getRaster().getDataBuffer()).getData();
            mat = new Mat(image.getHeight(), convertToRgbFormatImage.getWidth(), CvType.CV_8UC3);
            mat.put(0, 0, data);
            // 小型图片可以输出 查看下
//            HighGui.imshow("book",src);
//            HighGui.waitKey(0);
        } catch (Exception e) {
            log.error("读取图像出现异常:", e);
        }
        return mat;
    }

    /**
     * BufferedImage均转为TYPE_3BYTE_BGR,RGB格式
     *
     * @param input 未知格式BufferedImage图片
     * @return TYPE_3BYTE_BGR格式的BufferedImage图片
     * @author lqt
     */
    public static BufferedImage convertToRgbFormat(BufferedImage input) {
        if (BufferedImage.TYPE_3BYTE_BGR != input.getType()){
            BufferedImage inputRgb = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(input, inputRgb);
            return inputRgb;
        } else{
            return input;
        }
    }

    /**
     * 保存mat到指定路径
     * @param mat 要保存的Mat
     * @param filePath 保存路径
     * @author lqt
     */
    public static void imWrite(Mat mat, String filePath){
        try {
            File file = new File(filePath);
            String fileName = file.getName();
            String fileType = "";
            if(fileName.contains(".")){
                fileType = fileName.substring(fileName.lastIndexOf("."));
            }
            // 将mat转为java的BufferedImage
            MatOfByte mob = new MatOfByte();
            Imgcodecs.imencode(fileType, mat, mob);
            BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(mob.toArray()));
            String type = fileType.substring(fileType.lastIndexOf(".") + 1).toUpperCase();
            ImageIO.write(bufferedImage, type, new File(filePath));
        } catch (Exception e) {
            log.error("保存文件出现异常:", e);
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
JavaOpenCV可以一起使用来实现图像训练。下面是一个简单的示例,演示如何使用JavaOpenCV训练图像分类器。 1. 准备数据集 首先,需要准备训练数据集。数据集应该包含正样本和负样本。正样本应该包含需要分类的对象的图像,而负样本则应该包含与正样本类别不同的图像。这些图像应该是相同大小的,并标记为正样本或负样本。 2. 选择特征 在训练分类器之前,需要选择用于分类的特征。OpenCV提供了几种特征选择方法,例如Haar特征和HOG特征。你可以根据数据集的特性选择最适合的特征。 3. 训练分类器 使用OpenCV的CascadeClassifier类可以训练分类器。下面是一个简单的示例: ``` CascadeClassifier classifier = new CascadeClassifier(); MatOfFloat weights = new MatOfFloat(); MatOfInt labels = new MatOfInt(); List<Mat> images = new ArrayList<>(); List<Integer> categories = new ArrayList<>(); // Load positive samples File[] posFiles = new File("positive/").listFiles(); for (File file : posFiles) { Mat image = Imgcodecs.imread(file.getAbsolutePath()); images.add(image); categories.add(1); } // Load negative samples File[] negFiles = new File("negative/").listFiles(); for (File file : negFiles) { Mat image = Imgcodecs.imread(file.getAbsolutePath()); images.add(image); categories.add(0); } // Train classifier classifier.train(images, labels, weights, 3, 0, new Size(), new Size(), true); classifier.save("classifier.xml"); ``` 这段代码将加载所有正样本和负样本,并使用它们训练分类器。分类器将保存在名为“classifier.xml”的文件中。 4. 测试分类器 训练分类器后,可以使用它来测试新图像。下面是一个简单的示例: ``` CascadeClassifier classifier = new CascadeClassifier(); classifier.load("classifier.xml"); Mat image = Imgcodecs.imread("test.jpg"); MatOfRect detections = new MatOfRect(); classifier.detectMultiScale(image, detections); for (Rect rect : detections.toArray()) { Imgproc.rectangle(image, rect.tl(), rect.br(), new Scalar(0, 255, 0), 3); } Imgcodecs.imwrite("result.jpg", image); ``` 这段代码将加载训练好的分类器,并使用它来检测名为“test.jpg”的图像中的对象。分类器将在图像中检测到对象,并用绿色矩形框标记。结果将保存在名为“result.jpg”的文件中。 这是一个简单的示例,演示了如何使用JavaOpenCV训练图像分类器。你可以根据需要进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_39310051

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值