java 解决绝对路径中文乱码

本文详细介绍了在Java中如何使用ResourceUtils、URLDecoder及System类进行路径操作和资源定位,包括类路径、当前目录及特定文件路径的获取。通过实例展示了如何处理路径中的特殊字符,如空格和编码。
       String path1 = ResourceUtils.getURL("classpath:static").getPath();
                    String s = path1.replaceAll("%20", " ");

                    String decode = URLDecoder.decode(path1, "utf-8");
                    System.out.println(decode);

                    System.out.println(path1);
                    System.out.println(s);
                    //利用System.getProperty()函数获取当前路径
                    System.out.println(System.setProperty("user.dir", "c:users"));
                    System.out.println(System.getProperty("user.dir"));//user.dir指定了当前的路径

                    //在类中取得类的绝对路径
                    System.out.println(Class.class.getClass().getResource("/").getPath());
                    System.out.println(Thread.currentThread().getContextClassLoader().getResource("./static").getPath());
                    System.out.println(Thread.currentThread().getContextClassLoader().getResource("").getPath());//ClassPath的绝对URI路径
                    System.out.println(Thread.currentThread().getContextClassLoader().getResource(".").getPath());//项目的绝对路径


 

<think>我们正在讨论Java中OpenCV的Imgproc.putText方法出现中文乱码的问题。 根据引用[1]:在没有字体支持的情况下,默认中文显示为问号。因此,我们需要确保提供支持中文的字体文件,并使用正确的方法来加载和设置字体。 解决思路: 1. 加载一个支持中文的字体文件(例如.ttf文件)。 2. 使用Java的Graphics2D在BufferedImage上绘制中文文本,然后再将BufferedImage转换回OpenCV的Mat格式。 3. 或者,使用OpenCV的freetype模块(OpenCV3.0以上版本支持),通过加载字体文件来绘制中文。 方法一:使用Java的Graphics2D(推荐,因为简单且字体支持好) 步骤: - 将Mat转换为BufferedImage - 使用Graphics2D在BufferedImage上绘制中文 - 将BufferedImage转换回Mat 方法二:使用OpenCV的freetype模块(需要OpenCV的contrib模块) 步骤: - 创建FreeType2对象 - 加载字体文件 - 使用该对象的putText方法绘制中文 由于方法一不依赖OpenCV的contrib模块,且兼容性好,这里先展示方法一。 详细代码(方法一): 假设我们有一个Mat对象(图像),我们想在上面添加中文文本。 步骤1:将Mat转换为BufferedImage 步骤2:使用Graphics2D绘制文本 步骤3:将BufferedImage转换回Mat 注意:需要处理颜色通道顺序(OpenCV为BGR,BufferedImage为RGB) 示例代码: ```java import org.opencv.core.Mat; import org.opencv.core.MatOfByte; import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; public class ChineseTextInOpenCV { public static void main(String[] args) { // 加载OpenCV库 System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME); // 假设有一个Mat对象(这里创建一个空白图像) Mat mat = new Mat(480, 640, CvType.CV_8UC3, new Scalar(255,255,255)); // 将Mat转换为BufferedImage BufferedImage bufferedImage = matToBufferedImage(mat); // 在BufferedImage上绘制中文文本 Graphics2D g2d = bufferedImage.createGraphics(); g2d.setColor(Color.BLACK); // 设置字体(确保系统中存在该字体,或者使用字体文件) Font font = new Font("宋体", Font.PLAIN, 24); g2d.setFont(font); g2d.drawString("你好,OpenCV!", 50, 50); g2d.dispose(); // 将BufferedImage转换回Mat Mat result = bufferedImageToMat(bufferedImage); // 保存结果 Imgcodecs.imwrite("output.png", result); } // 将Mat转换为BufferedImage private static BufferedImage matToBufferedImage(Mat mat) { MatOfByte mob = new MatOfByte(); Imgcodecs.imencode(".png", mat, mob); byte[] byteArray = mob.toArray(); BufferedImage bufferedImage = null; try { bufferedImage = ImageIO.read(new ByteArrayInputStream(byteArray)); } catch (IOException e) { e.printStackTrace(); } return bufferedImage; } // 将BufferedImage转换为Mat private static Mat bufferedImageToMat(BufferedImage bufferedImage) { Mat mat = new Mat(bufferedImage.getHeight(), bufferedImage.getWidth(), CvType.CV_8UC3); byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); mat.put(0, 0, data); return mat; } } ``` 注意:上面的转换方法(matToBufferedImage和bufferedImageToMat)可能不是最高效的,但对于简单应用足够了。另外,颜色通道顺序在转换中需要注意,因为OpenCV使用BGR,而BufferedImage使用RGB。上面的代码在保存为png时,Imgcodecs.imencode已经处理了颜色通道(因为Mat是BGR,而png需要RGB?)。实际上,在转换过程中可能需要进行颜色转换。 更精确的转换方法(考虑颜色通道): 我们可以使用OpenCV的Imgproc.cvtColor来转换颜色空间,或者在转换过程中交换R和B通道。 由于时间关系,我们采用另一种转换方式(避免通过文件编码)并处理颜色通道: 另一种将Mat转为BufferedImage的方法(直接操作像素): 这里提供一个更高效的转换方法(但代码稍长): 参考:https://stackoverflow.com/questions/14958643/converting-bufferedimage-to-mat-in-opencv 然而,为了简单起见,我们使用上面的方法。但请注意,上面的方法在转换回Mat时,BufferedImage应该是TYPE_3BYTE_BGR类型,这样数据可以直接放入Mat中。 修改后的bufferedImageToMat方法: ```java private static Mat bufferedImageToMat(BufferedImage bufferedImage) { if (bufferedImage == null) { return null; } // 创建一个与BufferedImage相同大小的Mat,类型为8UC3 Mat mat = new Mat(bufferedImage.getHeight(), bufferedImage.getWidth(), CvType.CV_8UC3); // 获取BufferedImage的数据 byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); // 将数据放入Mat mat.put(0, 0, data); return mat; } ``` 但是,这种方法要求BufferedImage的类型是TYPE_3BYTE_BGR。因此,在将Mat转换为BufferedImage时,我们需要确保生成的BufferedImage是这种类型。 调整matToBufferedImage方法,使其生成TYPE_3BYTE_BGR的BufferedImage: 实际上,我们之前的方法通过编码和解码,可能已经改变了类型。因此,我们采用直接构造BufferedImage的方式: 更好的方法是在不经过编码解码的情况下转换: 这里提供一个直接转换的方法(假设Mat是CV_8UC3类型,即BGR三通道): ```java private static BufferedImage matToBufferedImage(Mat mat) { int type = BufferedImage.TYPE_3BYTE_BGR; int bufferSize = mat.channels() * mat.cols() * mat.rows(); byte[] buffer = new byte[bufferSize]; mat.get(0, 0, buffer); // 获取所有像素 BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type); final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); System.arraycopy(buffer, 0, targetPixels, 0, buffer.length); return image; } ``` 注意:这种方法要求Mat的通道顺序是BGR,且为3通道。如果Mat不是这种类型,需要先转换。 综合以上,我们重新编写转换方法: 由于原始Mat是BGR三通道,我们可以直接使用上述方法。 因此,修改后的两个转换方法如下: ```java private static BufferedImage matToBufferedImage(Mat mat) { if (mat == null || mat.empty()) { return null; } if (mat.channels() != 3) { throw new IllegalArgumentException("Mat must have 3 channels (BGR)"); } int width = mat.cols(); int height = mat.rows(); byte[] data = new byte[width * height * (int) mat.elemSize()]; mat.get(0, 0, data); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); image.getRaster().setDataElements(0, 0, width, height, data); return image; } private static Mat bufferedImageToMat(BufferedImage bufferedImage) { if (bufferedImage == null) { return null; } if (bufferedImage.getType() != BufferedImage.TYPE_3BYTE_BGR) { // 如果BufferedImage不是TYPE_3BYTE_BGR,则转换 BufferedImage newImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = newImage.createGraphics(); g.drawImage(bufferedImage, 0, 0, null); g.dispose(); bufferedImage = newImage; } byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); Mat mat = new Mat(bufferedImage.getHeight(), bufferedImage.getWidth(), CvType.CV_8UC3); mat.put(0, 0, data); return mat; } ``` 这样,我们就能正确转换了。 方法二:使用OpenCV的freetype模块(需要opencv_java和opencv_java_contrib) 步骤: 1. 确保包含opencv_contrib模块,并在项目中添加对应的jar包。 2. 创建`FreeType2`对象,并加载字体文件(.ttf)。 3. 使用`putText`方法绘制中文。 示例代码: ```java import org.opencv.core.*; import org.opencv.freetype.FreeType2; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class ChineseTextWithFreeType { public static void main(String[] args) { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 创建一个空白Mat Mat mat = new Mat(480, 640, CvType.CV_8UC3, new Scalar(255,255,255)); // 创建FreeType2对象 FreeType2 freeType2 = FreeType2.create(); // 加载字体文件(例如simsun.ttc或simhei.ttf) freeType2.loadFontData("simsun.ttc", 0); // 确保字体文件路径正确 // 设置字体大小 int fontHeight = 24; freeType2.setSplitNumber(4); // 设置分割数(可选,用于提高渲染性能) // 绘制中文 freeType2.putText(mat, "你好,OpenCV!", new Point(50, 50), fontHeight, new Scalar(0, 0, 0), -1, 8, false); // 保存 Imgcodecs.imwrite("freetype_output.png", mat); } } ``` 注意:使用freetype模块需要下载OpenCV的额外库(opencv_contrib),并在项目中包含opencv_java_contrib.jar。 总结: 两种方法都可以解决中文乱码问题。方法一使用Java原生绘图,不需要额外的OpenCV模块,但涉及图像格式转换。方法二使用OpenCV的freetype模块,直接操作Mat,但需要contrib模块。 根据项目环境和需求选择合适的方法。 §§相关问题§§ 1. 如何在没有字体文件的情况下,确保Java程序中的中文字体显示正常? 2. 使用OpenCV的freetype模块时,如何处理字体文件路径问题(例如跨平台部署)? 3. 除了中文乱码,Imgproc.putText还可能遇到哪些常见问题?如何解决? </think>### Java Imgproc.putText 方法中文乱码解决方案 OpenCV 的 `Imgproc.putText()` 方法默认不支持中文字符渲染,会导致中文显示为问号(???)或乱码。以下是两种有效的解决方案: --- ### 方法一:使用 Java Graphics2D 绘制中文(推荐) 通过 Java 的原生图形 API 绘制中文文本,然后与 OpenCV Mat 对象相互转换: ```java import org.opencv.core.*; import org.opencv.imgproc.Imgproc; import org.opencv.imgcodecs.Imgcodecs; import java.awt.*; import java.awt.image.BufferedImage; public class ChineseTextDrawer { static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args) { // 读取原始图像 Mat src = Imgcodecs.imread("input.jpg"); // 将Mat转换为BufferedImage BufferedImage bufferedImage = new BufferedImage( src.cols(), src.rows(), BufferedImage.TYPE_3BYTE_BGR ); byte[] data = new byte[src.cols() * src.rows() * (int)src.elemSize()]; src.get(0, 0, data); bufferedImage.getRaster().setDataElements(0, 0, src.cols(), src.rows(), data); // 使用Graphics2D绘制中文 Graphics2D g2d = bufferedImage.createGraphics(); g2d.setColor(Color.WHITE); // 文本颜色 g2d.setFont(new Font("微软雅黑", Font.BOLD, 30)); // 支持中文的字体 g2d.drawString("你好,OpenCV!", 50, 50); // 绘制文本 g2d.dispose(); // 转换回Mat对象 Mat result = new Mat(src.rows(), src.cols(), CvType.CV_8UC3); byte[] resultData = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); result.put(0, 0, resultData); // 保存结果 Imgcodecs.imwrite("output.jpg", result); } } ``` **关键点说明:** 1. 使用 `BufferedImage` 作为中介,利用 Java 原生字体渲染能力 2. 务必指定支持中文的系统字体(如宋体、微软雅黑) 3. 颜色通道处理:OpenCV 使用 BGR 顺序,Java 使用 RGB,需保持一致 4. 性能优化:对于视频流,可复用 `BufferedImage` 对象减少创建开销[^1] --- ### 方法二:使用 OpenCV FreeType 扩展 需要安装 OpenCV contrib 模块中的 `freetype` 组件: ```java import org.opencv.core.*; import org.opencv.freetype.FreeType2; import org.opencv.imgcodecs.Imgcodecs; public class FreeTypeChinese { static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args) { Mat img = Imgcodecs.imread("input.jpg"); // 初始化FreeType2对象 FreeType2 ft2 = FreeType2.create(); // 加载中文字体文件(如simsun.ttc) ft2.loadFontData("/fonts/simsun.ttc", 0); // 设置字体参数 ft2.putText( img, // 目标图像 "中文测试", // 中文文本 new Point(100, 100), // 位置 30, // 字体大小 new Scalar(0, 255, 0), // 颜色(BGR) -1, // 线宽(-1表示填充) Core.LINE_AA, // 抗锯齿 false // 是否翻转 ); Imgcodecs.imwrite("output.jpg", img); } } ``` **依赖配置:** 1. 下载包含 `opencv_contrib` 的 OpenCV 版本(4.x+) 2. 项目中需包含 `opencv_java` 和 `opencv_freetype` 库 3. 字体文件需随应用部署或在代码中指定绝对路径 --- ### 常见问题解决 1. **字体路径问题** 使用 `getClass().getResource("/fonts/simsun.ttc").getPath()` 获取资源路径 2. **字体大小不一致** 通过 `ft2.setSplitNumber(4)` 提高渲染精度 3. **多行文本处理** 需手动计算行高:`ft2.getTextSize("测试", 30, -1, new int[]{0}).height() + 5` 4. **性能优化** 复用 `FreeType2` 对象避免重复加载字体文件 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值