Opencv创建车牌图片识别系统方法详解
程序员文章站
2022-03-24 10:55:54
目录前言包含功能软件版本软件架构参考文档效果图展示车牌检测过程图片车牌文字识别过程部分核心代码前言这是一个基于spring boot + maven + opencv 实现的图像识别及训练的demo项...
前言
这是一个基于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语言的理解,整理出当前项目
效果图展示
车牌识别
黄牌识别
绿牌识别
夜间识别
图片提取工具
人脸识别
训练
接口文档
车牌检测过程
高斯模糊:
图像灰度化:
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; } /** * 单张图片 车牌识别 * 拷贝文件到临时目录 * 过程及结果更新数据库 * @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; } }
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); } }
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; } }
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车牌图片识别系统的资料请关注其它相关文章!