ocr之opencv配合paddleocr提高识别率
创始人
2024-12-26 08:04:33
0

背景1:在这篇文章编写之前使用到的工具并不是opencv,而是java原有的工具BufferedImage。但因为在使用过程中会频繁切图,放大,模糊,所以导致的jvm内存使用量巨大,分秒中都在以百兆的速度累加内存空间。这种情况会让程序卡顿,频繁的发生full gc。增加了jvm宕机的不确定性,也给自己埋下了定时炸弹。在不断摸索后一直不能解决这个高内存使用率的问题。而这又关乎到程序的稳定,于是在近日发现并决定使用opencv试一试。

背景2:使用BufferedImage的这段时间里虽然通过不断调整jvm①达到了没有明显卡顿的效果,但是这个坑迟早还是会害人的。
注①:怎样调整的jvm可以看这篇博文。调整参数不复杂,只是通过较小堆大小来做的,但这不是最佳解决方案》》

注:只是通过paddleocr识别,准确度不如人意。但是经过矫正,使用放大模糊图片,就像给paddleocr带上了一副眼睛,成功的提高了识别率。美哉。应上了一首名句(不识庐山这面目,只缘身在此山中),让paddle能看到山就好。

一、识别思路

1. 切割图片

切割的位置以及尺寸大小是通过提前测量好的,也就是可以通过系统内的操作。

2. 放大图片①

放大的尺寸大小非常需要测试。首先放大倍数过小会导致图片不够清除。倍数过大导致图片的文件大小过量,这会导致各种的不方便,尤其是在通过后面要讲的paddleocr识别起来效率降低(识别时间过长)。
注①:测试后计划使用的放大倍数选择8

3. 模糊图片

模糊图片的操作会带使得paddleocr在现有模型下提高识别率。据观测,棱角分明的像素体,识别率是很低的(感觉paddleocr被训练的更容易看懂抽象一般)

4. paddleocr识别

这是最后一步。我在实际使用的场景下应用的是打包的exe程序。exe打包的具体内容可以查看我的这篇博文 》》

二、具体实现介绍

注:如何使用opencv呢?我咨询的大模型【文心一言】。说实话在变成使用方面他还是很在行的。在使用大模型方面我还解除了【抖音】的【豆包】,豆包的效果不是很好,文心还是不错。

opencv如何使用

1. 下载opencv4.6.0版本并进行配置

注:我使用的是460版本, 是在官网进行的下载,直接下载网速会特别慢,于是使用的【迅雷】(通过看广告获取快下的资格)
opencv官网下载页面》》

  • 下载后解压缩并配置环境变量

注:双击解压到你指定的目录
在这里插入图片描述
注:将你的下方路径配置到环境变量

E:\prgrames\opencv\build 

在这里插入图片描述

  • 将下方文件配置到%JAVA_HOME%\bin目录下

在这里插入图片描述

  • 将下方文件配置到项目中

在这里插入图片描述
注:我配置的位置为根目录的/lib/下
在这里插入图片描述

  • 配置maven依赖
     opencv     opencv     460     system     ${project.basedir}/lib/opencv-460.jar  
  • 在java代码中静态加载dll文件
static {    System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } 

由此就可以开始使用了

