package ocr;
import net.sourceforge.tess4j.ITesseract;
 import net.sourceforge.tess4j.Tesseract;
 import net.sourceforge.tess4j.TesseractException;import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.IOException;/**
• ocr测试.
• 
• @author huc_逆天
• @since 2021/1/12 17:42
 */
 public class TestTextOcr {
public static void main(String[] args) throws IOException {
 // 创建实例
 ITesseract instance = new Tesseract();
// 设置识别语言
instance.setLanguage(“chi_sim”);
// 设置识别引擎
instance.setOcrEngineMode(1);
// 读取文件
BufferedImage image = ImageIO.read(TestTextOcr.class.getResourceAsStream("/2.jpg"));
 try {// 识别

String result = instance.doOCR(image);
System.out.println(result);} catch (TesseractException e) {
 System.err.println(e.getMessage());
 }}
 }

ide训练,
Java使用Tessdata做OCR图片文字识别的详细思路
更新时间:2021年07月29日 16:58:45 作者:恒生LIGHT云社区
这篇文章主要介绍了Java使用Tessdata做OCR图片文字识别的详细思路,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

说到文字识别,目前除了用一些现成的api,大概就是 tessdata、canvas或者 ocrad等。

1、百度接口用过(可以自己去百度开发者申请,免费的),识别率吧,还可以,但也不是百分百的,但是次数使用有限制,虽然也是够用,但是被限制总是害怕超过不让用。
2、canvas的话是需要对图片做具体的处理,涉及到图片的翻转、置灰、文字间隔的设定等等,成功率很高,但是公司产品验证码是各式各样的,没办法用这种方法处理,所以暂时放弃了。
3、ocrad这个目前用过其.js版本,识别率还是比较低的,具体使用后面会再写一篇文章介绍一下的。
虽然,网上对于 Tessdata的技术介绍文章一搜一大片,但是其实小仙真正用起来的时候,还是费了点周折的。:fendou:

思路:截全图–截取元素图片–处理–识别–输出

注意:图片截取格式统一为.jpg,用png会出问题。

1、添加项目依赖
在项目的pom.xml文件中,添加以下依赖


net.java.dev.jna jna 4.1.0 net.sourceforge.tess4j tess4j 2.0.1 com.sun.jna jna 2、从全图中截取元素图片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 // 元素截图 
public static String[] elementscreenShot(WebElement element )
 throws Exception {
 WrapsDriver wrapsDriver = (WrapsDriver) element;
 long time = System.currentTimeMillis();
// 截图整个页面
File screen = ((TakesScreenshot) wrapsDriver.getWrappedDriver())
        .getScreenshotAs(OutputType.FILE);
BufferedImage img = ImageIO.read(screen);
// 获得元素的高度和宽度
int width = element.getSize().getWidth();
int height = element.getSize().getHeight();
// 创建一个矩形使用上面的高度,和宽度
Rectangle rect = new Rectangle(width, height);
// 得到元素的坐标
Point p = element.getLocation();
BufferedImage dest = img.getSubimage(p.getX(), p.getY(),
        (int) rect.getWidth(), (int) rect.getHeight());
// 存为png格式
ImageIO.write(dest, "png", screen);
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
FileSystemView fsv = FileSystemView.getFileSystemView();
File com = fsv.getHomeDirectory(); // 这便是读取桌面路径的方法了
String url = com.getPath() + "/test";
File location = new File(url);
if (!location.exists()) {
    location.mkdirs();
}

String imgPath = location.getAbsolutePath() + File.separator + "pic_"
        + time + ".jpg";
String cleanPath = location.getAbsolutePath();
//存了原图片和清楚后图片的地址
String[] imgpath = { imgPath, cleanPath };
File targetFile = new File(imgPath);
try {
    FileUtils.copyFile(screen, targetFile);
} catch (IOException e1) {
    e1.printStackTrace();
}
//元素图片路径
return imgpath;
}


3、对截取图片进行处理:灰度化、二值化、去除干扰线等
以下是图像处理的类,其中对于去除干扰线的操作还是慎用,可能会把文字也剔除掉。

