1. 程式人生 > >JavaOpencv實現答題卡掃描 銀行卡號碼擷取

JavaOpencv實現答題卡掃描 銀行卡號碼擷取

專案中需要用到opencv,先了解後做仿照別人做了兩個 關於java Opencv 答題卡掃描 銀行卡號碼擷取 的 小程式。


Opencv的安裝下載,就不多介紹,主要是貼程式碼,希望大家能多多指教。


答題卡

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

import java.util.*;

import static org.opencv.core.CvType.CV_8U;
import static org.opencv.imgproc.Imgproc.MORPH_RECT;


/**
 * @author  lsw
 * @email 
[email protected]
*/ public class OpenCv { static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String []args) { String sheet = "D://A4.jpg"; //A4 二值化膨脹後生成的圖片路徑 String results = "E://result.jpg"; String msg = rowsAndCols(sheet, results); System.out.println(msg); } public static void Canny(String oriImg, String dstImg, int threshold) { //裝載圖片 Mat img = Imgcodecs.imread(oriImg); Mat srcImage2 = new Mat(); Mat srcImage3 = new Mat(); Mat srcImage4 = new Mat(); Mat srcImage5 = new Mat(); //圖片變成灰度圖片 Imgproc.cvtColor(img, srcImage2, Imgproc.COLOR_RGB2GRAY); //圖片二值化 Imgproc.adaptiveThreshold(srcImage2, srcImage3, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 255, 1); //確定腐蝕和膨脹核的大小 Mat element = Imgproc.getStructuringElement(MORPH_RECT, new Size(1, 6)); //腐蝕操作 Imgproc.erode(srcImage3, srcImage4, element); //膨脹操作 Imgproc.dilate(srcImage4, srcImage5, element); //Imgcodecs.imwrite("E:/picpool/card/enresults.jpg", srcImage4); //確定每張答題卡的ROI區域 Mat imag_ch1 = srcImage4.submat(new Rect(200, 1065, 1930, 2210)); //識別所有輪廓 Vector<MatOfPoint> chapter1 = new Vector<>(); Imgproc.findContours(imag_ch1, chapter1, new Mat(), 2, 3); Mat result = new Mat(imag_ch1.size(), CV_8U, new Scalar(255)); Imgproc.drawContours(result, chapter1, -1, new Scalar(0), 2); Imgcodecs.imwrite("E://result.jpg", result); //new一個 矩形集合 用來裝 輪廓 List<RectComp> RectCompList = new ArrayList<>(); for (int i = 0; i < chapter1.size(); i++) { Rect rm = Imgproc.boundingRect(chapter1.get(i)); RectComp ti = new RectComp(rm); //把輪廓寬度區間在 50 - 80 範圍內的輪廓裝進矩形集合 if (ti.rm.width > 60 && ti.rm.width < 85) { RectCompList.add(ti); } } //new一個 map 用來儲存答題卡上填的答案 (A\B\C\D) TreeMap<Integer, String> listenAnswer = new TreeMap<>(); //按 X軸 對listenAnswer進行排序 RectCompList.sort((o1, o2) -> { if (o1.rm.x > o2.rm.x) { return 1; } if (o1.rm.x == o2.rm.x) { return 0; } if (o1.rm.x < o2.rm.x) { return -1; } return -1; }); /* 如果精度高,可以通過畫素計算 for (RectComp rc : RectCompList) { int x = RectCompList.get(t).getRm().x - 16; int y = RectCompList.get(t).getRm().y - 94; //計算x軸上的分割 如果超過5題,那麼還會有一個大分割 int xSplit = x/85 /5; //因為第一題 x=21 計算機中題目從0開始算,現實是從1開始 所以+1 int xTitleNum = x/85 + 1; //由於精度問題 x軸會慢慢遞減 遞減到上一個答案去 如果不跨過兩個答案以上,都沒問題 如果答題卡x軸40題左右 會出問題 if(x%85>20){ System.out.println("x軸遞減程度" + x%85); xTitleNum++; } xTitleNum = xTitleNum - xSplit; System.out.println(xTitleNum); } */ //根據 Y軸 確定被選擇答案 (A\B\C\D) for (RectComp rc : RectCompList) { for (int h = 0; h < 7; h++) { if ((rc.rm.contains(new Point(rc.rm.x + 20, 115 + (320 * h))))) { for (int w = 0; w < 4; w++) { if (rc.rm.contains(new Point(55 + (500 * w), rc.rm.y))) { listenAnswer.put(1 + (20 * h) + (5 * w), "A"); } else if (rc.rm.contains(new Point(135 + (500 * w), rc.rm.y))) { listenAnswer.put(2 + (20 * h) + (5 * w), "A"); } else if (rc.rm.contains(new Point(215 + (500 * w), rc.rm.y))) { listenAnswer.put(3 + (20 * h) + (5 * w), "A"); } else if (rc.rm.contains(new Point(300 + (500 * w), rc.rm.y))) { listenAnswer.put(4 + (20 * h) + (5 * w), "A"); } else if (rc.rm.contains(new Point(380 + (500 * w), rc.rm.y))) { listenAnswer.put(5 + (20 * h) + (5 * w), "A"); } } } else if ((rc.rm.contains(new Point(rc.rm.x + 20, 165 + (320 * h))))) { for (int w = 0; w < 4; w++) { if (rc.rm.contains(new Point(55 + (500 * w), rc.rm.y))) { listenAnswer.put(1 + (20 * h) + (5 * w), "B"); } else if (rc.rm.contains(new Point(135 + (500 * w), rc.rm.y))) { listenAnswer.put(2 + (20 * h) + (5 * w), "B"); } else if (rc.rm.contains(new Point(215 + (500 * w), rc.rm.y))) { listenAnswer.put(3 + (20 * h) + (5 * w), "B"); } else if (rc.rm.contains(new Point(300 + (500 * w), rc.rm.y))) { listenAnswer.put(4 + (20 * h) + (5 * w), "B"); } else if (rc.rm.contains(new Point(380 + (500 * w), rc.rm.y))) { listenAnswer.put(5 + (20 * h) + (5 * w), "B"); } } } else if ((rc.rm.contains(new Point(rc.rm.x + 20, 220 + (320 * h))))) { for (int w = 0; w < 4; w++) { if (rc.rm.contains(new Point(55 + (500 * w), rc.rm.y))) { listenAnswer.put(1 + (20 * h) + (5 * w), "C"); } else if (rc.rm.contains(new Point(135 + (500 * w), rc.rm.y))) { listenAnswer.put(2 + (20 * h) + (5 * w), "C"); } else if (rc.rm.contains(new Point(215 + (500 * w), rc.rm.y))) { listenAnswer.put(3 + (20 * h) + (5 * w), "C"); } else if (rc.rm.contains(new Point(300 + (500 * w), rc.rm.y))) { listenAnswer.put(4 + (20 * h) + (5 * w), "C"); } else if (rc.rm.contains(new Point(380 + (500 * w), rc.rm.y))) { listenAnswer.put(5 + (20 * h) + (5 * w), "C"); } } } else if ((rc.rm.contains(new Point(rc.rm.x + 20, 275 + (320 * h))))) { for (int w = 0; w < 4; w++) { if (rc.rm.contains(new Point(55 + (500 * w), rc.rm.y))) { listenAnswer.put(1 + (20 * h) + (5 * w), "D"); } else if (rc.rm.contains(new Point(135 + (500 * w), rc.rm.y))) { listenAnswer.put(2 + (20 * h) + (5 * w), "D"); } else if (rc.rm.contains(new Point(215 + (500 * w), rc.rm.y))) { listenAnswer.put(3 + (20 * h) + (5 * w), "D"); } else if (rc.rm.contains(new Point(300 + (500 * w), rc.rm.y))) { listenAnswer.put(4 + (20 * h) + (5 * w), "D"); } else if (rc.rm.contains(new Point(380 + (500 * w), rc.rm.y))) { listenAnswer.put(5 + (20 * h) + (5 * w), "D"); } } } } } Iterator iter = listenAnswer.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object val = entry.getValue(); System.out.println("第" + key + "題,分數:" + val); } } public static String rowsAndCols(String oriImg, String dstImg) { String msg = ""; Canny(oriImg, dstImg, 50); Mat mat = Imgcodecs.imread(dstImg); msg += "\n行數:" + mat.rows(); msg += "\n列數:" + mat.cols(); msg += "\nheight:" + mat.height(); msg += "\nwidth:" + mat.width(); msg += "\nelemSide:" + mat.elemSize(); //CvType contourSeq = null; return msg; } }

核心程式碼如上圖: 還有另外一個類,也很簡單  我就不貼出來了,大家可以去我的github上面找得到  通過核心程式碼就能理解出大概的思路。

github地址 : https://github.com/shiwenlin/opencv


銀行卡也很簡單最後是也在github上   專案中擷取到銀行卡的圖片,我們也可以用別的外掛轉成數字,