基于Opencv实现车牌图片识别系统

简介: • 这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目• 包含车牌识别、人脸识别等功能,贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点• java语言的深度学习项目,在整个开源社区来说都相对较少;• 拥有完整的训练过程、检测、识别过程的开源项目更是少之又少!!


    • 这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目
    • 包含车牌识别、人脸识别等功能,贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点
    • java语言的深度学习项目,在整个开源社区来说都相对较少;
    • 拥有完整的训练过程、检测、识别过程的开源项目更是少之又少!!

    包含功能

      • 蓝、绿、黄车牌检测及车牌号码识别
      • 网上常见的轮廓提取车牌算法JAVA实现
      • hsv色彩分割提取车牌算法JAVA实现
      • 基于svm算法的车牌检测训练JAVA实现
      • 基于ann算法的车牌号码识别训练JAVA实现
      • 人脸检测 接下来将实现人脸识别
      • 图片处理工具,目前实现了HSV色彩切割,后续将添加更多使用的图片处理工具,用于辅助算法优化

      操作界面

      软件版本

        • jdk 1.8.61+
        • maven 3.0+
        • opencv 4.0.1 ; javacpp1.4.4;opencv-platform 4.0.1-1.4.4
        • spring boot 2.1.5.RELEASE
        • yx-image-recognition 1.0.0版本

        软件架构

          • B/S 架构,前端html + requireJS,后端java
          • 数据库使用 sqlite3.0
          • 接口文档使用swagger 2.0

          参考文档

            相关功能实现展示:

            image.gif编辑

            车牌识别

            image.gif编辑

            黄牌识别

            image.gif编辑

            绿牌识别

            image.gif编辑

            夜间识别

            image.gif编辑

            图片提取工具

            image.gif编辑

            image.gif编辑

            人脸识别

            image.gif编辑

            训练

            image.gif编辑

            接口文档

            image.gif编辑

            车牌检测过程

            高斯模糊:

            image.gif编辑

            图像灰度化:

            image.gif编辑

            Sobel 算子:

            image.gif编辑

            图像二值化:

            image.gif编辑

            图像闭操作:

            image.gif编辑

            二值图像降噪:

            image.gif编辑

            提取外部轮廓:

            image.gif编辑

            外部轮廓筛选:

            image.gif编辑

            切图:

            image.gif编辑

            重置切图尺寸:

            image.gif编辑

            车牌检测结果:

            图片车牌文字识别过程

            车牌检测结果:

            image.gif编辑

            图片车牌文字识别过程

            debug_char_threshold

            image.gif编辑

            debug_char_clearLiuDing

            image.gif编辑

            debug_specMat

            image.gif编辑

            debug_chineseMat

            image.gif编辑

            debug_char_auxRoi

            image.gif编辑

            部门核心代码:

            package com.yuxue.service.impl;
            import java.io.File;
            import java.util.List;
            import java.util.Map;
            import java.util.Set;
            import java.util.Vector;
            import org.opencv.core.Core;
            import org.opencv.core.CvType;
            import org.opencv.core.Mat;
            import org.opencv.imgcodecs.Imgcodecs;
            import org.opencv.imgproc.Imgproc;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.stereotype.Service;
            import org.springframework.transaction.annotation.Propagation;
            import org.springframework.transaction.annotation.Transactional;
            import com.alibaba.druid.util.StringUtils;
            import com.alibaba.fastjson.JSONObject;
            import com.google.common.collect.Lists;
            import com.google.common.collect.Maps;
            import com.google.common.collect.Sets;
            import com.yuxue.constant.Constant;
            import com.yuxue.entity.PlateFileEntity;
            import com.yuxue.entity.TempPlateFileEntity;
            import com.yuxue.enumtype.PlateColor;
            import com.yuxue.mapper.PlateFileMapper;
            import com.yuxue.mapper.TempPlateFileMapper;
            import com.yuxue.service.PlateService;
            import com.yuxue.util.FileUtil;
            import com.yuxue.util.GenerateIdUtil;
            import com.yuxue.util.PlateUtil;
            @Service
            public class PlateServiceImpl implements PlateService {
                @Autowired
                private PlateFileMapper plateFileMapper;
                @Autowired
                private TempPlateFileMapper tempPlateFileMapper;
                static {
                    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
                }
                @Override
                @Transactional(propagation = Propagation.REQUIRED)
                public Object refreshFileInfo() {
                    File baseDir = new File(Constant.DEFAULT_DIR);
                    if(!baseDir.exists() || !baseDir.isDirectory()) {
                        return null;
                    }
                    List<TempPlateFileEntity> resultList = Lists.newArrayList();
                    // 获取baseDir下第一层级的目录, 仅获取文件夹,不递归子目录,遍历
                    List<File> folderList = FileUtil.listFile(baseDir, ";", false);
                    folderList.parallelStream().forEach(folder -> {
                        if(!folder.getName().equals("temp")) {
                            // 遍历每一个文件夹, 递归获取文件夹下的图片
                            List<File> imgList = FileUtil.listFile(folder, Constant.DEFAULT_TYPE, true);
                            if(null != imgList && imgList.size() > 0) {
                                imgList.parallelStream().forEach(n->{
                                    TempPlateFileEntity entity = new TempPlateFileEntity();
                                    entity.setFilePath(n.getAbsolutePath().replaceAll("\\\\", "/"));
                                    entity.setFileName(n.getName());
                                    entity.setFileType(n.getName().substring(n.getName().lastIndexOf(".") + 1));
                                    resultList.add(entity);
                                });
                            }
                        }
                    });
                    tempPlateFileMapper.turncateTable();
                    tempPlateFileMapper.batchInsert(resultList);
                    tempPlateFileMapper.updateFileInfo();
                    return 1;
                }
                @Override
                public Object recognise(String filePath, boolean reRecognise) {
                    filePath = filePath.replaceAll("\\\\", "/");
                    File f = new File(filePath);
                    PlateFileEntity entity = null;
                    Map<String, Object> paramMap = Maps.newHashMap();
                    paramMap.put("filePath", filePath);
                    List<PlateFileEntity> list= plateFileMapper.selectByCondition(paramMap);
                    if(null == list || list.size() <= 0) {
                        if(FileUtil.checkFile(f)) {
                            entity = new PlateFileEntity();
                            entity.setFileName(f.getName());
                            entity.setFilePath(f.getAbsolutePath().replaceAll("\\\\", "/"));
                            entity.setFileType(f.getName().substring(f.getName().lastIndexOf(".") + 1));
                            plateFileMapper.insertSelective(entity);
                        }
                        reRecognise = true;
                    } else {
                        entity = list.get(0);
                    }
                    if(reRecognise || StringUtils.isEmpty(entity.getTempPath())) {
                        doRecognise(f, entity); // 重新识别
                        entity = plateFileMapper.selectByPrimaryKey(entity.getId()); // 重新识别之后,重新获取一下数据
                    }
                    // 查询debug文件
                    if(!StringUtils.isEmpty(entity.getTempPath())) {
                        Vector<String> debugFiles = new Vector<String>();
                        FileUtil.getFiles(entity.getTempPath(), debugFiles);
                        entity.setDebugFiles(debugFiles);
                    }
                    return entity;
                }
                @Override
                public Object recogniseAll() {
                    // 查询到还没有进行车牌识别的图片
                    List<PlateFileEntity> list = plateFileMapper.getUnRecogniseList();
                    list.parallelStream().forEach(n->{
                        File f = new File(n.getFilePath());
                        if(FileUtil.checkFile(f)) {
                            doRecognise(f, n);
                        }
                    });
                    return 1;
                }
                /**
                 * 单张图片 车牌识别
                 * 拷贝文件到临时目录
                 * 过程及结果更新数据库
                 * @param f
                 * @param e
                 * @return
                 */
                public Object doRecognise(File f, PlateFileEntity e) {
                    if(!f.exists()) {
                        return null;
                    }
                    String ct = GenerateIdUtil.getStrId();
                    String targetPath = Constant.DEFAULT_TEMP_DIR + ct + (f.getName().substring(f.getName().lastIndexOf(".")));
                    FileUtil.copyAndRename(f.getAbsolutePath(), targetPath); // 拷贝文件并且重命名
                    // 创建临时目录, 存放过程图片
                    String tempPath =  Constant.DEFAULT_TEMP_DIR + ct + "/";
                    FileUtil.createDir(tempPath);
                    e.setTempPath(tempPath);
                    Boolean debug = false;
                    Vector<Mat> dst = new Vector<Mat>();
                    PlateUtil.getPlateMat(targetPath, dst, debug, tempPath);
                    Set<String> plates = Sets.newHashSet();
                    dst.stream().forEach(inMat -> {
                        PlateColor color = PlateUtil.getPlateColor(inMat, true, false, tempPath);
                        String plate = PlateUtil.charsSegment(inMat, color, debug, tempPath);
                        plates.add("<" + plate + "," + color.desc + ">");
                    });
                    e.setRecoPlate(plates.toString());
                    new File(targetPath).delete();  // 删除拷贝的临时文件
                    plateFileMapper.updateByPrimaryKeySelective(e);
                    return 1;
                }
                @Override
                public Object getImgInfo(String imgPath) {
                    Map<String, Object> result = Maps.newHashMap();
                    String ct = GenerateIdUtil.getStrId();
                    File f = new File(imgPath);
                    if(f.exists()) {
                        String targetPath = Constant.DEFAULT_TEMP_DIR + ct + (f.getName().substring(f.getName().lastIndexOf(".")));
                        FileUtil.copyAndRename(f.getAbsolutePath(), targetPath);
                        result.put("targetPath", targetPath);   // 返回临时路径给前端
                        // 获取图片的基本信息
                        Mat inMat = Imgcodecs.imread(targetPath);
                        result.put("rows", inMat.rows());
                        result.put("cols", inMat.cols());
                    }
                    return result;
                }
                @Override
                public Object getHSVValue(String imgPath, Integer row, Integer col) {
                    Map<String, Object> result = Maps.newHashMap();
                    Mat inMat = Imgcodecs.imread(imgPath);
                    double[] rgb = inMat.get(row, col);
                    result.put("RGB", JSONObject.toJSONString(rgb));
                    Mat dst = new Mat(inMat.rows(), inMat.cols(), CvType.CV_32FC3);
                    Imgproc.cvtColor(inMat, dst, Imgproc.COLOR_BGR2HSV); // 转到HSV空间进行处理
                    double[] hsv = dst.get(row, col);
                    result.put("HSV", (int)hsv[0] + ", " + (int)hsv[1] + ", " + (int)hsv[2]);
                    return result;
                }
            }

            image.gif

            package com.znz.service.impl;
            import com.znz.service.PlateTypeService;
            import com.znz.entity.PlateTypeEntity;
            import com.znz.mapper.PlateTypeMapper;
            import com.github.pagehelper.PageHelper;
            import com.github.pagehelper.PageInfo;
            import org.springframework.transaction.annotation.Transactional;
            import org.springframework.transaction.annotation.Propagation;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.stereotype.Service;
            import java.util.HashMap;
            import java.util.Map;
            import java.util.List;
            /**
             * 服务实现层
             * @author znz
             * @date 2020-09-30T16:54:41.823
             */
            @Service
            public class PlateTypeServiceImpl implements PlateTypeService {
                @Autowired
                private PlateTypeMapper plateTypeMapper;
                @Override
                public PlateTypeEntity getByPrimaryKey(Integer id) {
                    PlateTypeEntity entity = plateTypeMapper.selectByPrimaryKey(id);
                    return entity;
                }
                @Override
                public PageInfo<PlateTypeEntity> queryByPage(Integer pageNo, Integer pageSize, Map<String, Object> map) {
                  PageHelper.startPage(pageNo, pageSize);
                PageInfo<PlateTypeEntity> page = new PageInfo(plateTypeMapper.selectByCondition(map));
                return page;
                }
                @Override
                public List<PlateTypeEntity> queryByCondition(Map<String, Object> map) {
                return plateTypeMapper.selectByCondition(map);
                }
                @Override
                @Transactional(propagation = Propagation.REQUIRED)
                public Map<String, Object> save(PlateTypeEntity plateTypeEntity) {
                  plateTypeEntity.setId(0);
                  plateTypeMapper.insertSelective(plateTypeEntity);
                  Map<String, Object> result = new HashMap<>();
                  result.put("id" , plateTypeEntity.getId());
                  return result;
                }
                @Override
              @Transactional(propagation = Propagation.REQUIRED)
              public Integer deleteById(Integer id){
                return plateTypeMapper.deleteByPrimaryKey(id);
              }
                @Override
                @Transactional(propagation = Propagation.REQUIRED)
                public Integer updateById(PlateTypeEntity plateTypeEntity) {
                  if(null == plateTypeEntity || plateTypeEntity.getId() <= 0){
                    return 0;
                  }
                  return plateTypeMapper.updateByPrimaryKeySelective(plateTypeEntity);
                }
            }

            image.gif

            package com.znz.service.impl;
            import com.github.pagehelper.PageHelper;
            import com.github.pagehelper.PageInfo;
            import com.google.common.collect.Lists;
            import com.google.common.collect.Maps;
            import com.znz.entity.SystemMenuEntity;
            import com.znz.mapper.SystemMenuMapper;
            import com.znz.service.SystemMenuService;
            import org.springframework.transaction.annotation.Transactional;
            import org.springframework.transaction.annotation.Propagation;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.stereotype.Service;
            import java.util.HashMap;
            import java.util.List;
            import java.util.Map;
            /**
             * 服务实现层
             * @author znz
             * @date 2021-06-20 16:15:23
             */
            @Service
            public class SystemMenuServiceImpl  implements SystemMenuService {
                @Autowired
                private SystemMenuMapper systemMenuMapper;
                @Override
                public SystemMenuEntity getByPrimaryKey(Integer id) {
                    SystemMenuEntity entity = systemMenuMapper.selectByPrimaryKey(id);
                    return entity;
                }
                @Override
                public PageInfo<SystemMenuEntity> queryByPage(Integer pageNo, Integer pageSize, Map<String, Object> map) {
                  PageHelper.startPage(pageNo, pageSize);
                PageInfo<SystemMenuEntity> page = new PageInfo(systemMenuMapper.selectByCondition(map));
                return page;
                }
                @Override
              public List<SystemMenuEntity> queryByCondition(Map<String, Object> map) {
                return systemMenuMapper.selectByCondition(map);
              }
                @Override
                @Transactional(propagation = Propagation.REQUIRED)
                public Map<String, Object> save(SystemMenuEntity entity) {
                  entity.setId(0);
                  systemMenuMapper.insertSelective(entity);
                  Map<String, Object> result = new HashMap<>();
                  result.put("id" , entity.getId());
                  return result;
                }
              @Override
              @Transactional(propagation = Propagation.REQUIRED)
              public Integer deleteById(Integer id){
                return systemMenuMapper.deleteByPrimaryKey(id);
              }
              @Override
                @Transactional(propagation = Propagation.REQUIRED)
                public Integer updateById(SystemMenuEntity systemMenuEntity) {
                  if(null == systemMenuEntity || systemMenuEntity.getId() <= 0){
                    return 0;
                  }
                  return systemMenuMapper.updateByPrimaryKeySelective(systemMenuEntity);
                }
              @Override
                public Object getUserMenu() {
                    Map<String, Object> map = Maps.newHashMap();
                    map.put("showFlag", 1);
                    List<SystemMenuEntity> menus = systemMenuMapper.selectByCondition(map);
                    //按层级封装,最多三级
                    Map<String, Object> result = Maps.newHashMap();
                    result.put("first", menus.stream().filter(n -> {
                        return n.getMenuLevel() == 1;
                    }));
                    result.put("second", menus.stream().filter(n -> {
                        return n.getMenuLevel() == 2;
                    }));
                    result.put("third", menus.stream().filter(n -> {
                        return n.getMenuLevel() == 3;
                    }));
                    return result;
                }
            }

            image.gif

            package com.znz.service.impl;
            import java.io.File;
            import java.util.List;
            import org.springframework.stereotype.Service;
            import com.alibaba.druid.util.StringUtils;
            import com.alibaba.fastjson.JSONObject;
            import com.google.common.collect.Lists;
            import com.znz.constant.Constant;
            import com.znz.exception.ResultReturnException;
            import com.znz.service.FileService;
            import com.znz.util.FileUtil;
            @Service
            public class FileServiceImpl implements FileService {
                @Override
                public List<JSONObject> getFileTreeByDir(String rootPath, String dir, String typeFilter) {
                    if(StringUtils.isEmpty(dir)){
                        if(StringUtils.isEmpty(rootPath)){
                            dir = Constant.DEFAULT_DIR;
                        } else {
                            dir = rootPath;
                        }
                    }
                    if(StringUtils.isEmpty(typeFilter)){
                        typeFilter = Constant.DEFAULT_TYPE;
                    }
                    File f = new File(dir);
                    List<File> list = FileUtil.listFile(f, typeFilter, false);
                    List<JSONObject> result = Lists.newArrayList();
                    list.stream().forEach(n->{
                        JSONObject jo = new JSONObject();
                        jo.put("id", n.getAbsolutePath());
                        jo.put("pid", n.getParentFile().getAbsolutePath());
                        jo.put("filePath", n.getAbsolutePath());
                        jo.put("fileName", n.getName());
                        jo.put("isDir", n.isDirectory());
                        result.add(jo);
                    });
                    return result;
                }
                @Override
                public File readFile(String filePath) {
                    File f = new File(filePath);
                    if(!f.exists() || f.isDirectory()) {
                        throw new ResultReturnException("filePath参数异常,找不到指定的文件: " + filePath);
                    }
                    if(!f.exists() || f.isDirectory()) {
                        throw new ResultReturnException("读取图片异常:" + f.getName());
                    }
                    return f;
                }
            }

            image.gif


            相关文章
            |
            7月前
            |
            算法 计算机视觉 开发者
            OpenCV中使用Eigenfaces人脸识别器识别人脸实战(附Python源码)
            OpenCV中使用Eigenfaces人脸识别器识别人脸实战(附Python源码)
            371 0
            |
            计算机视觉
            opencv进行人脸识别
            opencv进行人脸识别
            91 0
            |
            4月前
            |
            分布式计算 vr&ar Spark
            人脸口罩识别——人脸添加口罩方法masked_faces
            人脸口罩识别——人脸添加口罩方法masked_faces
            47 1
            |
            4月前
            |
            机器学习/深度学习 算法 机器人
            |
            计算机视觉
            opencv 人脸识别
            opencv 人脸识别
            77 0
            opencv 人脸识别
            |
            7月前
            |
            计算机视觉 开发者 Python
            OpenCV中Fisherfaces人脸识别器识别人脸实战(附Python源码)
            OpenCV中Fisherfaces人脸识别器识别人脸实战(附Python源码)
            264 0
            |
            7月前
            |
            机器学习/深度学习 文字识别 算法
            [Halcon&识别] OCR字符识别
            [Halcon&识别] OCR字符识别
            244 1
            |
            7月前
            |
            算法 计算机视觉 开发者
            OpenCV中LBPH人脸识别器识别人脸实战(附Python源码)
            OpenCV中LBPH人脸识别器识别人脸实战(附Python源码)
            434 0
            |
            7月前
            |
            计算机视觉 Python
            OpenCV检测眼睛、猫脸、行人、车牌实战(附Python源码)
            OpenCV检测眼睛、猫脸、行人、车牌实战(附Python源码)
            307 0
            |
            7月前
            |
            文字识别
            [Halcon&识别] 车牌识别
            [Halcon&识别] 车牌识别
            87 0