Java使用OpenCV和Tesseract-OCR实现银行卡图片处理与卡号识别

直接上代码,代码每一步都是解释与插图,一步步实现,如果不清楚opencv的环境如何搭建,可上网查或者参见我的前几篇博客,不多说了, java代码如下:

package com.zmx.opencvtest;


import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

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

/**
 * Created by zhangwenchao on 2017/9/27.
 */
public class FirstOpenCVTest {
    static {

        //注意程序运行的时候需要在VM option添加该行 指明opencv的dll文件所在路径
        //-Djava.library.path=$PROJECT_DIR$\opencv\x64
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);   //载入opencv all库
    }

    public static void main(String[] args) throws InterruptedException {

        /**
         * 1. 读取原始图像转换为OpenCV的Mat数据格式
         */

        Mat srcMat = Imgcodecs.imread("E:/srcImage.jpg");  //原始图像


        /**
         * 2. 强原始图像转化为灰度图像
         */
        Mat grayMat = new Mat(); //灰度图像
        Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_RGB2GRAY);

        BufferedImage grayImage =  toBufferedImage(grayMat);

        saveJpgImage(grayImage,"E:/grayImage.jpg");

        System.out.println("保存灰度图像!");


        /**
         * 3、对灰度图像进行二值化处理
         */
        Mat binaryMat = new Mat(grayMat.height(),grayMat.width(),CvType.CV_8UC1);
        Imgproc.threshold(grayMat, binaryMat, 20, 255, Imgproc.THRESH_BINARY);
        BufferedImage binaryImage =  toBufferedImage(binaryMat);
        saveJpgImage(binaryImage,"E:/binaryImage.jpg");
        System.out.println("保存二值化图像!");


        /**
         * 4、图像腐蚀---腐蚀后变得更加宽,粗.便于识别--使用3*3的图片去腐蚀
         */
        Mat destMat = new Mat(); //腐蚀后的图像
        Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
        Imgproc.erode(binaryMat,destMat,element);
        BufferedImage destImage =  toBufferedImage(destMat);
        saveJpgImage(destImage,"E:/destImage.jpg");
        System.out.println("保存腐蚀化后图像!");


        /**
         * 5 图片切割
         */

        //获取截图的范围--从第一行开始遍历,统计每一行的像素点值符合阈值的个数,再根据个数判断该点是否为边界
        //判断该行的黑色像素点是否大于一定值(此处为150),大于则留下,找到上边界,下边界后立即停止
        int a =0, b=0, state = 0;
        for (int y = 0; y < destMat.height(); y++)//行
        {
            int count = 0;
            for (int x = 0; x < destMat.width(); x++) //列
            {
                //得到该行像素点的值
                byte[] data = new byte[1];
                destMat.get(y, x, data);
                if (data[0] == 0)
                    count = count + 1;
            }
            if (state == 0)//还未到有效行
            {
                if (count >= 150)//找到了有效行
                {//有效行允许十个像素点的噪声
                    a = y;
                    state = 1;
                }
            }
            else if (state == 1)
            {
                if (count <= 150)//找到了有效行
                {//有效行允许十个像素点的噪声
                    b = y;
                    state = 2;
                }
            }
        }
        System.out.println("过滤下界"+Integer.toString(a));
        System.out.println("过滤上界"+Integer.toString(b));


        //参数,坐标X,坐标Y,截图宽度,截图长度
        Rect rect = new Rect(0,a,destMat.width(),b - a);
        Mat resMat = new Mat(destMat,rect);
        BufferedImage resImage =  toBufferedImage(resMat);
        saveJpgImage(resImage,"E:/resImage.jpg");
        System.out.println("保存切割后图像!");


        /**
         * 识别-
         */
       /* try {
            Process  pro = Runtime.getRuntime().exec(new String[]{"D:/Program Files (x86)/Tesseract-OCR/tesseract.exe", "E:/resImage.jpg","E:/result"});
            pro.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        try {
            String result =  TesseractOCRUtil.recognizeText(new File("E:/resImage.jpg"));
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }



    /**
     * 将Mat图像格式转化为 BufferedImage
     * @param matrix  mat数据图像
     * @return BufferedImage
     */
    private static BufferedImage toBufferedImage(Mat matrix) {
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (matrix.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
        byte[] buffer = new byte[bufferSize];
        matrix.get(0, 0, buffer); // 获取所有的像素点
        BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
        final byte[] targetPixels = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
        System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
        return image;
    }


    /**
     * 将BufferedImage内存图像保存为图像文件
     * @param image BufferedImage
     * @param filePath  文件名
     */
    private static void saveJpgImage(BufferedImage image, String filePath) {

        try {
            ImageIO.write(image, "jpg", new File(filePath));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }





}

对于图片识别,我单独写了一个工具类,本文也有引用,java代码如下:

package com.zmx.opencvtest;

/**
 * Created by zhangwenchao on 2017/9/28.
 */


import java.io.BufferedReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class TesseractOCRUtil{

    private static final String LANG_OPTION = "-l";
    private static final String EOL = System.getProperty("line.separator");

    /**
     * @param imageFile
     *            传入的图像文件
     * @return 识别后的字符串
     */
    public static String recognizeText(File imageFile) throws Exception {
        /**
         * 设置输出文件的保存的文件目录
         */
        File outputFile = new File(imageFile.getParentFile(), "output");

        StringBuffer strB = new StringBuffer();

        Process  pro = Runtime.getRuntime().exec(
                         new String[]{
                            "D:/Program Files (x86)/Tesseract-OCR/tesseract.exe",
                            imageFile.getPath(),
                            outputFile.getPath()}
                         );
       int w = pro.waitFor();
        if (w == 0) // 0代表正常退出
        {
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    new FileInputStream(outputFile.getAbsolutePath() + ".txt"),
                    "UTF-8"));
            String str;

            while ((str = in.readLine()) != null)
            {
                strB.append(str).append(EOL);
            }
            in.close();
        } else
        {
            String msg;
            switch (w)
            {
                case 1:
                    msg = "Errors accessing files. There may be spaces in your image's filename.";
                    break;
                case 29:
                    msg = "Cannot recognize the image or its selected region.";
                    break;
                case 31:
                    msg = "Unsupported image format.";
                    break;
                default:
                    msg = "Errors occurred.";
            }
            throw new RuntimeException(msg);
        }
        new File(outputFile.getAbsolutePath() + ".txt").delete();
        return strB.toString().replaceAll("\\s*", "");



    }


    public static void main(String[] args) {


        try {
            String result =  recognizeText(new File("E:/resImage.jpg"));
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}


运行结果如下:

1、原始图像(网上不知哪位仁兄的银行卡):


2、保存灰度图像!


3、保存二值化图像!



4、保存腐蚀化后图像!


5、获取的截取图像的上下边界
       过滤上界386
       过滤下界447


6、保存切割后图像!


7、识别的卡号:
         6228482298797273578


搞了一天的时间,总算大功告成,效果还不错!

  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
以下是使用JavaOpenCV4.0.1-1.4.4实现图片中物品数量识别功能的示例代码: ```java import org.opencv.core.*; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class ItemCounter { public static void main(String[] args) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取图片 Mat image = Imgcodecs.imread("item.jpg"); // 转换为灰度图像 Mat gray = new Mat(); Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY); // 二值化图像 Mat binary = new Mat(); Imgproc.threshold(gray, binary, 100, 255, Imgproc.THRESH_BINARY); // 查找轮廓 Mat contours = new Mat(); Imgproc.findContours(binary, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); // 绘制轮廓 Mat result = new Mat(image.size(), CvType.CV_8UC3, new Scalar(0, 0, 0)); Imgproc.drawContours(result, contours, -1, new Scalar(0, 255, 0), 2); // 统计物体数量 int count = contours.toArray().length; System.out.println("物品数量:" + count); // 显示结果 Imgcodecs.imwrite("result.jpg", result); } } ``` 在这个示例代码中,我们首先加载OpenCV库,然后读取一张名为“item.jpg”的图片。接着,我们将图片转换为灰度图像,并对其进行二值化处理,以便于查找轮廓。然后,我们使用OpenCV的findContours函数查找图像中的所有轮廓,并使用drawContours函数绘制这些轮廓。最后,我们统计轮廓的数量,即为物品的数量,并将结果输出到控制台上。同时,我们将绘制轮廓后的结果保存为“result.jpg”文件,并显示出来。 需要注意的是,本示例代码中的图片路径需要根据实际情况进行修改。同时,我们在统计轮廓数量时使用了contours.toArray().length方法,其中contours是一个MatOfPoint类型的对象,toArray()方法将其转换为一个Point类型的数组,length方法返回该数组的长度,即为轮廓的数量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值