基于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:https://gitee.com/easypr/EasyPR?_from=gitee_search
- fan-wenjie/EasyPR-Java: GitHub - fan-wenjie/EasyPR-Java: 车牌识别软件EasyPR的Java版本
- opencv官方: Home - 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 {@Autowiredprivate PlateFileMapper plateFileMapper;@Autowiredprivate 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;/*** 服务实现层* @author znz* @date 2020-09-30T16:54:41.823*/
@Service
public class PlateTypeServiceImpl implements PlateTypeService {@Autowiredprivate PlateTypeMapper plateTypeMapper;@Overridepublic PlateTypeEntity getByPrimaryKey(Integer id) {PlateTypeEntity entity = plateTypeMapper.selectByPrimaryKey(id);return entity;}@Overridepublic 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;}@Overridepublic 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;/*** 服务实现层* @author znz* @date 2021-06-20 16:15:23*/
@Service
public class SystemMenuServiceImpl implements SystemMenuService {@Autowiredprivate SystemMenuMapper systemMenuMapper;@Overridepublic SystemMenuEntity getByPrimaryKey(Integer id) {SystemMenuEntity entity = systemMenuMapper.selectByPrimaryKey(id);return entity;}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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实现车牌图片识别系统相关推荐
- Python基于OpenCV的人脸表情识别系统[源码&部署教程]
1.项目背景 人脸表情识别是模式识别中一个非常重要却十分复杂的课题.首先对计算机人脸表情识别技术的研究背景及发展历程作了简单回顾.然后对近期人脸表情识别的方法进行了分类综述.通过对各种识别方法的分析与 ...
- linux自动识别车牌设计,基于Linux的车牌智能识别系统的设计与实现
摘要: 随着人们生活水平的不断提高,越来越多的技术应用到人们的日常生活中,通信技术和计算机技术与人们的生活密切相连,应用在视频监控.数码网络等方面,这些技术为人们的生活提供了强有力的保障.如何设计一套 ...
- 基于OpenCV的简单人脸识别系统
目录 1. 调用库函数 2. 调用摄像头并设置窗口 3. 设置图片正负样本数据集的路径 4. 调用人脸检测器 5. 正负样本载入 6.提取人脸区域 7. 建立LBPH人脸识别模型 8. 实时检测 9. ...
- 基于Opencv的口罩佩戴识别系统
疫情之下,有人选择负重前行,有人在年假与工作中毅然选择后者.感谢"疫"路有你,祝愿祖国繁荣昌盛,国泰民安! 人脸识别技术已经非常普及啦,现在戴口罩的脸支付宝也可以识别,据报道阿里现 ...
- opencv实战项目:基于opencv的车牌号码识别
首先,呈上我自己根据代码写的步骤流程,方便记忆,字有点丑,哈哈哈!!! 好吧,图片看不清,那就上代码 import cv2 import imutils import numpy as np impo ...
- python的快车智能车牌号码识别系统的开发
It is not always possible to prove some crimes. To achieve this, modern tools may be needed which mu ...
- Python 基于 opencv 的车牌识别系统, 可以准确识别车牌号
大家好,我是程序员徐师兄,6 年大厂程序员经验,点击关注我 简介 毕业设计基于Opencv的车牌识别系统 车牌搜索识别找出某个车牌号 对比识别车牌系统 车牌数据库认证系统 车牌图文搜索系统 车牌数据库 ...
- 基于python+OpenCV的车牌号码识别
基于python+OpenCV的车牌号码识别 车牌识别行业已具备一定的市场规模,在电子警察.公路卡口.停车场.商业管理.汽修服务等领域已取得了部分应用.一个典型的车辆牌照识别系统一般包括以下4个部分: ...
- 基于OpenCV的车牌识别的设计与实现
随着大数据和互联网技术的快速发展,利用人工智能技术实现车牌信息的自动识别推荐成为研究的热门话题.通过对基于OpenCV的车牌识别系统的网站功能需要进行讨论研究,这种跨平台计算机视觉和机器学习非常适用于 ...
- 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【三】VGG网络进行特征提取
前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...
最新文章
- Electron中 提示:Uncaught ReferenceError: process is not defined
- “拯救网站运维经理赵明”有奖方案征集启事
- 2019蓝桥杯省赛---java---C---9(等差数列)
- 微服务架构会和分布式单体架构高度重合吗
- 不用去验血,一查就能知道自己缺啥,一定要收好
- android应用开发(16)---AndroidManifest.xml
- 王文汉:大学毕业后的5-10年最重要
- 基于JAVA+SpringMVC+Mybatis+MYSQL的旅游管理系统
- C++中的多重继承(二)
- MySQL 的CASE WHEN 语句使用说明
- mulitpartfile怎么接收不到值_GNSS接收机设计杂谈(射频前端+捕获)
- 侧方、s弯道、坡起相关
- 转载: Fisher精确检验概述
- 螺栓预紧力与拧紧力矩的计算方法
- 服装行业个性化服务:订阅电商鼻祖Stitch Fix商业模式中的个性化推荐分析
- WPS表格excel实现下拉搜索(简单几步,轻松搞定)
- 2022年全国最新高级消防设施操作员模拟题库及答案
- 企业三层架构、冗余、STP生成树协议总结
- 比“5G有多快”更重要的,是5G将带来哪些改变
- Bill Joy (zz.IS2120)
热门文章
- 中班音乐会跳舞的机器人_中班音乐律动机器人
- 从JDK 6升级到JDK 7过程中遇到的一个问题
- 1500个前端开发常用JavaScript特效
- Chrome插件:中国天气预报与万年历
- 微信小程序教程、开发资源下载汇总(2.8日更新,持续更新中……)
- html5响应式的插件,Chocolat-jQuery响应式LightBox插件 -HTML5功能
- WPE封包外挂教程(下)
- 英文名称(缩写)汇总
- [Android第三方类库]聊一聊Android的第三方开发组件
- 高等数学辅导讲义_历年真题,复习讲义的经验分享(数二127分)