当前位置:   article > 正文

springboot整合opencv进行灰度图像与RGB图像互转_nu.pattern.opencv.loadlocally();

nu.pattern.opencv.loadlocally();

问题:

在开发过程中遇到一个问题,需要在图片上加上数据(原卷留痕),由于图片是灰度的,无法进行彩色编辑,需要将灰度图片转成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 直接去加载。

代码如下

  1. package com.zhixinhuixue.opencv;
  2. import java.io.*;
  3. import java.net.JarURLConnection;
  4. import java.net.URL;
  5. import java.util.Enumeration;
  6. import java.util.jar.JarEntry;
  7. import java.util.jar.JarFile;
  8. /**
  9. * @author Biscop
  10. * @create 2023-01-05
  11. * 动态链接库加载类
  12. */
  13. public class NativeLoader {
  14. /**
  15. * 把opencv-460.jar/opencv_java460.dll/opencv_java460.so
  16. * 放在resources下的opencv文件夹中
  17. */
  18. private static final String NATIVE_PATH = "opencv";
  19. /**
  20. * 加载native dll/so
  21. *
  22. * @throws Exception
  23. */
  24. public static void loader() throws Exception {
  25. Enumeration<URL> dir = Thread.currentThread().getContextClassLoader().getResources(NATIVE_PATH);
  26. String systemType = System.getProperty("os.name");
  27. String ext = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so";
  28. while (dir.hasMoreElements()) {
  29. URL url = dir.nextElement();
  30. String protocol = url.getProtocol();
  31. if ("jar".equals(protocol)) {
  32. JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
  33. JarFile jarFile = jarURLConnection.getJarFile();
  34. // 遍历Jar包
  35. Enumeration<JarEntry> entries = jarFile.entries();
  36. while (entries.hasMoreElements()) {
  37. JarEntry jarEntry = entries.nextElement();
  38. String entityName = jarEntry.getName();
  39. if (jarEntry.isDirectory() || !entityName.startsWith(NATIVE_PATH)) {
  40. continue;
  41. }
  42. if (entityName.endsWith(ext)) {
  43. loadJarNative(jarEntry);
  44. }
  45. }
  46. } else if ("file".equals(protocol)) {
  47. File file = new File(url.getPath());
  48. loadFileNative(file, ext);
  49. }
  50. }
  51. }
  52. private static void loadFileNative(File file, String ext) {
  53. if (null == file) {
  54. return;
  55. }
  56. if (file.isDirectory()) {
  57. File[] files = file.listFiles();
  58. if (null != files) {
  59. for (File f : files) {
  60. loadFileNative(f, ext);
  61. }
  62. }
  63. }
  64. if (file.canRead() && file.getName().endsWith(ext)) {
  65. try {
  66. System.load(file.getPath());
  67. System.out.println("加载native文件 :" + file + "成功!!");
  68. } catch (UnsatisfiedLinkError e) {
  69. System.out.println("加载native文件 :" + file + "失败!!请确认操作系统是X86还是X64!!!");
  70. }
  71. }
  72. }
  73. /**
  74. * @param jarEntry
  75. * @throws IOException
  76. * @throws ClassNotFoundException
  77. */
  78. private static void loadJarNative(JarEntry jarEntry) throws IOException, ClassNotFoundException {
  79. File path = new File(".");
  80. String rootOutputPath = path.getAbsoluteFile().getParent() + File.separator;
  81. String entityName = jarEntry.getName();
  82. String fileName = entityName.substring(entityName.lastIndexOf("/") + 1);
  83. File tempFile = new File(rootOutputPath + File.separator + entityName);
  84. if (!tempFile.getParentFile().exists()) {
  85. tempFile.getParentFile().mkdirs();
  86. }
  87. if (tempFile.exists()) {
  88. tempFile.delete();
  89. }
  90. InputStream in = null;
  91. BufferedInputStream reader = null;
  92. FileOutputStream writer = null;
  93. try {
  94. in = NativeLoader.class.getResourceAsStream(entityName);
  95. if (in == null) {
  96. in = NativeLoader.class.getResourceAsStream("/" + entityName);
  97. if (null == in) {
  98. return;
  99. }
  100. }
  101. NativeLoader.class.getResource(fileName);
  102. reader = new BufferedInputStream(in);
  103. writer = new FileOutputStream(tempFile);
  104. byte[] buffer = new byte[1024];
  105. while (reader.read(buffer) > 0) {
  106. writer.write(buffer);
  107. buffer = new byte[1024];
  108. }
  109. } finally {
  110. if (in != null) {
  111. in.close();
  112. }
  113. if (writer != null) {
  114. writer.close();
  115. }
  116. }
  117. try {
  118. System.load(tempFile.getPath());
  119. System.out.println("加载native文件 :" + tempFile + "成功!!");
  120. } catch (UnsatisfiedLinkError e) {
  121. System.out.println("加载native文件 :" + tempFile + "失败!!请确认操作系统是X86还是X64!!!");
  122. }
  123. }
  124. }

