赞
踩
在开发过程中遇到一个问题,需要在图片上加上数据(原卷留痕),由于图片是灰度的,无法进行彩色编辑,需要将灰度图片转成RGB图片,才能进行彩色编辑,于是想到用opencv进行处理。
参考SpringBoot使用OpenCV总结 - ksfzhaohui的个人页面 - OSCHINA - 中文开源技术交流社区
灰度图片处理前 位深度8 无法进行彩色留痕
转成RGB图片后 位深度24 可以在上面进行彩色留痕
1、最开始我是去OpenCv官网OpenCV - Browse Files at SourceForge.net 下载的文件解压,使用相对路径加载dll文件,在test环境中测试成功了,后来启动springboot服务后,却报错了
Caused by: java.lang.UnsatisfiedLinkError
因为springboot服务会打成jar包运行,通过system.load并不能加载成功;如果使用绝对路径,就可以加载成功
2、由于我们使用的k8s管理微服务,使用绝对路径加载文件肯定不合适,然后参考其他博主的方案,
最后采用的方式是把读取的库文件,存放到系统的一个临时文件夹下,然后拿到库文件的绝对路径,这样就可以通过 system.load 直接去加载。
代码如下
- package com.zhixinhuixue.opencv;
-
- import java.io.*;
- import java.net.JarURLConnection;
- import java.net.URL;
- import java.util.Enumeration;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
-
- /**
- * @author Biscop
- * @create 2023-01-05
- * 动态链接库加载类
- */
- public class NativeLoader {
-
- /**
- * 把opencv-460.jar/opencv_java460.dll/opencv_java460.so
- * 放在resources下的opencv文件夹中
- */
- private static final String NATIVE_PATH = "opencv";
-
- /**
- * 加载native dll/so
- *
- * @throws Exception
- */
- public static void loader() throws Exception {
- Enumeration<URL> dir = Thread.currentThread().getContextClassLoader().getResources(NATIVE_PATH);
- String systemType = System.getProperty("os.name");
- String ext = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so";
- while (dir.hasMoreElements()) {
- URL url = dir.nextElement();
- String protocol = url.getProtocol();
- if ("jar".equals(protocol)) {
- JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
- JarFile jarFile = jarURLConnection.getJarFile();
- // 遍历Jar包
- Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- JarEntry jarEntry = entries.nextElement();
- String entityName = jarEntry.getName();
- if (jarEntry.isDirectory() || !entityName.startsWith(NATIVE_PATH)) {
- continue;
- }
- if (entityName.endsWith(ext)) {
- loadJarNative(jarEntry);
- }
- }
- } else if ("file".equals(protocol)) {
- File file = new File(url.getPath());
- loadFileNative(file, ext);
- }
-
- }
- }
-
- private static void loadFileNative(File file, String ext) {
- if (null == file) {
- return;
- }
- if (file.isDirectory()) {
- File[] files = file.listFiles();
- if (null != files) {
- for (File f : files) {
- loadFileNative(f, ext);
- }
- }
- }
- if (file.canRead() && file.getName().endsWith(ext)) {
- try {
- System.load(file.getPath());
- System.out.println("加载native文件 :" + file + "成功!!");
- } catch (UnsatisfiedLinkError e) {
- System.out.println("加载native文件 :" + file + "失败!!请确认操作系统是X86还是X64!!!");
- }
- }
- }
-
- /**
- * @param jarEntry
- * @throws IOException
- * @throws ClassNotFoundException
- */
- private static void loadJarNative(JarEntry jarEntry) throws IOException, ClassNotFoundException {
- File path = new File(".");
- String rootOutputPath = path.getAbsoluteFile().getParent() + File.separator;
- String entityName = jarEntry.getName();
- String fileName = entityName.substring(entityName.lastIndexOf("/") + 1);
- File tempFile = new File(rootOutputPath + File.separator + entityName);
- if (!tempFile.getParentFile().exists()) {
- tempFile.getParentFile().mkdirs();
- }
- if (tempFile.exists()) {
- tempFile.delete();
- }
- InputStream in = null;
- BufferedInputStream reader = null;
- FileOutputStream writer = null;
- try {
- in = NativeLoader.class.getResourceAsStream(entityName);
- if (in == null) {
- in = NativeLoader.class.getResourceAsStream("/" + entityName);
- if (null == in) {
- return;
- }
- }
- NativeLoader.class.getResource(fileName);
- reader = new BufferedInputStream(in);
- writer = new FileOutputStream(tempFile);
- byte[] buffer = new byte[1024];
-
- while (reader.read(buffer) > 0) {
- writer.write(buffer);
- buffer = new byte[1024];
- }
- } finally {
- if (in != null) {
- in.close();
- }
- if (writer != null) {
- writer.close();
- }
- }
- try {
- System.load(tempFile.getPath());
- System.out.println("加载native文件 :" + tempFile + "成功!!");
- } catch (UnsatisfiedLinkError e) {
- System.out.println("加载native文件 :" + tempFile + "失败!!请确认操作系统是X86还是X64!!!");
- }
-
- }
-
-
- }
启动时加载或者使用时加载都行
- package com.zhixinhuixue.opencv;
-
- import nu.pattern.OpenCV;
- import org.springframework.context.annotation.Configuration;
-
- /**
- * @author Biscop
- * @create 2023-01-05
- */
- @Configuration
- public class NativeConfig {
-
- static {
- try {
- NativeLoader.loader();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 引入加载方式
- * <dependency>
- * <groupId>org.openpnp</groupId>
- * <artifactId>opencv</artifactId>
- * <version>4.6.0-0</version>
- * </dependency>
- */
- // static {
- // OpenCV.loadLocally();
- // }
- }
3、引入依赖Maven Central: org.openpnp:opencv:4.6.0-0,已经集成了各个平台的本地库,以及加载本地库的封装类,自己只需要加载就行
调用这个方法OpenCV.loadLocally();
- <dependency>
- <groupId>org.openpnp</groupId>
- <artifactId>opencv</artifactId>
- <version>4.6.0-0</version>
- </dependency>
我在Linux环境部署时,出现错误 /lib64/libm.so.6: version `GLIBC_2.27' not found,然后我换成3.4.2-2这个版本,但是要注意,有些API会发生变化,要自己去调试。
4、后来和同事讨论,可以通过图片合成的方法,在灰度图像上进行彩色编辑,通过ImageIO就可以实现,无需引入opencv,毕竟这个包很大
- //下载图片内容
- byte[] data = null;
- //处理图片水印
- BufferedImage image = null;
- try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
- Image srcImg = ImageIO.read(new URL(imageUrl));
- int imgWidth = srcImg.getWidth(null);
- int imgHeight = srcImg.getHeight(null);
- logger.info("下载图片{}", imageUrl);
- //创建生成图片(尺寸,色彩)
- image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
- Graphics2D g2d = (Graphics2D) image.getGraphics();
- // 写入原图
- g2d.drawImage(srcImg, 0, 0, null);
- coordinates.forEach(coordinate -> {
- g2d.setColor(coordinate.getColorType() == 1 ? Color.red : Color.green);//画笔颜色
- g2d.setStroke(new BasicStroke(5.0f));
- if (coordinate.getType() == 2) {//正方形
- g2d.drawRect(coordinate.getX(), coordinate.getY(), coordinate.getW(), coordinate.getH());//矩形框(原点x坐标,原点y坐标,矩形的长,矩形的宽)
- } else {
- Font font = new Font("宋体", Font.ITALIC, coordinate.getFontSize()); //水印字体
- g2d.setFont(font); //水印字体
- g2d.drawString(coordinate.getContent(), coordinate.getX(), coordinate.getY()); //水印位置
- }
- });
- g2d.dispose();
-
- ImageIO.write(image, "jpeg", os);
- data = os.toByteArray();
- logger.info("合成图片数据");
- } catch (IOException e) {
- logger.error("原卷编辑失败", e);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。