public class CleanElementImage {
 /**
 *
 * @param sfile
 * 需要去噪的图像
 * @param destDir
 * 去噪后的图像保存地址
 * @throws IOException
 */
 public static void handlImage(File sfile, String destDir) throws IOException {
 File destF = new File(destDir);
 if (!destF.exists())
 {
 destF.mkdirs();
 }
BufferedImage bufferedImage = ImageIO.read(sfile);
    int h = bufferedImage.getHeight();
    int w = bufferedImage.getWidth();

    // 灰度化
    int[][] gray = new int[w][h];
    for (int x = 0; x < w; x++)
    {
        for (int y = 0; y < h; y++)
        {
            int argb = bufferedImage.getRGB(x, y);
            // 图像加亮(调整亮度识别率非常高)
            int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
            int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
            int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
            if (r >= 255)
            {
                r = 255;
            }
            if (g >= 255)
            {
                g = 255;
            }
            if (b >= 255)
            {
                b = 255;
            }
            gray[x][y] = (int) Math
                    .pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
                            * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
        }
    }

    // 二值化
    int threshold = ostu(gray, w, h);
    BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
    for (int x = 0; x < w; x++)
    {
        for (int y = 0; y < h; y++)
        {
            if (gray[x][y] > threshold)
        {
            gray[x][y] |= 0x00FFFF;
        } else
        {
            gray[x][y] &= 0xFF0000;
        }
        binaryBufferedImage.setRGB(x, y, gray[x][y]);
    }
}

    //去除干扰线条
// for(int y = 1; y < h-1; y++){
 // for(int x = 1; x < w-1; x++){
 // boolean flag = false ;
 // if(isBlack(binaryBufferedImage.getRGB(x, y))){
 // //左右均为空时,去掉此点
 // if(isWhite(binaryBufferedImage.getRGB(x-1, y)) && isWhite(binaryBufferedImage.getRGB(x+1, y))){
 // flag = true;
 // }
 // //上下均为空时,去掉此点
 // if(isWhite(binaryBufferedImage.getRGB(x, y+1)) && isWhite(binaryBufferedImage.getRGB(x, y-1))){
 // flag = true;
 // }
 // //斜上下为空时,去掉此点
 // if(isWhite(binaryBufferedImage.getRGB(x-1, y+1)) && isWhite(binaryBufferedImage.getRGB(x+1, y-1))){
 // flag = true;
 // }
 // if(isWhite(binaryBufferedImage.getRGB(x+1, y+1)) && isWhite(binaryBufferedImage.getRGB(x-1, y-1))){
 // flag = true;
 // }
 // if(flag){
 // binaryBufferedImage.setRGB(x,y,-1);
 // }
 // }
 // }
 // }
 ImageIO.write(binaryBufferedImage, “jpg”, new File(destDir, sfile
 .getName()));}
public static boolean isBlack(int colorInt)
 {
 Color color = new Color(colorInt);
 if (color.getRed() + color.getGreen() + color.getBlue() <= 300)
 {
 return true;
 }
 return false;
 }public static boolean isWhite(int colorInt)
 {
 Color color = new Color(colorInt);
 if (color.getRed() + color.getGreen() + color.getBlue() > 300)
 {
 return true;
 }
 return false;
 }public static int isBlackOrWhite(int colorInt)
 {
 if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730)
 {
 return 1;
 }
 return 0;
 }public static int getColorBright(int colorInt)
 {
 Color color = new Color(colorInt);
 return color.getRed() + color.getGreen() + color.getBlue();
 }public static int ostu(int[][] gray, int w, int h)
 {
 int[] histData = new int[w * h];
 // Calculate histogram
 for (int x = 0; x < w; x++)
 {
 for (int y = 0; y < h; y++)
 {
 int red = 0xFF & gray[x][y];
 histData[red]++;
 }
 }
// Total number of pixels
int total = w * h;

float sum = 0;
for (int t = 0; t < 256; t++){
    sum += t * histData[t];}

float sumB = 0;
int wB = 0;
int wF = 0;

float varMax = 0;
int threshold = 0;

for (int t = 0; t < 256; t++)
{
    wB += histData[t]; // Weight Background
    if (wB == 0) {
        continue;
    }

    wF = total - wB; // Weight Foreground
    if (wF == 0) {
        break;
    }

    sumB += (float) (t * histData[t]);

    float mB = sumB / wB; // Mean Background
    float mF = (sum - sumB) / wF; // Mean Foreground

    // Calculate Between Class Variance
    float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

    // Check if new maximum found
    if (varBetween > varMax)
    {
        varMax = varBetween;
        threshold = t;
    }
}

return threshold;
}
 }


Java技术迷

4、准备识别的语言包
默认是英文(识别字母和数字),如果要识别中文(数字 + 中文),需要制定语言包。
语言包可以指定一个路径,有就可以了。
源码下载地址
可以下载源码,然后到下面这个路径找到语言包,把语言包放到一个路径:
例如:XXX/tessdata/下面。

1
tesseract.js-master.zip\tesseract.js-master\tests\assets\traineddata

5、对图片进行识别

/**
• 图片识别
• @author wangy
• @date 2019-08-26
• @param parameter
 */
 public static String ocrResult(WebElement element ) throws Exception {
FileSystemView fsv = FileSystemView.getFileSystemView();
 File com=fsv.getHomeDirectory(); //这便是读取桌面路径的方法了
 String url = “”;
 String os = System.getProperty(“os.name”);
 //识别系统,找不同的语言包路径
 if (os.indexOf(“Windows”) == -1) {
 url = “/opt/google/”;
 } else {
 url = com.getPath();
 }
 //获取元素截图的路径
 String path[]=Screenshot.elementscreenShot(element);
 //获取未处理的截图路径
 String imgpath=path[0];
 String result = null;
 File imageFile = new File(imgpath);
 //要对图片处理
 CleanElementImage.handlImage(imageFile,path[1]);
 ITesseract instance = new Tesseract();
 //读取语言包的路径地址
 instance.setDatapath(url + File.separator + “test” + File.separator
 + “tessdata”);
 // 默认是英文(识别字母和数字),如果要识别中文(数字 + 中文),需要制定语言包,这里是数字,所以没用语言包
 // instance.setLanguage(“chi_sim”);
 //为了防止没截完图片就识别,做了一个简单的循环
 try{
 String ocrResult=instance.doOCR(imageFile);
 if(imageFile.exists()&&ocrResult!=""){
 result=ocrResult;
 }else {
 while(true){
 Thread.sleep(1000);
 if(imageFile.exists()&&ocrResult!=""){
 result=ocrResult;
 break;
 }
 }
 }
}catch(TesseractException e){
 System.out.println(e.getMessage());
 }
 return result;
 }

  • 这一部分由于项目问题,贴在这里做了特殊处理,原码有一点点区别。大家使用,如果有什么问题,欢迎反馈!

6、成果
这里简单放个对照,图片将就看一下效果,识别结果大概90%以上吧: