欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java图像识别

程序员文章站 2022-04-05 19:43:18
...

今年软件杯有一个项目是工商图片文字提取。大致的要求就是将天猫给的50张样例图片中的企业名称和注册号提取出来。速度和准确率是这个项目的关键。
我觉得软件杯历年的项目都挺有难度的,很有挑战性。近几年由于人工智能和大数据的飞速发展,项目命题也偏向这方面而不是传统项目了。所以对于程序员来说,除了了解传统项目知识(比如java web三大框架),还要与时俱进,自主学习大数据和人工智能的前沿知识,我认为现在及时转型对个人发展是非常重要的。这可能决定未来的走向,因为在不远的将来,AI和大数据将是主流。
工商图片文字提取涉及到计算机视觉处理,也就是图像识别。本来是想用python写的,会方便点,但是那时候看项目的语言要求,好像不能使用python,只能用java写咯。java图像处理这方面还真不如python。由于底层涉及太多的像素处理等等,我用的是Tesseract-OCR,tess4j这个谷歌的开源框架,识别文字挺好的。能识别一些常用的文字,底层代码都是C++写的,然后用java封装起来,写好方法供上层调用。
这个框架自行百度下载然后配置好就ok了,下面看看我的maven项目结构。
java图像识别
有个特别重要的是tessdata文件夹中要放一些词库,比如英文词库eng.traineddata,中文词库chi_sim.traineddata(要自行下载)等等。如果你想提高这套框架识别的速度和准确率的话,可以去训练对应词库,然后加入到tessdata文件夹下,这样对特定的文字群将会有更好的识别效果。以前是接近0.9秒一张,训练词库以后可以达到0.1秒左右。
另外在识别图片之前,还需要对一些难点图片进行特殊处理,比如翻转,放大缩小,去水印(二值化),灰度处理,图片截取等等,这样预处理对后面的识别有很大的帮助。
总代码:

package Test;

import com.recognition.software.jdeskew.ImageDeskew;
import net.sourceforge.tess4j.ITessAPI;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.Word;
import net.sourceforge.tess4j.util.ImageHelper;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Date;
import java.util.List;

    public class Test {
    static final double MINIMUM_DESKEW_THRESHOLD = 0.05d;
    static ITesseract instance;
    public static void main(String[] args) throws Exception{
        Date data1=new Date();
          //testEn();
         testZh();
        //Wordbyword_extraction();
        Date data2=new Date();
        System.out.println((data2.getTime()-data1.getTime())/1000);
    }

    //使用英文字库 - 识别图片
    public static void testEn() throws Exception {
        File imageFile = new File("pictures/10.png");
        BufferedImage image = ImageIO.read(imageFile);
        //对图片进行处理
        image = flipImage(image);
        image = convertImage(image);
        instance = new Tesseract();//JNA Interface Mapping
        //划定区域
        // x,y是以左上角为原点,width和height是以x,y为基础
        //Rectangle rect = new Rectangle(20, 20, 1500, 200);
        String result = instance.doOCR(image);
        System.out.println(result);
    }

    //使用中文字库 - 识别图片
    public static void testZh() throws Exception {
        File imageFile = new File("pictures/10.png");
        BufferedImage image = ImageIO.read(imageFile);
        //对图片进行处理
        image = flipImage(image);
        image = convertImage(image);
        instance = new Tesseract();//JNA Interface Mapping
        instance.setLanguage("chi_sim");//使用中文字库
        //划定区域
        // x,y是以左上角为原点,width和height是以x,y为基础
        //Rectangle rect = new Rectangle(20, 20, 800, 200);
        String result = instance.doOCR(image);
        System.out.println(result);
    }

    //逐词提取
    public static void Wordbyword_extraction() throws Exception {
        //按照每个字取词
        int pageIteratorLevel = ITessAPI.TessPageIteratorLevel.RIL_SYMBOL;
        File imageFile = new File("pictures/10.png");
        BufferedImage image = ImageIO.read(imageFile);
        //对图片进行处理
        image = flipImage(image);
        image = convertImage(image);
        instance = new Tesseract();//JNA Interface Mapping
        instance.setLanguage("chi_sim");//使用中文字库
        List<Word> result = instance.getWords(image, pageIteratorLevel);
        for (Word word : result) {
            System.out.print(word.toString());
        }
    }

    //对图片进行处理 - 提高识别度
    public static BufferedImage convertImage(BufferedImage image) throws Exception {
        //按指定宽高创建一个图像副本
        image = ImageHelper.getSubImage(image, 0, 0, image.getWidth(), image.getHeight());
        //图像转换成灰度的简单方法 - 黑白处理
        image = ImageHelper.convertImageToGrayscale(image);
        //图像缩放 - 放大n倍图像
        image = ImageHelper.getScaledInstance(image, image.getWidth() * 3,   image.getHeight() * 3);
        return image;
    }

    //处理倾斜
    public static BufferedImage flipImage(BufferedImage image) throws Exception {
        //按指定宽高创建一个图像副本
        image = ImageHelper.getSubImage(image, 0, 0, image.getWidth(), image.getHeight());
             ImageDeskew id = new ImageDeskew(image);
             double imageSkewAngle = id.getSkewAngle(); //获取倾斜角度
               if ((imageSkewAngle > MINIMUM_DESKEW_THRESHOLD || imageSkewAngle < -(MINIMUM_DESKEW_THRESHOLD))) {
                   image = ImageHelper.rotateImage(image, -imageSkewAngle); //纠偏图像
        }
        return image;
        }
        }