2. 编写放大模糊裁剪方法
import cn.hutool.core.util.StrUtil; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.Rect; import org.opencv.core.Size; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc;  import java.io.File; import java.io.IOException;  /**  * opencv图片处理  */ public class OpencvPicHanldle {      static {         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);     }      /** 裁剪图片 */     static String CLIP_NAME = "tmp_cp";     /** 放大图片 */     static String ZOOM_NAME = "tmp_zm";     /** 模糊图片 */     static String BLUR_NAME = "tmp_br";      public static File blurPic(String inputFilePath, String picFormat, String tmpDir, int redius) {         // 读取图片         Mat src = Imgcodecs.imread(inputFilePath);         // 创建输出Mat对象         Mat dst = new Mat();         // 定义高斯滤波器的大小,这里使用5x5的核         Size ksize = new Size(redius, redius);         // 定义高斯滤波器的标准差,这里使用0,意味着OpenCV会根据核大小自己计算         double sigmaX = 0;         double sigmaY = 0;         // 应用高斯模糊         Imgproc.GaussianBlur(src, dst, ksize, sigmaX, sigmaY);         File file;         try {             file = File.createTempFile(BLUR_NAME, StrUtil.DOT+picFormat.toLowerCase(), mkdir(tmpDir));         } catch (IOException e) {             throw new RuntimeException(e);         }         // 保存模糊处理后的图片         Imgcodecs.imwrite(file.getAbsolutePath(), dst);         // 显示模糊处理后的图片(如果需要的话)         // HighGui.imshow("Blurred Image", dst);         // HighGui.waitKey(0);         // 释放资源         src.release();         dst.release();         return file;     }      public static File clipPic(String filePath, String picFormat, String tmpDir, int x, int y, int w, int h) {         Mat src = Imgcodecs.imread(filePath);         // 定义切割区域         Rect roi = new Rect(x, y, w, h); // x, y 是起始点坐标,width, height 是切割区域的宽和高         // 获取切割后的图片(子矩阵)         Mat cropped = new Mat(src, roi);         File file;         try {             file = File.createTempFile(CLIP_NAME, StrUtil.DOT+picFormat.toLowerCase(), mkdir(tmpDir));         } catch (IOException e) {             throw new RuntimeException(e);         }         // 保存切割后的图片         Imgcodecs.imwrite(file.getAbsolutePath(), cropped);         // 释放资源         src.release();         cropped.release();         return file;     }      public static File zoomPic(String inputFilePath, String picFormat, String tmpDir, double scale) {         // 读取图片         Mat src = Imgcodecs.imread(inputFilePath);         // 定义放大后的尺寸,这里假设放大两倍         double scaleFactor = scale; // 放大倍数         Size newSize = new Size(src.width() * scaleFactor, src.height() * scaleFactor);         // 创建放大后的Mat对象         Mat dst = new Mat();         // 使用Imgproc.resize()函数放大图片         Imgproc.resize(src, dst, newSize);         File file;         try {             file = File.createTempFile(ZOOM_NAME, StrUtil.DOT+picFormat.toLowerCase(), mkdir(tmpDir));         } catch (IOException e) {             throw new RuntimeException(e);         }         // 保存放大后的图片         Imgcodecs.imwrite(file.getAbsolutePath(), dst);         // 释放资源         src.release();         dst.release();         return file;     }      public static File mkdir(String dirPath) {         File dirFile = new File(dirPath);         if(!dirFile.exists()) {             dirFile.mkdir();         }         return dirFile;     }  }  
3. 对接paddleocr识别
python脚本识别

使用python脚本识别只是为了测试, 实际我在java中使用时用到的为打包后的exe
注:paddleocr的安装详情可查看这篇文章》》
注:安装后可使用脚本进行测试识别图片如下是python的识别脚本
注:使用时命令如:标红处为识别出的内容。

# 参数1为打印识别到的内容 padocr.py C:\main\tmp_zm1295880000423201969.jpg 1 

在这里插入图片描述

from paddleocr import PaddleOCR import sys def recognize(imgPath,printx): 	# 模型路径下必须含有model和params文件 	ocr = PaddleOCR( 					use_angle_cls = True, # 是否加载分类模型 					use_gpu = False# 是否使用gpu 					,show_log=False 					)			 	#img_path = 'C:/Users/Administrator/Desktop/zuoshangjiao/20240129162437.jpg' 	result = ocr.ocr(imgPath, cls = True) 	#print(f"result:{result}") 	for i,line in enumerate(result): 		#print(f"i:{i}, line:{line}") 		for j,item in enumerate(line): 			print(f"item: {item}") 			for k, body in enumerate(item): 				#if k == 1: 					print(f"k:{k}, point:{body[0]}, value:{body[1]}") 					print(printx) 					if printx == "1": 						print(f"{body[0]}, ordinary:{body[1]}") 					else: 						print(f"{body[0]}")  if __name__ == "__main__": 	recognize(sys.argv[1],sys.argv[2]) 
java程序
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.opencv.core.Mat; import org.opencv.core.Rect; import org.opencv.core.Size; 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.File; import java.io.IOException; import java.util.Date;  /**  * paddleocr识别工具类  */ @Slf4j public class PaddleOcrUtil {     /** 临时文件路径 */     public static String tmpPath = System.getProperty("user.dir") + StrUtil.SLASH + "tmpFile" + StrUtil.SLASH + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_FORMAT);      /**      * 创建图片路径      */     static {         File tmpFile = new File(tmpPath);         if(!tmpFile.exists()) {             if(FileUtil.mkParentDirs(tmpPath).exists()) {                 if(tmpFile.mkdir()) {}             }         }     }      /**      * 测试使用, 勿删除      */     public static void testRec() {         String cutPic = "D:\\...\\tmp_cp8579718493577844855.jpg";         String abs = "D:\\...\\tmpFile\\20240328104742415\\acc3";         File a = OpencvPicHanldle.zoomPic(cutPic, "jpg", abs, 8);         File b = OpencvPicHanldle.blurPic(a.getAbsolutePath(), "jpg", abs, 5);         System.out.println(b.getAbsolutePath());     }      /**      * 识别图片      * @param filePath 整图      * @param picFormat 整图类型      * @param x 需要切割的坐标x      * @param y 需要切割的坐标y      * @param w 需要切割的坐标w      * @param h 需要切割的坐标h      * @return      */     public static String rec(String filePath, String picFormat, int x, int y, int w, int h) {         File outputfile;         try{             outputfile = OpencvPicHanldle.clipPic(filePath, picFormat, tmpPath, x, y, w, h);         }catch (Throwable e) {             log.error("rec.err: ", e);             return StrUtil.EMPTY;         }         return rec(outputfile, picFormat);     }      /**      * 识别图片具体方法      * @param outputfile 切割后的图片路径      * @param formatName 图片类型      * @return      */     private static String rec(File outputfile, String formatName) {         File zoomFile = null;         File blurFile = null;         try {             // 放大             zoomFile = OpencvPicHanldle.zoomPic(outputfile.getAbsolutePath(), formatName, tmpPath, 8);             // 模糊化             blurFile = OpencvPicHanldle.blurPic(zoomFile.getAbsolutePath(), formatName, tmpPath, 5);             String console;             try {                 console = ShellUtils.exec(OcrServiceRegistry.execPath, blurFile.getAbsolutePath());             } catch (Exception e) {                 throw new RuntimeException(e);             }             if(StrUtil.isEmpty(console)) return StrUtil.EMPTY;             return console.replaceAll("[\\s\\t\\n\\r]+", "");         }catch (Throwable e) {             e.printStackTrace();             return "";         }finally {             if(outputfile != null) {                 if(!OcrServiceRegistry.saveClipImage) {                     outputfile.delete();                 }             }             if(zoomFile != null) {                 if(!OcrServiceRegistry.saveBlurImage) {                     zoomFile.delete();                 }             }             if(blurFile != null) {                 if(!OcrServiceRegistry.saveBlurImage) {                     blurFile.delete();                 }             }         }     } } 

三、使用opencv注意事项

注:不要有中文路径,否则会报错

  • 不要有中文路径(java程序如jar包所在路径)
  • 不要有中文路径(要处理的图片所在路径)

总结

1. 持之以恒

对不满意的事情想办法让他变得更好。
注:心里一直装着的事终于能够落地了。因为一直装着,也就是放在心上,终归有了解决方案。

2. 换种思路

注:避免死心眼钻牛角尖。就比如死磕jvm调优,但还是于事无补。
注:多尝试新的东西,会带来不小的收获

相关内容

热门资讯

重大通报,金花房卡如何购买西游... 西游联盟房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...
IA解析/牛牛房卡官网皇豪互娱... 皇豪互娱是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:【3329006910】或QQ:332900...
正版授权!牛牛充值房卡超游联盟... 您好!微信超游联盟大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(超游联盟)大厅介绍:...
头条推荐!金花微信链接市场价格... 头条推荐!金花微信链接市场价格表九酷大厅/随意玩/房卡是在哪里买的九酷大厅/随意玩是一款非常受欢迎的...
科技实测!微信金花房卡怎么弄海... 微信游戏中心:海贝之城房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或相关小程...
正规平台有哪些,牛牛房卡制作链... 豌豆互娱是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:【3329006910】或QQ:332900...
正规平台有哪些,牛牛房卡代理海... 您好!微信海航大厅大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(海航大厅)大厅介绍:...
我来教你/如何购买金花房卡神盾... 微信游戏中心:神盾大厅/新天道房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或...
我来教你/斗牛房卡充值新天道/... 今 日消息,新天道/皇豪互娱房卡添加微信33549083 苹果今日发布了 iOS 16.1 正式版更...
玩家攻略,金花房卡批发价卡丁互... 玩家攻略,金花房卡批发价卡丁互娱/正规房卡找谁买卡丁互娱是一款非常受欢迎的游戏,咨询房/卡添加微信:...
IA解析/牛牛房卡游戏代理海米... 微信游戏中心:海米大厅房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或相关小程...
玩家攻略,怎么买斗牛房卡朱雀大... 微信游戏中心:朱雀大厅房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或相关小程...
推荐一款!牛牛房卡制作链接海星... 海星大厅房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...
头条推荐!金花房卡如何购买超游... 头条推荐!金花房卡如何购买超游联盟/房卡购买房间怎么开超游联盟是一款非常受欢迎的游戏,咨询房/卡添加...
我来教你/如何购买金花房卡老神... 微信游戏中心:老神兽/皇豪互众房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或...
正版授权!牛牛房卡出售海豚大厅... 正版授权!牛牛房卡出售海豚大厅/房卡购买房间怎么开Sa9Ix苹果iPhone 17手机即将进入量产阶...
重大通报,如何购买金花房卡龙马... 您好!微信龙马大厅大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(龙马大厅)大厅介绍:...
科技实测!金花房卡官网烛龙大厅... 烛龙大厅/新道游房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 ...
我来教你/金花微信链接市场价格... 我来教你/金花微信链接市场价格表天酷大厅/房卡在哪里购买天酷大厅是一款非常受欢迎的游戏,咨询房/卡添...
ia实测“金花房卡从哪里购买/... 皇豪互娱是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:86909166许多玩家在游戏中会购买房卡来...