启动时加载或者使用时加载都行

  1. package com.zhixinhuixue.opencv;
  2. import nu.pattern.OpenCV;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. * @author Biscop
  6. * @create 2023-01-05
  7. */
  8. @Configuration
  9. public class NativeConfig {
  10. static {
  11. try {
  12. NativeLoader.loader();
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. /**
  18. * 引入加载方式
  19. * <dependency>
  20. * <groupId>org.openpnp</groupId>
  21. * <artifactId>opencv</artifactId>
  22. * <version>4.6.0-0</version>
  23. * </dependency>
  24. */
  25. // static {
  26. // OpenCV.loadLocally();
  27. // }
  28. }

3、引入依赖Maven Central: org.openpnp:opencv:4.6.0-0,已经集成了各个平台的本地库,以及加载本地库的封装类,自己只需要加载就行

调用这个方法OpenCV.loadLocally();
  1. <dependency>
  2. <groupId>org.openpnp</groupId>
  3. <artifactId>opencv</artifactId>
  4. <version>4.6.0-0</version>
  5. </dependency>

我在Linux环境部署时,出现错误 /lib64/libm.so.6: version `GLIBC_2.27' not found,然后我换成3.4.2-2这个版本,但是要注意,有些API会发生变化,要自己去调试。

4、后来和同事讨论,可以通过图片合成的方法,在灰度图像上进行彩色编辑,通过ImageIO就可以实现,无需引入opencv,毕竟这个包很大

  1. //下载图片内容
  2. byte[] data = null;
  3. //处理图片水印
  4. BufferedImage image = null;
  5. try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
  6. Image srcImg = ImageIO.read(new URL(imageUrl));
  7. int imgWidth = srcImg.getWidth(null);
  8. int imgHeight = srcImg.getHeight(null);
  9. logger.info("下载图片{}", imageUrl);
  10. //创建生成图片(尺寸,色彩)
  11. image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
  12. Graphics2D g2d = (Graphics2D) image.getGraphics();
  13. // 写入原图
  14. g2d.drawImage(srcImg, 0, 0, null);
  15. coordinates.forEach(coordinate -> {
  16. g2d.setColor(coordinate.getColorType() == 1 ? Color.red : Color.green);//画笔颜色
  17. g2d.setStroke(new BasicStroke(5.0f));
  18. if (coordinate.getType() == 2) {//正方形
  19. g2d.drawRect(coordinate.getX(), coordinate.getY(), coordinate.getW(), coordinate.getH());//矩形框(原点x坐标,原点y坐标,矩形的长,矩形的宽)
  20. } else {
  21. Font font = new Font("宋体", Font.ITALIC, coordinate.getFontSize()); //水印字体
  22. g2d.setFont(font); //水印字体
  23. g2d.drawString(coordinate.getContent(), coordinate.getX(), coordinate.getY()); //水印位置
  24. }
  25. });
  26. g2d.dispose();
  27. ImageIO.write(image, "jpeg", os);
  28. data = os.toByteArray();
  29. logger.info("合成图片数据");
  30. } catch (IOException e) {
  31. logger.error("原卷编辑失败", e);
  32. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/623253
推荐阅读
相关标签
  

闽ICP备14008679号