Opencv实现身份证OCR识别

article/2025/8/21 10:20:10

Opencv 配置IDEA可参考:https://blog.csdn.net/zwl18210851801/article/details/81075781

opencv位置:

OpencvUtil类:

package com.x.common.utils;import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public  class OpencvUtil {private static final int BLACK = 0;private static final int WHITE = 255;/*** 灰化处理* @return*/public static Mat gray (Mat mat){Mat gray = new Mat();Imgproc.cvtColor(mat, gray, Imgproc.COLOR_BGR2GRAY,1);return gray;}/*** 二值化处理* @return*/public static Mat binary (Mat mat){Mat binary = new Mat();Imgproc.adaptiveThreshold(mat, binary, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 25, 10);return binary;}/*** 模糊处理* @param mat* @return*/public static Mat blur (Mat mat) {Mat blur = new Mat();Imgproc.blur(mat,blur,new Size(5,5));return blur;}/***膨胀* @param mat* @return*/public static Mat dilate (Mat mat,int size){Mat dilate=new Mat();Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(size,size));//膨胀Imgproc.dilate(mat, dilate, element, new Point(-1, -1), 1);return dilate;}/*** 腐蚀* @param mat* @return*/public static Mat erode (Mat mat,int size){Mat erode=new Mat();Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(size,size));//腐蚀Imgproc.erode(mat, erode, element, new Point(-1, -1), 1);return erode;}/*** 边缘检测* @param mat* @return*/public static Mat carry(Mat mat){Mat dst=new Mat();//高斯平滑滤波器卷积降噪Imgproc.GaussianBlur(mat, dst, new Size(3,3), 0);//边缘检测Imgproc.Canny(mat, dst, 50, 150);return dst;}/*** 轮廓检测* @param mat* @return*/public static List<MatOfPoint> findContours(Mat mat){List<MatOfPoint> contours=new ArrayList<>();Mat hierarchy = new Mat();Imgproc.findContours(mat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);return contours;}/*** 清除小面积轮廓* @param mat* @param size* @return*/public static Mat drawContours(Mat mat,int size){List<MatOfPoint> cardContours=OpencvUtil.findContours(mat);for (int i = 0; i < cardContours.size(); i++){double area=OpencvUtil.area(cardContours.get(i));if(area<size){Imgproc.drawContours(mat, cardContours, i, new Scalar( 0, 0, 0),-1 );}}return mat;}/*** 人脸识别* @param mat* @return*/public static Mat face(Mat mat){CascadeClassifier faceDetector = new CascadeClassifier(System.getProperty("user.dir")+"\\opencv\\haarcascades\\haarcascade_frontalface_alt.xml");// 在图片中检测人脸MatOfRect faceDetections = new MatOfRect();//指定人脸识别的最大和最小像素范围Size minSize = new Size(100, 100);Size maxSize = new Size(500, 500);//参数设置为scaleFactor=1.1f, minNeighbors=4, flags=0 以此来增加识别人脸的正确率faceDetector.detectMultiScale(mat, faceDetections, 1.1f, 4, 0, minSize, maxSize);Rect[] rects = faceDetections.toArray();if(rects != null && rects.length == 1){// 在每一个识别出来的人脸周围画出一个方框Rect rect = rects[0];return mat;}else{return null;}}/*** 循环进行人脸识别* */public static Mat faceLoop(Mat src){Mat face=new Mat();//默认人脸识别失败时图像旋转90度int k=90;while (k>0){for(int i=0;i<360/k;i++){//人脸识别face= OpencvUtil.face(src);if(face==null){src = rotate3(src,k);}else{break;}}if(face!=null){break;}else{k=k-30;}}return src;}/*** 剪切身份证区域* @param mat*/public static Mat houghLinesP(Mat begin,Mat mat){//灰度mat=OpencvUtil.gray(mat);//二值化mat=OpencvUtil.binary(mat);//腐蚀mat=OpencvUtil.erode(mat,5);//边缘检测mat=OpencvUtil.carry(mat);//降噪mat=OpencvUtil.navieRemoveNoise(mat,1);//膨胀mat=OpencvUtil.dilate(mat,3);//轮廓检测,清除小的轮廓部分List<MatOfPoint> contours=OpencvUtil.findContours(mat);for(int i=0;i<contours.size();i++){double area=OpencvUtil.area(contours.get(i));if(area<5000){Imgproc.drawContours(mat, contours, i, new Scalar( 0, 0, 0), -1);}}Mat storage = new Mat();Imgproc.HoughLinesP(mat, storage, 1, Math.PI / 180, 10, 0, 10);double[] maxLine = new double[]{0,0,0,0};//获取最长的直线for (int x = 0; x < storage.rows(); x++){double[] vec = storage.get(x, 0);double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];double newLength = Math.sqrt(Math.abs((x1 - x2)* (x1 - x2)+(y1 - y2)* (y1 - y2)));double oldLength = Math.sqrt(Math.abs((maxLine[0] - maxLine[2])* (maxLine[0] - maxLine[2])+(maxLine[1] - maxLine[3])* (maxLine[1] - maxLine[3])));if(newLength>oldLength){maxLine = vec;}}//计算最长线的角度double angle = getAngle(maxLine[0],maxLine[1],maxLine[2],maxLine[3]);//旋转角度mat = rotate3( mat,angle);begin = rotate3( begin,angle);Imgproc.HoughLinesP(mat, storage, 1, Math.PI / 180, 10, 10, 10);List<double[]> lines=new ArrayList<>();//在mat上划线for (int x = 0; x < storage.rows(); x++){double[] vec = storage.get(x, 0);double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];Point start = new Point(x1, y1);Point end = new Point(x2, y2);//获取与图像x边缘近似平行的直线if(Math.abs(start.y-end.y)<5){if(Math.abs(x2-x1)>20){lines.add(vec);}}//获取与图像y边缘近似平行的直线if(Math.abs(start.x-end.x)<5){if(Math.abs(y2-y1)>20){lines.add(vec);}}}//获取最大的和最小的X,Y坐标double maxX=0.0,minX=10000,minY=10000,maxY=0.0;for(int i=0;i<lines.size();i++){double[] vec = lines.get(i);double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];maxX=maxX>x1?maxX:x1;maxX=maxX>x2?maxX:x2;minX=minX>x1?x1:minX;minX=minX>x2?x2:minX;maxY=maxY>y1?maxY:y1;maxY=maxY>y2?maxY:y2;minY=minY>y1?y1:minY;minY=minY>y2?y2:minY;}if(maxX<mat.cols()&&minX>0&&maxY<mat.rows()&&minY>0){List<Point> list=new ArrayList<>();Point point1=new Point(minX+10,minY+10);Point point2=new Point(minX+10,maxY-10);Point point3=new Point(maxX-10,minY+10);Point point4=new Point(maxX-10,maxY-10);list.add(point1);list.add(point2);list.add(point3);list.add(point4);mat=shear(begin,list);}else{mat=begin;}return mat;}/*** 计算角度* @param px1* @param py1* @param px2* @param py2* @return*/public static double  getAngle(double px1, double py1, double px2, double py2) {//两点的x、y值double x = px2-px1;double y = py2-py1;double hypotenuse = Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2));//斜边长度double cos = x/hypotenuse;double radian = Math.acos(cos);//求出弧度double angle = 180/(Math.PI/radian);//用弧度算出角度if (y<0) {angle = -angle;} else if ((y == 0) && (x<0)) {angle = 180;}while (angle<0){angle = angle +90;}return angle;}/*** 累计概率hough变换直线检测* @param mat*/public static Mat houghLines(Mat mat){Mat storage = new Mat();Imgproc.HoughLines(mat, storage, 1, Math.PI / 180, 50, 0, 0, 0, 1);for (int x = 0; x < storage.rows(); x++) {double[] vec = storage.get(x, 0);double rho = vec[0];double theta = vec[1];Point pt1 = new Point();Point pt2 = new Point();double a = Math.cos(theta);double b = Math.sin(theta);double x0 = a * rho;double y0 = b * rho;pt1.x = Math.round(x0 + 1000 * (-b));pt1.y = Math.round(y0 + 1000 * (a));pt2.x = Math.round(x0 - 1000 * (-b));pt2.y = Math.round(y0 - 1000 * (a));if (theta >= 0){Imgproc.line(mat, pt1, pt2, new Scalar(255), 3);}}return mat;}/*** 根据四点坐标截取模板图片* @param mat* @param pointList* @return*/public static Mat shear (Mat mat,List<Point> pointList){int x=minX(pointList);int y=minY(pointList);int xl=xLength(pointList)>mat.cols()-x?mat.cols()-x:xLength(pointList);int yl=yLength(pointList)>mat.rows()-y?mat.rows()-y:yLength(pointList);Rect re=new Rect(x,y,xl,yl);return new Mat(mat,re);}/*** 图片旋转* @param splitImage* @param angle* @return*/public static Mat rotate3(Mat splitImage, double angle){double thera = angle * Math.PI / 180;double a = Math.sin(thera);double b = Math.cos(thera);int wsrc = splitImage.width();int hsrc = splitImage.height();int wdst = (int) (hsrc * Math.abs(a) + wsrc * Math.abs(b));int hdst = (int) (wsrc * Math.abs(a) + hsrc * Math.abs(b));Mat imgDst = new Mat(hdst, wdst, splitImage.type());Point pt = new Point(splitImage.cols() / 2, splitImage.rows() / 2);// 获取仿射变换矩阵Mat affineTrans = Imgproc.getRotationMatrix2D(pt, angle, 1.0);//System.out.println(affineTrans.dump());// 改变变换矩阵第三列的值affineTrans.put(0, 2, affineTrans.get(0, 2)[0] + (wdst - wsrc) / 2);affineTrans.put(1, 2, affineTrans.get(1, 2)[0] + (hdst - hsrc) / 2);Imgproc.warpAffine(splitImage, imgDst, affineTrans, imgDst.size(),Imgproc.INTER_CUBIC | Imgproc.WARP_FILL_OUTLIERS);return imgDst;}/*** 图像直方图处理* @param mat* @return*/public static Mat equalizeHist(Mat mat){Mat dst = new Mat();List<Mat> mv = new ArrayList<>();Core.split(mat, mv);for (int i = 0; i < mat.channels(); i++){Imgproc.equalizeHist(mv.get(i), mv.get(i));}Core.merge(mv, dst);return dst;}/*** 8邻域降噪,又有点像9宫格降噪;即如果9宫格中心被异色包围,则同化* @param pNum 默认值为1*/public static Mat navieRemoveNoise(Mat mat,int pNum) {int i, j, m, n, nValue, nCount;int nWidth = mat.cols();int nHeight = mat.rows();// 如果一个点的周围都是白色的,而它确是黑色的,删除它for (j = 1; j < nHeight - 1; ++j) {for (i = 1; i < nWidth - 1; ++i) {nValue =  (int)mat.get(j, i)[0];if (nValue == 0) {nCount = 0;// 比较以(j ,i)为中心的9宫格,如果周围都是白色的,同化for (m = j - 1; m <= j + 1; ++m) {for (n = i - 1; n <= i + 1; ++n) {if ((int)mat.get(m, n)[0] == 0) {nCount++;}}}if (nCount <= pNum) {// 周围黑色点的个数小于阀值pNum,把该点设置白色mat.put(j, i, WHITE);}} else {nCount = 0;// 比较以(j ,i)为中心的9宫格,如果周围都是黑色的,同化for (m = j - 1; m <= j + 1; ++m) {for (n = i - 1; n <= i + 1; ++n) {if ((int)mat.get(m, n)[0] == 0) {nCount++;}}}if (nCount >= 7) {// 周围黑色点的个数大于等于7,把该点设置黑色;即周围都是黑色mat.put(j, i, BLACK);}}}}return mat;}/*** 连通域降噪* @param pArea 默认值为1*/public static Mat contoursRemoveNoise(Mat mat,double pArea) {//mat=floodFill(mat,mat.new Point(mat.cols()/2,mat.rows()/2),new Color(225,0,0));int i, j, color = 1;int nWidth =  mat.cols(), nHeight = mat.rows();for (i = 0; i < nWidth; ++i) {for (j = 0; j < nHeight; ++j) {if ((int) mat.get(j, i)[0] == BLACK) {//用不同颜色填充连接区域中的每个黑色点//floodFill就是把一个点x的所有相邻的点都涂上x点的颜色,一直填充下去,直到这个区域内所有的点都被填充完为止Imgproc.floodFill(mat, new Mat(), new Point(i, j), new Scalar(color));color++;}}}//统计不同颜色点的个数int[] ColorCount = new int[255];for (i = 0; i < nWidth; ++i) {for (j = 0; j < nHeight; ++j) {if ((int) mat.get(j, i)[0] != 255) {ColorCount[(int) mat.get(j, i)[0] - 1]++;}}}//去除噪点for (i = 0; i < nWidth; ++i) {for (j = 0; j < nHeight; ++j) {if (ColorCount[(int) mat.get(j, i)[0] - 1] <= pArea) {mat.put(j, i, WHITE);}}}for (i = 0; i < nWidth; ++i) {for (j = 0; j < nHeight; ++j) {if ((int) mat.get(j, i)[0] < WHITE) {mat.put(j, i, BLACK);}}}return mat;}/*** Mat转换成BufferedImage** @param matrix*            要转换的Mat* @param fileExtension*            格式为 ".jpg", ".png", etc* @return*/public static BufferedImage Mat2BufImg (Mat matrix, String fileExtension) {MatOfByte mob = new MatOfByte();Imgcodecs.imencode(fileExtension, matrix, mob);byte[] byteArray = mob.toArray();BufferedImage bufImage = null;try {InputStream in = new ByteArrayInputStream(byteArray);bufImage = ImageIO.read(in);} catch (Exception e) {e.printStackTrace();}return bufImage;}/*** BufferedImage转换成Mat** @param original*            要转换的BufferedImage* @param imgType*            bufferedImage的类型 如 BufferedImage.TYPE_3BYTE_BGR* @param matType*            转换成mat的type 如 CvType.CV_8UC3*/public static Mat BufImg2Mat (BufferedImage original, int imgType, int matType) {if (original == null) {throw new IllegalArgumentException("original == null");}if (original.getType() != imgType) {BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);Graphics2D g = image.createGraphics();try {g.setComposite(AlphaComposite.Src);g.drawImage(original, 0, 0, null);} finally {g.dispose();}}DataBufferByte dbi =(DataBufferByte)original.getRaster().getDataBuffer();byte[] pixels = dbi.getData();Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);mat.put(0, 0, pixels);return mat;}/*** 人眼识别* @param mat* @return*/public static List<Point> eye(Mat mat){List<Point> eyeList=new ArrayList<>();CascadeClassifier eyeDetector = new CascadeClassifier(System.getProperty("user.dir")+"\\opencv\\haarcascades\\haarcascade_eye.xml");// 在图片中检测人眼MatOfRect eyeDetections = new MatOfRect();//指定人脸识别的最大和最小像素范围Size minSize = new Size(20, 20);Size maxSize = new Size(30, 30);eyeDetector.detectMultiScale(mat, eyeDetections, 1.1f, 3, 0, minSize, maxSize);Rect[] rects = eyeDetections.toArray();if(rects != null && rects.length == 2){Point point1=new Point(rects[0].x,rects[0].y);eyeList.add(point1);Point point2=new Point(rects[1].x,rects[1].y);eyeList.add(point2);}else{return null;}return eyeList;}/*** 获取轮廓的顶点坐标* @param contour* @return*/public static List<Point> getPointList(MatOfPoint contour){MatOfPoint2f mat2f=new MatOfPoint2f();contour.convertTo(mat2f,CvType.CV_32FC1);RotatedRect rect=Imgproc.minAreaRect(mat2f);Mat points=new Mat();Imgproc.boxPoints(rect,points);return getPoints(points.dump());}/*** 获取轮廓的面积* @param contour* @return*/public static double area (MatOfPoint contour){MatOfPoint2f mat2f=new MatOfPoint2f();contour.convertTo(mat2f,CvType.CV_32FC1);RotatedRect rect=Imgproc.minAreaRect(mat2f);return rect.boundingRect().area();}/*** 获取点坐标集合* @param str* @return*/public  static List<Point> getPoints(String str){List<Point> points=new ArrayList<>();str=str.replace("[","").replace("]","");String[] pointStr=str.split(";");for(int i=0;i<pointStr.length;i++){double x=Double.parseDouble(pointStr[i].split(",")[0]);double y=Double.parseDouble(pointStr[i].split(",")[1]);Point po=new Point(x,y);points.add(po);}return points;}/*** 获取最小的X坐标* @param points* @return*/public  static int minX(List<Point> points){Collections.sort(points, new XComparator(false));return (int)(points.get(0).x>0?points.get(0).x:-points.get(0).x);}/*** 获取最小的Y坐标* @param points* @return*/public  static int minY(List<Point> points){Collections.sort(points, new YComparator(false));return (int)(points.get(0).y>0?points.get(0).y:-points.get(0).y);}/*** 获取最长的X坐标距离* @param points* @return*/public static int xLength(List<Point> points){Collections.sort(points, new XComparator(false));return (int)(points.get(3).x-points.get(0).x);}/*** 获取最长的Y坐标距离* @param points* @return*/public  static int yLength(List<Point> points){Collections.sort(points, new YComparator(false));return (int)(points.get(3).y-points.get(0).y);}//集合排序规则(根据X坐标排序)public static class XComparator implements Comparator<Point> {private boolean reverseOrder; // 是否倒序public XComparator(boolean reverseOrder) {this.reverseOrder = reverseOrder;}public int compare(Point arg0, Point arg1) {if(reverseOrder)return (int)arg1.x - (int)arg0.x;elsereturn (int)arg0.x - (int)arg1.x;}}//集合排序规则(根据Y坐标排序)public static class YComparator implements Comparator<Point> {private boolean reverseOrder; // 是否倒序public YComparator(boolean reverseOrder) {this.reverseOrder = reverseOrder;}public int compare(Point arg0, Point arg1) {if(reverseOrder)return (int)arg1.y - (int)arg0.y;elsereturn (int)arg0.y - (int)arg1.y;}}}

OCRUtil类:

package com.xinjian.x.common.ocr;import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.util.LoadLibs;import java.awt.image.BufferedImage;
import java.io.File;public class OCRUtil {/*** 识别图片信息* @param img* @return*/public static String getImageMessage(BufferedImage img,String language){String result="end";try{ITesseract instance = new Tesseract();File tessDataFolder = LoadLibs.extractTessResources("tessdata");instance.setLanguage(language);instance.setDatapath(tessDataFolder.getAbsolutePath());result = instance.doOCR(img);//System.out.println(result);}catch(Exception e){System.out.println(e.getMessage());}return result;}
}

language为语言包名称eng或者chi_sim,chi_sim语言包可能与jar包不匹配需要注意

语言包下载地址:https://download.csdn.net/download/psdnfu/5187836

<!--OCR  Tesseract-->
<dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>4.1.0</version>
</dependency>
<dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><version>2.0.1</version><exclusions><exclusion><groupId>com.sun.jna</groupId><artifactId>jna</artifactId></exclusion></exclusions>
</dependency>

Main 方法:

package com.xinjian.x.modules.orc;import com.xinjian.x.common.ocr.OCRUtil;
import com.xinjian.x.common.utils.OpencvUtil;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import static com.xinjian.x.common.utils.OpencvUtil.rotate3;
import static com.xinjian.x.common.utils.OpencvUtil.shear;public class OrcTest {static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);//注意程序运行的时候需要在VM option添加该行 指明opencv的dll文件所在路径//-Djava.library.path=$PROJECT_DIR$\opencv\x64}public static void main(String[] args){String path="D:/Users/xinjian09/Desktop/c.jpg";Mat mat= Imgcodecs.imread(path);cardUp(mat);}/*** 身份证反面识别*/public static void cardDown(Mat mat){//灰度mat=OpencvUtil.gray(mat);//二值化mat=OpencvUtil.binary(mat);//腐蚀mat=OpencvUtil.erode(mat,3);//膨胀mat=OpencvUtil.dilate(mat,3);//检测是否有居民身份证字体,若有为正向,若没有则旋转图片for(int i=0;i<4;i++){String temp=temp(mat);if(!temp.contains("居")&&!temp.contains("民")){mat= rotate3(mat,90);}else{break;}}Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/result.jpg", mat);String organization=organization (mat);System.out.print("签发机关是:"+organization);String time=time (mat);System.out.print("有效期限是:"+time);}public static String temp (Mat mat){Point point1=new Point(mat.cols()*0.30,mat.rows()*0.25);Point point2=new Point(mat.cols()*0.30,mat.rows()*0.25);Point point3=new Point(mat.cols()*0.90,mat.rows()*0.45);Point point4=new Point(mat.cols()*0.90,mat.rows()*0.45);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat temp= shear(mat,list);List<MatOfPoint> nameContours=OpencvUtil.findContours(temp);for (int i = 0; i < nameContours.size(); i++){double area=OpencvUtil.area(nameContours.get(i));if(area<100){Imgproc.drawContours(temp, nameContours, i, new Scalar( 0, 0, 0), -1);}}Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/temp.jpg", temp);BufferedImage nameBuffer=OpencvUtil.Mat2BufImg(temp,".jpg");String nameStr=OCRUtil.getImageMessage(nameBuffer,"chi_sim");nameStr=nameStr.replace("\n","");return nameStr;}public static String organization (Mat mat){Point point1=new Point(mat.cols()*0.36,mat.rows()*0.68);Point point2=new Point(mat.cols()*0.36,mat.rows()*0.68);Point point3=new Point(mat.cols()*0.80,mat.rows()*0.80);Point point4=new Point(mat.cols()*0.80,mat.rows()*0.80);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat name= shear(mat,list);List<MatOfPoint> nameContours=OpencvUtil.findContours(name);for (int i = 0; i < nameContours.size(); i++){double area=OpencvUtil.area(nameContours.get(i));if(area<100){Imgproc.drawContours(name, nameContours, i, new Scalar( 0, 0, 0), -1);}}Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/organization.jpg", name);BufferedImage nameBuffer=OpencvUtil.Mat2BufImg(name,".jpg");String nameStr=OCRUtil.getImageMessage(nameBuffer,"chi_sim");nameStr=nameStr.replace("\n","");return nameStr+"\n";}public static String time (Mat mat){Point point1=new Point(mat.cols()*0.38,mat.rows()*0.82);Point point2=new Point(mat.cols()*0.38,mat.rows()*0.82);Point point3=new Point(mat.cols()*0.85,mat.rows()*0.92);Point point4=new Point(mat.cols()*0.85,mat.rows()*0.92);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat time= shear(mat,list);List<MatOfPoint> timeContours=OpencvUtil.findContours(time);for (int i = 0; i < timeContours.size(); i++){double area=OpencvUtil.area(timeContours.get(i));if(area<100){Imgproc.drawContours(time, timeContours, i, new Scalar( 0, 0, 0), -1);}}Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/time.jpg", time);//起始日期Point startPoint1=new Point(0,0);Point startPoint2=new Point(0,time.rows());Point startPoint3=new Point(time.cols()*0.47,0);Point startPoint4=new Point(time.cols()*0.47,time.rows());List<Point> startList=new ArrayList<>();startList.add(startPoint1);startList.add(startPoint2);startList.add(startPoint3);startList.add(startPoint4);Mat start= shear(time,startList);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/start.jpg", start);BufferedImage yearBuffer=OpencvUtil.Mat2BufImg(start,".jpg");String startStr=OCRUtil.getImageMessage(yearBuffer,"eng");startStr=startStr.replace("-","");startStr=startStr.replace(" ","");startStr=startStr.replace("\n","");//截止日期Point endPoint1=new Point(time.cols()*0.47,0);Point endPoint2=new Point(time.cols()*0.47,time.rows());Point endPoint3=new Point(time.cols(),0);Point endPoint4=new Point(time.cols(),time.rows());List<Point> endList=new ArrayList<>();endList.add(endPoint1);endList.add(endPoint2);endList.add(endPoint3);endList.add(endPoint4);Mat end= shear(time,endList);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/end.jpg", end);BufferedImage endBuffer=OpencvUtil.Mat2BufImg(end,".jpg");String endStr=OCRUtil.getImageMessage(endBuffer,"chi_sim");if(!endStr.contains("长")&&!endStr.contains("期")){endStr=OCRUtil.getImageMessage(endBuffer,"eng");endStr=endStr.replace("-","");endStr=endStr.replace(" ","");}return startStr+"-"+endStr;}/*** 身份证正面识别*/public static void cardUp (Mat mat){Mat begin=mat.clone();//截取身份证区域,并校正旋转角度mat = OpencvUtil.houghLinesP(begin,mat);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/houghLinesP.jpg", mat);//循环进行人脸识别,校正图片方向mat=OpencvUtil.faceLoop(mat);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/face.jpg", mat);//灰度mat=OpencvUtil.gray(mat);//二值化mat=OpencvUtil.binary(mat);//腐蚀mat=OpencvUtil.erode(mat,1);//膨胀mat=OpencvUtil.dilate(mat,1);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/bbb.jpg", mat);//获取名称String name=name(mat);System.out.print("姓名是:"+name);//获取性别String sex=sex(mat);System.out.print("性别是:"+sex);//获取民族String nation=nation(mat);System.out.print("民族是:"+nation);//获取出生日期String birthday=birthday(mat);System.out.print("出生日期是:"+birthday);//获取住址String address=address(mat);System.out.print("住址是:"+address);//获取身份证String card=card(mat);System.out.print("身份证号是:"+card);}public static String name(Mat mat){Point point1=new Point(mat.cols()*0.18,mat.rows()*0.11);Point point2=new Point(mat.cols()*0.18,mat.rows()*0.24);Point point3=new Point(mat.cols()*0.4,mat.rows()*0.11);Point point4=new Point(mat.cols()*0.4,mat.rows()*0.24);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat name= shear(mat,list);name=OpencvUtil.drawContours(name,50);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/name.jpg", name);BufferedImage nameBuffer=OpencvUtil.Mat2BufImg(name,".jpg");String nameStr=OCRUtil.getImageMessage(nameBuffer,"chi_sim");nameStr=nameStr.replace("\n","");return nameStr+"\n";}public static String sex(Mat mat){Point point1=new Point(mat.cols()*0.18,mat.rows()*0.25);Point point2=new Point(mat.cols()*0.18,mat.rows()*0.35);Point point3=new Point(mat.cols()*0.25,mat.rows()*0.25);Point point4=new Point(mat.cols()*0.25,mat.rows()*0.35);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat sex= shear(mat,list);sex=OpencvUtil.drawContours(sex,50);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/sex.jpg", sex);BufferedImage sexBuffer=OpencvUtil.Mat2BufImg(sex,".jpg");String sexStr=OCRUtil.getImageMessage(sexBuffer,"chi_sim");sexStr=sexStr.replace("\n","");return sexStr+"\n";}public static String nation(Mat mat){Point point1=new Point(mat.cols()*0.39,mat.rows()*0.25);Point point2=new Point(mat.cols()*0.39,mat.rows()*0.36);Point point3=new Point(mat.cols()*0.55,mat.rows()*0.25);Point point4=new Point(mat.cols()*0.55,mat.rows()*0.36);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat nation= shear(mat,list);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/nation.jpg", nation);BufferedImage nationBuffer=OpencvUtil.Mat2BufImg(nation,".jpg");String nationStr=OCRUtil.getImageMessage(nationBuffer,"chi_sim");nationStr=nationStr.replace("\n","");return nationStr+"\n";}public static String birthday(Mat mat){Point point1=new Point(mat.cols()*0.18,mat.rows()*0.35);Point point2=new Point(mat.cols()*0.18,mat.rows()*0.35);Point point3=new Point(mat.cols()*0.55,mat.rows()*0.48);Point point4=new Point(mat.cols()*0.55,mat.rows()*0.48);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat birthday= shear(mat,list);birthday=OpencvUtil.drawContours(birthday,50);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/birthday.jpg", birthday);//年份Point yearPoint1=new Point(0,0);Point yearPoint2=new Point(0,birthday.rows());Point yearPoint3=new Point(birthday.cols()*0.29,0);Point yearPoint4=new Point(birthday.cols()*0.29,birthday.rows());List<Point> yearList=new ArrayList<>();yearList.add(yearPoint1);yearList.add(yearPoint2);yearList.add(yearPoint3);yearList.add(yearPoint4);Mat year= shear(birthday,yearList);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/year.jpg", year);BufferedImage yearBuffer=OpencvUtil.Mat2BufImg(year,".jpg");String yearStr=OCRUtil.getImageMessage(yearBuffer,"eng");//月份Point monthPoint1=new Point(birthday.cols()*0.44,0);Point monthPoint2=new Point(birthday.cols()*0.44,birthday.rows());Point monthPoint3=new Point(birthday.cols()*0.55,0);Point monthPoint4=new Point(birthday.cols()*0.55,birthday.rows());List<Point> monthList=new ArrayList<>();monthList.add(monthPoint1);monthList.add(monthPoint2);monthList.add(monthPoint3);monthList.add(monthPoint4);Mat month= shear(birthday,monthList);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/month.jpg", month);BufferedImage monthBuffer=OpencvUtil.Mat2BufImg(month,".jpg");String monthStr=OCRUtil.getImageMessage(monthBuffer,"eng");//日期Point dayPoint1=new Point(birthday.cols()*0.69,0);Point dayPoint2=new Point(birthday.cols()*0.69,birthday.rows());Point dayPoint3=new Point(birthday.cols()*0.80,0);Point dayPoint4=new Point(birthday.cols()*0.80,birthday.rows());List<Point> dayList=new ArrayList<>();dayList.add(dayPoint1);dayList.add(dayPoint2);dayList.add(dayPoint3);dayList.add(dayPoint4);Mat day= shear(birthday,dayList);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/day.jpg", day);BufferedImage dayBuffer=OpencvUtil.Mat2BufImg(day,".jpg");String dayStr=OCRUtil.getImageMessage(dayBuffer,"eng");String birthdayStr=yearStr+"年"+monthStr+"月"+dayStr+"日";birthdayStr=birthdayStr.replace("\n","");return birthdayStr+"\n";}public static String address(Mat mat){Point point1=new Point(mat.cols()*0.17,mat.rows()*0.47);Point point2=new Point(mat.cols()*0.17,mat.rows()*0.47);Point point3=new Point(mat.cols()*0.61,mat.rows()*0.76);Point point4=new Point(mat.cols()*0.61,mat.rows()*0.76);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat address= shear(mat,list);address=OpencvUtil.drawContours(address,50);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/address.jpg", address);BufferedImage addressBuffer=OpencvUtil.Mat2BufImg(address,".jpg");return OCRUtil.getImageMessage(addressBuffer,"chi_sim")+"\n";}public static String card(Mat mat){Point point1=new Point(mat.cols()*0.34,mat.rows()*0.75);Point point2=new Point(mat.cols()*0.34,mat.rows()*0.75);Point point3=new Point(mat.cols()*0.89,mat.rows()*0.91);Point point4=new Point(mat.cols()*0.89,mat.rows()*0.91);List<Point> list=new ArrayList<>();list.add(point1);list.add(point2);list.add(point3);list.add(point4);Mat card= shear(mat,list);card=OpencvUtil.drawContours(card,50);Imgcodecs.imwrite("D:/Users/xinjian09/Desktop/card.jpg", card);BufferedImage cardBuffer=OpencvUtil.Mat2BufImg(card,".jpg");return OCRUtil.getImageMessage(cardBuffer,"eng")+"\n";}}

http://chatgpt.dhexx.cn/article/lf83C5m8.shtml

相关文章

身份证OCR实名认证接口

人工智能&#xff0c;身份证&#xff0c;OCR实名验证 一、接口介绍 自动识别及快速提取二代居民身份证正反面所有字段&#xff0c;包括姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期限&#xff0c;实时联网核查校验是否一致。对URL网络图片或base64信息进行…

身份证OCR识别SDK

一、身份证OCR识别SDK应用背景 随着Android、IOS智能手机的普及&#xff0c;5G通信技术的发展&#xff0c;移动互联迎来了爆发式增长&#xff0c;越来越多的公司都推出了自己的移动APP、小程序等应用。这些应用多数都涉及到个人身份证信息的输入认证&#xff08;即实名认证&…

阿里云智能身份证OCR文字识别

智能身份证OCR文字识别 做的项目里面涉及到了身份证识别输入的真实姓名与身份证号码是否匹配功能&#xff0c;于是在阿里云接了智能身份证OCR文字识别API&#xff0c;登录阿里云找到对应的产品&#xff0c;如下图 购买使用然后生成对应的APPcode。 使用的demo有蛮多&#xff0c…

如何用 身份证OCR 接口进行快速开发

最近公司项目有一个身份证文字识别的小需求&#xff0c;想着如果用现成的API就可以大大提高开发效率&#xff0c;在网上的API商店搜索了一番&#xff0c;发现了 APISpace&#xff0c;它里面的身份证OCR非常符合我的开发需求。 身份证OCR&#xff0c;传入身份证照片&#xff0c…

离线身份证OCR识别

离线身份证ocr识别简介 离线身份证ocr识别SDK可支持Android、iOS主流移动操作系统&#xff0c;android平台提供jar包&#xff0c;ios提供静态库.a文件。APP集成离线身份证ocr识别SDK后&#xff0c;用户采用手机、平板电脑对身份证进行拍摄识别即可自动识别身份证信息。 离线身…

身份证OCR识别

本文章来源于自己的学习图像处理以及识别过程中的一些经验&#xff0c;开发了一个OCR识别身份证程序&#xff0c;此程序虽不够完美但有一定的参考价值&#xff0c;CSDN上本人也将提供源代码&#xff0c;对身份证OCR识别整个过程的一个梳理。 程序依赖库&#xff0c;OpenCV3.20…

4款堪称手机神器的APP,每个都可以玩转手机,尤其是第三个

每个人的手机中都会一到两个永远不会卸载的APP&#xff0c;有些APP可以让你在工作中事半功倍&#xff0c;有些可以让你打发时间&#xff0c;并且还可以学习到不同的知识。下面就为大家介绍几个即可以娱乐还可以学习的APP。 一周计划 对于记忆力不好的小伙伴&#xff0c;可以在…

安卓手机软件开发_安卓最牛的下载神器,快收藏起来自己偷偷用

小编一直在想&#xff0c;有木有一款安卓手机电影下载神器让用户在一个手机 App 软件里&#xff0c;既能播放 BT 文件&#xff0c;又能下载网盘文件呢&#xff1f; 谁又不想要一个迅雷百度云网盘资源网站&#xff0c;三合一的手机电影下载神器呢&#xff1f; 其实小编很早就注意…

电脑复制手机粘贴神器-快贴使用方法

首先电脑下载快贴&#xff1a;https://home.clipber.com/index.html?styleorange 然后手机应用市场下载app:快贴&#xff08;安卓苹果都可以下载&#xff09; 回到电脑上把下载的软件安装好&#xff0c;用邮件注册登录&#xff0c;设置&#xff1a; 第二步点右下角任务栏 快…

android代码让手机降温,手机降温神器下载 手机一键降温神器 for Android v1.0.1 安卓版 下载-脚本之家...

对于经常使用手机的朋友来说&#xff0c;肯定手机会非常烫&#xff0c;如果手机持续高温的话就会降低电池的生命周期&#xff0c;所以&#xff0c;为手机降温是非常有必要的。今天小编带来了这款手机一键降温神器就不错&#xff0c;这是一款可以帮助用户快速降低手机温度的工具…

安卓手机垃圾清理神器!彻底清理你的手机垃圾!手机瞬间飞起来!

使用安卓手机的小伙伴经常会遇到一个令人头疼的问题“手机时间一久&#xff0c;各种缓存数据和垃圾文件会越来越多&#xff0c;不及时清理的话&#xff0c;不见占用储存空间&#xff0c;而且还会拖慢手机的运行速度”&#xff0c;大家可能使用过很多垃圾清理软件&#xff0c;清…

android wear阅读器,手机软件有哪些神器?

根据使用场景分类吧&#xff0c;给大家介绍几款私藏的神器&#xff1a; 一、久坐提醒&#xff0c;健康第一 如今&#xff0c;越来越多的事情可以在电脑上完成&#xff0c;学生族和办公族们&#xff0c;一不小心就会在电脑前坐上整一天。久坐带来的一个最直接感受&#xff0c;就…

手机最强Python编程神器,在手机上运行Python

手机编程软件有很多&#xff0c;大部分都很难使用&#xff0c;操作不灵活&#xff0c;甚至不能安装第三方库。 尝试安装了很多Python移动编程软件&#xff0c;发现了很多问题&#xff0c;不是编码效率低就是各种bug。今天&#xff0c;来自一位python编程小哥指导&#xff0c;向…

BatteryHistorian Android手机耗电分析神器

Battery-Historian是谷歌推出的一款专门分析Bugreport的工具&#xff0c;是谷歌2015年I/O大会上推出的一款检测运行在android5.0(Lollipop)及以后版本的设备上电池的相关信息和事件的工具&#xff0c;是一款对于分析手机状态&#xff0c;历史运行情况很好的可视化分析工具。 当…

推荐一款手机app自动点击神器

点击上方"优派编程"选择“加入星标”&#xff0c;第一时间关注原创干货 工具软件下载地址&#xff1a;http://wp.fang1688.cn/ganhuo/931.html 今天小编方包介绍这款app自动点击神器&#xff1a;贝利自动点击器 贝利自动点击器安卓版是一款免费的手机自动连点器,用户…

可以用计算机控制手机的软件,还有这样的神奇软件!让你用PC操控手机的神器...

原标题&#xff1a;还有这样的神奇软件&#xff01;让你用PC操控手机的神器 [PConline 应用]想要用电脑来控制手机&#xff1f;这里有个简单的办法&#xff0c;你还别说&#xff0c;在电脑里刷刷抖音、刷刷朋友圈也是个不错的事儿。但你别误会&#xff0c;这篇文章并不是让你在…

苹果手机温度测试软件,苹果手机测温神器上线啦!

前几日看到有位刚做了几个月的宝妈&#xff0c;在群里说她家小孩发烧&#xff0c;她在家里用水银温度计测温的时候&#xff0c;宝宝不配合又哭又闹&#xff0c;她很怕宝宝把水银弄碎&#xff0c;但是又没有办法只能强行给宝宝完成体温测量。真是心疼又心酸。 日常生活中宝妈用水…

手机编程神器Pydroid3的简单使用——Python和c语言

一.简单介绍&#xff1a; Pydroid3手机版是一款手机编程软件,包含强大的编译器,轻松在手机上运行和调试Python程序。软件拥有离线Python 3.8解释器&#xff0c;运行程序不需要互联网&#xff0c;既是没有网也能够完美运行&#xff0c;Pydroid 3是最易于使用和功能强大的手机的…

分享两款手机优化神器!

我们手机用久了难免会有卡顿、存储空间不足、耗电严重等现象&#xff0c;虽然与手机老化有关&#xff0c;但很多情况是由于各种应用使用过程产生的垃圾文件越积越多又无法正常清理造成的&#xff0c;Android手机尤为严重。小编今天找到一款很强的手机清理工具&#xff0c;仅其中…

分享几个实用电脑手机神器

分享一&#xff1a;阿里小号 阿里小号是一款让你轻松拥有小号的应用。您只需要使用您的淘宝账号登录即可使用。支持申请两个小号&#xff08;生活号、好友号&#xff09;。申请的第一个月似乎是免费的。 如果使用时间较长&#xff0c;每年需要缴纳20元的费用。在选择小号的时候…