去水印

package Test;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.Color;

public class RemoveImageWatermark {
    public static void binaryImage() throws IOException {
        String frompath = "pictures/1.png";
        String topath = "pictures/1.png";
        File file1 = new File(frompath);
        BufferedImage image = ImageIO.read(file1);
        int w=image.getWidth();
        int h=image.getHeight();
        double[][] zuobiao = new double[w][h];
        for(int i=0;i<w;i++)
        {
            for(int j=0;j<h;j++)
            {
                int pixel = image.getRGB(i, j);
                int red = (pixel & 0xff0000) >> 16;
                int green = (pixel & 0xff00) >> 8;
                int blue = (pixel & 0xff);
                //System.out.println(red+" "+green+" "+blue);
                zuobiao[i][j]=(red+green+blue)/3.0;
                if(red>=229&&green>=229&&blue>=229)
                {
                    int white=new Color(255,255,255).getRGB();
                    image.setRGB(i,j,white);
                }
//                if(red>=10&&red<=20&&green>=10&&green<=20&&blue>=10&&blue<=20)
//                {
//                    int cover=new Color(red,green,blue).getRGB();
//                    image.setRGB(i,j,cover);
//                }
//                else
//                {
//                    int white=new Color(255,255,255).getRGB();
//                    image.setRGB(i,j,white);
//                }
            }
        }
        File file2=new File(topath);
        ImageIO.write(image,"png",file2);
    }
    public static void main(String[] args) throws IOException
    {
        new RemoveImageWatermark().binaryImage();
    }
}

图片截取:

package Test;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;

public class Screenshots {
    private String srcpath ;
    private String subpath ;
    private   int x ;
    private   int y ;
    private   int width ;
    private   int height ;
    public  Screenshots() {

    }
    public  Screenshots( int x, int y, int width, int height) {
        this.x = x ;
        this.y = y ;
        this.width = width ;
        this.height = height ;
    }

    public void cut()throws IOException {
        FileInputStream is =   null ;
        ImageInputStream iis = null ;
        try {
            is =new FileInputStream(srcpath);
            Iterator < ImageReader > it=ImageIO.getImageReadersByFormatName("png");
            ImageReader reader = it.next();
            iis = ImageIO.createImageInputStream(is);
            reader.setInput(iis, true ) ;
            ImageReadParam param = reader.getDefaultReadParam();
            Rectangle rect = new Rectangle(x, y, width, height);
            param.setSourceRegion(rect);
            BufferedImage bi=reader.read(0,param);
            ImageIO.write(bi,"png",new File(subpath));
        } finally {
            if (is != null )
                is.close() ;
            if (iis != null )
                iis.close();
        }
    }

    public static void main(String[] args) {
        Screenshots screenshots = new Screenshots(0, 0, 493, 80);
        screenshots.srcpath = "pictures/1.png";
        screenshots.subpath = "pictures/1.png";
        try {
            screenshots.cut();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

加入训练词库:
先将训练好的exercise.traineddata加入tessdata,然后在代码中这样修改就好了

instance.setLanguage("chi_sim+exercise");

训练词库的流程比较复杂,花了我挺多时间的,在这里不多说了,可以去看看训练词库的博客,有一个jTessBoxEditor软件,按照流程一步一步来就好了。
如果有好的图像识别的算法(可以是自己写的),欢迎交流。能理解图像识别原理并能自己写出算法或者运用经典算法的话,还是很不容易的。
详细代码可以访问我的github网址 https://github.com/29DCH/SoftwareCup-ImageTextExtraction

相关标签: java图像识别