License plate image recognition system based on Opencv

  • 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

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




}

Keywords: OpenCV AI Computer Vision

Added by Altec on Thu, 06 Jan 2022 14:00:38 +0200