基于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


            相关文章
            |
            4月前
            |
            算法 计算机视觉 开发者
            OpenCV中使用Eigenfaces人脸识别器识别人脸实战(附Python源码)
            OpenCV中使用Eigenfaces人脸识别器识别人脸实战(附Python源码)
            73 0
            |
            4月前
            |
            计算机视觉 开发者 Python
            OpenCV中Fisherfaces人脸识别器识别人脸实战(附Python源码)
            OpenCV中Fisherfaces人脸识别器识别人脸实战(附Python源码)
            63 0
            |
            4月前
            |
            算法 计算机视觉 开发者
            OpenCV中LBPH人脸识别器识别人脸实战(附Python源码)
            OpenCV中LBPH人脸识别器识别人脸实战(附Python源码)
            93 0
            |
            4月前
            |
            文字识别
            [Halcon&识别] 车牌识别
            [Halcon&识别] 车牌识别
            28 0
            |
            4月前
            |
            算法 计算机视觉
            OpenCV(图像处理)-图片搜索
            1.知识介绍 Opencv进行图片搜索需要的知识有:特征点匹配+单应性矩阵知识,特征点匹配作者前面文章有记录。 单应性矩阵:两个不同视角上的点所对应的单应性矩阵可以用同一个射影变换来表述可以简单理解为变换矩阵H,x1 = h*x2
            62 0
            |
            7月前
            |
            数据库 计算机视觉 Docker
            Python 基于 opencv 的车牌识别系统, 可以准确识别车牌号
            Python 基于 opencv 的车牌识别系统, 可以准确识别车牌号
            |
            7月前
            |
            计算机视觉 C++ Python
            opencv人脸识别与变形
            opencv人脸识别与变形
            74 0
            opencv人脸识别与变形
            |
            8月前
            |
            机器学习/深度学习 计算机视觉 Python
            使用OpenCV实现人脸图像卡通化
            使用OpenCV实现人脸图像卡通化
            |
            机器学习/深度学习 存储 算法
            基于Python opencv实现车牌识别及二维码条形码识别系统 附完整源码
            基于Python opencv实现车牌识别及二维码条形码识别系统 附完整源码
            414 0
            基于Python opencv实现车牌识别及二维码条形码识别系统 附完整源码
            |
            计算机视觉 Python
            OpenCV项目-人脸识别详解
            利用级联分类器进行OpenCV人脸识别项目
            108 0