我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Opencv创建车牌图片识别系统方法详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Opencv创建车牌图片识别系统方法详解

前言

这是一个基于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

参考文档

参考了EasyPR C++项目、以及fan-wenjie的EasyPR-Java项目;同时查阅了部分opencv官方4.0.1版本C++的源码,结合个人对java语言的理解,整理出当前项目

liuruoze/EasyPR

fan-wenjie/EasyPR-Java

opencv官方

效果图展示

车牌识别

黄牌识别

绿牌识别

夜间识别

图片提取工具

人脸识别

训练

接口文档

车牌检测过程

高斯模糊:

图像灰度化:

Sobel 算子:

图像二值化:

图像闭操作:

二值图像降噪:

提取外部轮廓:

外部轮廓筛选:

切图:

重置切图尺寸:

车牌检测结果:

图片车牌文字识别过程

车牌检测结果:

debug_char_threshold:

debug_char_clearLiuDing:

debug_specMat:

debug_chineseMat:

debug_char_auxRoi:

部分核心代码

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;
    }
 
    
    
    
    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;
    }
    
 
}
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;
 

@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);
    }
 
 
}
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;
 

@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;
    }
 
 
 
}
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;
    }
 
 
 
 
}

以上就是Opencv创建车牌图片识别系统方法详解的详细内容,更多关于Opencv车牌图片识别系统的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Opencv创建车牌图片识别系统方法详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Win8系统中如何创建虚拟网卡 Win8添加虚拟网卡方法图文详解

Win8系统添加虚拟网卡的操作和Win7不太一样,很多朋友不知道如何操作,今天小编就教教大家怎么在Win8中创建虚拟网卡。 Win8添加虚拟网卡步骤 首先进入Win8系统按下快捷键 win+x 打开设备管理器,如下图添加完以后,在网络连接里
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录