- This is a Demo project of image recognition and training based on spring boot + maven + opencv
- It includes functions such as license plate recognition and face recognition, and runs through technical points such as sample processing, model training, image processing, object detection and object recognition
- There are relatively few deep learning projects of java language in the whole open source community;
- There are few open source projects with complete training process, detection and identification process!!
Include functions
- Blue, green and yellow license plate detection and license plate number recognition
- JAVA implementation of common contour extraction license plate algorithm on the Internet
- JAVA implementation of hsv color segmentation algorithm for license plate extraction
- JAVA implementation of license plate detection and training based on svm algorithm
- JAVA implementation of license plate number recognition training based on ann algorithm
- Face detection} next, face recognition will be realized
- The image processing tool has realized HSV color cutting at present, and more image processing tools will be added in the future to assist in algorithm optimization
Operation interface
Software version
- 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 version 1.0.0
Software architecture
- B/S architecture, front-end html + requireJS, back-end java
- The database uses SQLite3 0
- Interface documentation uses swagger 2.0
Reference documents
- Refer to EasyPR C + + project and easypr java project of fan Wenjie; At the same time, I consulted the source code of some official opencv version 4.0.1 C + +, combined with my personal understanding of Java language, sorted out the current project
- liuruoze/EasyPR: https://gitee.com/easypr/EasyPR?_from=gitee_search
- fan-wenjie/EasyPR-Java: GitHub - Fan Wenjie / EasyPR Java: Java version of license plate recognition software EasyPR
- opencv official: Home - OpenCV
Display of relevant function realization:
License plate recognition
Yellow card identification
Green card identification
Night identification
Image extraction tool
Face recognition
train
Interface documentation
License plate detection process
Gaussian blur:
Image graying:
Sobel operator:
Image binarization:
Image closing operation:
Binary image denoising:
Extract external contour:
External contour filtering:
Cut:
Reset cut size:
License plate detection results:
Picture license plate character recognition process
License plate detection results:
Picture license plate character recognition process
debug_char_threshold:
debug_char_clearLiuDing:
debug_specMat:
debug_chineseMat:
debug_char_auxRoi:
Department core code:
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(); // Get the directory of the first level under baseDir, only get folders, do not recurse subdirectories, and traverse List<File> folderList = FileUtil.listFile(baseDir, ";", false); folderList.parallelStream().forEach(folder -> { if(!folder.getName().equals("temp")) { // Traverse each folder and recursively obtain the pictures under the folder 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); // Re identification entity = plateFileMapper.selectByPrimaryKey(entity.getId()); // After re identification, re obtain the data } // Query debug file 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() { // Query the picture without license plate recognition List<PlateFileEntity> list = plateFileMapper.getUnRecogniseList(); list.parallelStream().forEach(n->{ File f = new File(n.getFilePath()); if(FileUtil.checkFile(f)) { doRecognise(f, n); } }); return 1; } /** * Single picture license plate recognition * Copy files to temporary directory * Process and result update database * @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); // Copy files and rename // Create a temporary directory to store process pictures 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(); // Delete copied temporary files 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); // Return temporary path to front end // Get basic information about pictures 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); // Go to HSV space for processing 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 implementation layer * @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; /** * Service implementation layer * @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); //Package by level, up to three levels 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 Parameter exception. The specified file cannot be found: " + filePath); } if(!f.exists() || f.isDirectory()) { throw new ResultReturnException("Exception reading picture:" + f.getName()); } return f; } }