You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
9.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.yuxue.service.impl;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_imgcodecs;
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.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yuxue.constant.Constant;
import com.yuxue.easypr.core.CharsRecognise;
import com.yuxue.easypr.core.CoreFunc;
import com.yuxue.easypr.core.PlateDetect;
import com.yuxue.entity.PlateFileEntity;
import com.yuxue.entity.PlateRecoDebugEntity;
import com.yuxue.entity.TempPlateFileEntity;
import com.yuxue.enumtype.PlateColor;
import com.yuxue.mapper.PlateFileMapper;
import com.yuxue.mapper.PlateRecoDebugMapper;
import com.yuxue.mapper.TempPlateFileMapper;
import com.yuxue.service.PlateService;
import com.yuxue.util.FileUtil;
@Service
public class PlateServiceImpl implements PlateService {
// 车牌定位处理步骤该map用于表示步骤图片的顺序
private static Map<String, Integer> debugMap = Maps.newLinkedHashMap();
static {
debugMap.put("result", 99);
debugMap.put("debug_GaussianBlur", 0); // 高斯模糊
debugMap.put("debug_gray", 1); // 图像灰度化
debugMap.put("debug_Sobel", 2); // Sobel 算子
debugMap.put("debug_threshold", 3); //图像二值化
debugMap.put("debug_morphology", 4); // 图像闭操作
debugMap.put("debug_Contours", 5); // 提取外部轮廓
debugMap.put("debug_result", 6); // 原图处理结果
debugMap.put("debug_crop", 7); // 切图
debugMap.put("debug_resize", 8); // 切图resize
debugMap.put("debug_char_threshold", 9); //
// debugMap.put("debug_char_clearLiuDing", 10); // 去除柳钉
debugMap.put("debug_specMat", 11); //
debugMap.put("debug_chineseMat", 12); //
debugMap.put("debug_char_auxRoi", 13); //
}
@Autowired
private PlateFileMapper plateFileMapper;
@Autowired
private PlateRecoDebugMapper plateRecoDebugMapper;
@Autowired
private TempPlateFileMapper tempPlateFileMapper;
@Override
public Object recognise(String filePath, boolean reRecognise) {
filePath = filePath.replaceAll("\\\\", "/");
File f = new File(filePath);
PlateFileEntity e = 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)) {
e = new PlateFileEntity();
e.setFileName(f.getName());
e.setFilePath(f.getAbsolutePath().replaceAll("\\\\", "/"));
e.setFileType(f.getName().substring(f.getName().lastIndexOf(".") + 1));
plateFileMapper.insertSelective(e);
}
reRecognise = true;
} else {
e = list.get(0);
}
if(reRecognise) {
doRecognise(f, e, 0); // 重新识别
e = plateFileMapper.selectByPrimaryKey(e.getId()); // 重新识别之后,重新获取一下数据
}
// 查询数据库,返回结果
paramMap.clear();
paramMap.put("parentId", e.getId());
e.setDebug(plateRecoDebugMapper.selectByCondition(paramMap));
return e;
}
@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 recogniseAll() {
// 查询到还没有进行车牌识别的图片
List<PlateFileEntity> list = plateFileMapper.getUnRecogniseList();
// 开启多线程进行识别
Random r = new Random(99);
list.parallelStream().forEach(n->{
File f = new File(n.getFilePath());
if(FileUtil.checkFile(f)) {
doRecognise(f, n, r.nextInt());
}
});
return 1;
}
@Override
public Object getProcessStep() {
return debugMap;
}
/**
* 单张图片 车牌识别
* 拷贝文件到临时目录
* 过程及结果更新数据库
* @param f 调用方需要验证文件存在
* @param result
* @return
*/
public Object doRecognise(File f, PlateFileEntity e, Integer seed) {
// 插入识别过程图片数据信息 通过temp文件夹的文件更新数据库
List<PlateRecoDebugEntity> debug = Lists.newArrayList();
Long ct = System.currentTimeMillis();
String targetPath = Constant.DEFAULT_TEMP_DIR.concat(ct.toString() + seed)
.concat(f.getAbsolutePath().substring(f.getAbsolutePath().lastIndexOf(".")));
// 先将文件拷贝并且重命名到不包含中文及特殊字符的目录下
FileUtil.copyAndRename(f.getAbsolutePath(), targetPath);
// 开始识别,生成过程及结果切图,将识别结果更新到数据库
Mat src = opencv_imgcodecs.imread(targetPath);
String tempPath = Constant.DEFAULT_TEMP_DIR + ct + "/";
FileUtil.createDir(tempPath); // 创建文件夹
// 车牌检测对象
PlateDetect plateDetect = new PlateDetect();
plateDetect.setPDLifemode(true);
plateDetect.setDebug(true, tempPath); // 将过程的图块保存到盘符
Vector<Mat> matVector = new Vector<Mat>();
if (0 == plateDetect.plateDetect(src, matVector)) { // 定位及判断获取到车牌图块Mat
CharsRecognise cr = new CharsRecognise();
cr.setCRDebug(true);
for (int i = 0; i < matVector.size(); ++i) { // 遍历车牌图块Mat进行识别
Mat img = matVector.get(i);
String palte = cr.charsRecognise(img, tempPath); // 字符识别
PlateColor color = CoreFunc.getPlateType(img, true);
String fileName = "result_" + i + ".png";
// 识别的车牌,保存图片文件
String str = tempPath + fileName;
// 此方法生成的文件中文名称都是乱码试了各种编解码均无效OpenCV自身的编解码问题。
opencv_imgcodecs.imwrite(str, img);
// 重命名文件,让生成的文件包含中文
// String newName = palte + "_"+ color + ".png";
// FileUtil.renameFile(str, newName);
PlateRecoDebugEntity de = new PlateRecoDebugEntity();
de.setRecoPlate(palte);
de.setFilePath(str);
de.setFileName(fileName);
de.setPlateColor(color.desc);
de.setParentId(e.getId());
de.setDebugType("result");
de.setSort(debugMap.get("result"));
debug.add(de);
}
} else {
e.setRecoCorrect(3); // 未检测到车牌
}
new File(targetPath).delete(); // 删除拷贝的文件
e.setTempPath(tempPath);
List<File> debugList = FileUtil.listFile(new File(tempPath), Constant.DEFAULT_TYPE, false);
debugList.parallelStream().forEach(d -> {
String name = d.getName().substring(0, d.getName().lastIndexOf("."));
Pattern pattern = Pattern.compile("\\d+$");
Matcher matcher = pattern.matcher(name);
if(matcher.find()) {
name = name.substring(0, name.lastIndexOf("_"));
}
if(!"result".equals(name)) {
PlateRecoDebugEntity de = new PlateRecoDebugEntity();
de.setRecoPlate("");
de.setFilePath(d.getAbsolutePath().replaceAll("\\\\", "/"));
de.setFileName(d.getName());
de.setPlateColor("");
de.setParentId(e.getId());
de.setDebugType(name);
de.setSort(debugMap.get(name));
debug.add(de);
}
});
// 更新图片主表信息
plateFileMapper.updateByPrimaryKeySelective(e);
plateRecoDebugMapper.deleteByParentId(e.getId());
plateRecoDebugMapper.batchInsert(debug);
return 1;
}
}