优化代码结构

devA
yuxue 5 years ago
parent 48ded30583
commit 3ae780df71

@ -33,7 +33,7 @@ public class AroundMethod implements MethodInterceptor{
RetExclude re = methodInvocation.getMethod().getAnnotation(RetExclude.class);
if(null != re && null != re.value()) {
// log.info("api添加了封装排除注解");
log.info("api添加了封装排除注解");
return ret;
}
// log.info("封装返回值");

@ -1,5 +1,7 @@
package com.yuxue.constant;
import java.util.HashMap;
import java.util.Map;
/**
*
@ -21,6 +23,10 @@ public class Constant {
// 车牌识别,默认处理图片类型
public static String DEFAULT_TYPE = "png,jpg,jpeg";
public static String DEFAULT_ANN_PATH = "res/model/ann.xml";
// 车牌识别,判断是否车牌的正则表达式
public static String plateReg = "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})";
@ -32,6 +38,9 @@ public class Constant {
public final static char strCharacters[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 没有I */ 'J', 'K', 'L', 'M', 'N', /* 没有O */'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
// 没有I和0, 10个数字与24个英文字符之和
public final static Integer numCharacter = strCharacters.length;
// 并不全面,有些省份没有训练数据所以没有字符
// 有些后面加数字2的表示在训练时常看到字符的一种变形也作为训练数据存储
public final static String strChinese[] = {
@ -68,6 +77,45 @@ public class Constant {
"zh_zhe" /*浙*/
};
/* 34+31=65 34个字符跟31个汉字 */
public final static Integer numAll = strCharacters.length + strChinese.length;
public static Map<String, String> KEY_CHINESE_MAP = new HashMap<String, String>();
static {
if (KEY_CHINESE_MAP.isEmpty()) {
KEY_CHINESE_MAP.put("zh_cuan", "川");
KEY_CHINESE_MAP.put("zh_e", "鄂");
KEY_CHINESE_MAP.put("zh_gan", "赣");
KEY_CHINESE_MAP.put("zh_gan1", "甘");
KEY_CHINESE_MAP.put("zh_gui", "贵");
KEY_CHINESE_MAP.put("zh_gui1", "桂");
KEY_CHINESE_MAP.put("zh_hei", "黑");
KEY_CHINESE_MAP.put("zh_hu", "沪");
KEY_CHINESE_MAP.put("zh_ji", "冀");
KEY_CHINESE_MAP.put("zh_jin", "津");
KEY_CHINESE_MAP.put("zh_jing", "京");
KEY_CHINESE_MAP.put("zh_jl", "吉");
KEY_CHINESE_MAP.put("zh_liao", "辽");
KEY_CHINESE_MAP.put("zh_lu", "鲁");
KEY_CHINESE_MAP.put("zh_meng", "蒙");
KEY_CHINESE_MAP.put("zh_min", "闽");
KEY_CHINESE_MAP.put("zh_ning", "宁");
KEY_CHINESE_MAP.put("zh_qing", "青");
KEY_CHINESE_MAP.put("zh_qiong", "琼");
KEY_CHINESE_MAP.put("zh_shan", "陕");
KEY_CHINESE_MAP.put("zh_su", "苏");
KEY_CHINESE_MAP.put("zh_sx", "晋");
KEY_CHINESE_MAP.put("zh_wan", "皖");
KEY_CHINESE_MAP.put("zh_xiang", "湘");
KEY_CHINESE_MAP.put("zh_xin", "新");
KEY_CHINESE_MAP.put("zh_yu", "豫");
KEY_CHINESE_MAP.put("zh_yu1", "渝");
KEY_CHINESE_MAP.put("zh_yue", "粤");
KEY_CHINESE_MAP.put("zh_yun", "云");
KEY_CHINESE_MAP.put("zh_zang", "藏");
KEY_CHINESE_MAP.put("zh_zhe", "浙");
}
}
}

@ -1,10 +1,6 @@
package com.yuxue.easypr.core;
import static org.bytedeco.javacpp.opencv_core.CV_32FC1;
import java.util.HashMap;
import java.util.Map;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_ml.ANN_MLP;
@ -19,63 +15,16 @@ import com.yuxue.util.Convert;
*/
public class CharsIdentify {
private final static int numCharacter = 34; // 没有I和0, 10个数字与24个英文字符之和
private final static int numAll = 65; /* 34+31=65 34个字符跟31个汉字 */
private ANN_MLP ann=ANN_MLP.create();
private String path = "res/model/ann.xml";
static boolean hasPrint = false;
private Map<String, String> map = new HashMap<String, String>();
public CharsIdentify() {
loadModel(); // 加载ann配置文件
if (this.map.isEmpty()) {
map.put("zh_cuan", "川");
map.put("zh_e", "鄂");
map.put("zh_gan", "赣");
map.put("zh_gan1", "甘");
map.put("zh_gui", "贵");
map.put("zh_gui1", "桂");
map.put("zh_hei", "黑");
map.put("zh_hu", "沪");
map.put("zh_ji", "冀");
map.put("zh_jin", "津");
map.put("zh_jing", "京");
map.put("zh_jl", "吉");
map.put("zh_liao", "辽");
map.put("zh_lu", "鲁");
map.put("zh_meng", "蒙");
map.put("zh_min", "闽");
map.put("zh_ning", "宁");
map.put("zh_qing", "青");
map.put("zh_qiong", "琼");
map.put("zh_shan", "陕");
map.put("zh_su", "苏");
map.put("zh_sx", "晋");
map.put("zh_wan", "皖");
map.put("zh_xiang", "湘");
map.put("zh_xin", "新");
map.put("zh_yu", "豫");
map.put("zh_yu1", "渝");
map.put("zh_yue", "粤");
map.put("zh_yun", "云");
map.put("zh_zang", "藏");
map.put("zh_zhe", "浙");
}
}
private void loadModel() {
loadModel(this.path);
loadModel(Constant.DEFAULT_ANN_PATH);
}
public void loadModel(String s) {
this.ann.clear();
//ann=ANN_MLP.loadANN_MLP(s, "ann"); // 加载ann配置文件 图像转文字的训练库文件
// 加载ann配置文件 图像转文字的训练库文件
//ann=ANN_MLP.loadANN_MLP(s, "ann");
ann = ANN_MLP.load(s);
}
@ -95,20 +44,20 @@ public class CharsIdentify {
if (!isChinese) {
result = String.valueOf(Constant.strCharacters[index]);
} else {
String s = Constant.strChinese[index - numCharacter];
result = map.get(s);
String s = Constant.strChinese[index - Constant.numCharacter];
result = Constant.KEY_CHINESE_MAP.get(s); // 编码转中文
}
return result;
}
private int classify(final Mat f, final Boolean isChinses, final Boolean isSpeci) {
int result = -1;
Mat output = new Mat(1, numAll, CV_32FC1);
Mat output = new Mat(1, Constant.numAll, opencv_core.CV_32FC1);
ann.predict(f, output, 0); // 预测结果
int ann_min = (!isChinses) ? ((isSpeci) ? 10 : 0) : numCharacter;
int ann_max = (!isChinses) ? numCharacter : numAll;
int ann_min = (!isChinses) ? ((isSpeci) ? 10 : 0) : Constant.numCharacter;
int ann_max = (!isChinses) ? Constant.numCharacter : Constant.numAll;
float maxVal = -2;
@ -122,14 +71,4 @@ public class CharsIdentify {
return result;
}
public final void setModelPath(String path) {
this.path = path;
}
public final String getModelPath() {
return this.path;
}
}

@ -23,8 +23,9 @@ import com.yuxue.enumtype.PlateColor;
/**
* @author lin.yao
*
* @author yuxue
* @date 2020-05-16 21:09
*/
public class CoreFunc {

@ -1,6 +1,5 @@
package com.yuxue.train;
import java.util.Vector;
import org.opencv.core.Core;
@ -23,7 +22,7 @@ import com.yuxue.util.FileUtil;
* org.opencv
*
*
*
*
*
* ann.xml
* 1res/model/ann.xml
@ -40,14 +39,13 @@ public class ANNTrain {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private final int numCharacter = Constant.strCharacters.length;
// 默认的训练操作的根目录
private static final String DEFAULT_PATH = "D:/PlateDetect/train/chars_recognise_ann/";
// 训练模型文件保存位置
private static final String MODEL_PATH = DEFAULT_PATH + "ann.xml";
public static float[] projectedHistogram(final Mat img, Direction direction) {
int sz = 0;
switch (direction) {
@ -120,7 +118,7 @@ public class ANNTrain {
Mat samples = new Mat(); // 使用push_back行数列数不能赋初始值
Vector<Integer> trainingLabels = new Vector<Integer>();
// 加载数字及字母字符
for (int i = 0; i < numCharacter; i++) {
for (int i = 0; i < Constant.numCharacter; i++) {
String str = DEFAULT_PATH + "learn/" + Constant.strCharacters[i];
Vector<String> files = new Vector<String>();
FileUtil.getFiles(str, files);
@ -147,23 +145,20 @@ public class ANNTrain {
// System.err.println(files.get(j)); // 文件名不能包含中文
Mat f = features(img, _predictsize);
samples.push_back(f);
trainingLabels.add(i + numCharacter);
trainingLabels.add(i + Constant.numCharacter);
}
}
//440 vhist.length + hhist.length + lowData.cols() * lowData.rows();
// CV_32FC1 CV_32SC1 CV_32F
Mat classes = new Mat(trainingLabels.size(), 65, CvType.CV_32F);
Mat classes = new Mat(trainingLabels.size(), Constant.numAll, CvType.CV_32F);
float[] labels = new float[trainingLabels.size()];
for (int i = 0; i < labels.length; ++i) {
// labels[i] = trainingLabels.get(i).intValue();
classes.put(i, trainingLabels.get(i), 1.f);
}
// classes.put(0, 0, labels);
// samples.type() == CV_32F || samples.type() == CV_32S
TrainData train_data = TrainData.create(samples, Ml.ROW_SAMPLE, classes);
@ -194,11 +189,12 @@ public class ANNTrain {
Vector<String> files = new Vector<String>();
FileUtil.getFiles(DEFAULT_PATH + "test/", files);
int i = 0;
for (String string : files) {
Mat img = Imgcodecs.imread(string, 0);
Mat f = features(img, Constant.predictSize);
// 140 predictSize = 10; vhist.length + hhist.length + lowData.cols() * lowData.rows();
// 440 predictSize = 20;
Mat output = new Mat(1, 140, CvType.CV_32F);
//ann.predict(f, output, 0); // 预测结果
System.err.println(string + "===>" + (int) ann.predict(f, output, 0));
@ -207,7 +203,6 @@ public class ANNTrain {
// System.err.println(string + "===>" + output.get(0, 0)[0]);
}
}
public static void main(String[] args) {
@ -216,7 +211,7 @@ public class ANNTrain {
// 这里演示只训练model文件夹下的ann.xml此模型是一个predictSize=10,neurons=40的ANN模型
// 可根据需要训练不同的predictSize或者neurons的ANN模型
// 根据机器的不同训练时间不一样但一般需要10分钟左右所以慢慢等一会吧。
annT.train(Constant.predictSize, Constant.neurons);
// annT.train(Constant.predictSize, Constant.neurons);
annT.predict();

@ -19,6 +19,7 @@ import com.yuxue.util.FileUtil;
/**
* org.opencv
*
*
* windows
* 1openvphttps://opencv.org/releases/page/2/ 当前使用4.0.1版本
* 2exe \build\java\x64\opencv_java401.dll \build\x64\vc14\bin\

@ -1,192 +0,0 @@
package com.yuxue.train;
import java.io.File;
import java.util.List;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.TermCriteria;
import org.bytedeco.javacpp.opencv_imgcodecs;
import org.bytedeco.javacpp.opencv_imgproc;
import org.bytedeco.javacpp.opencv_ml.SVM;
import org.bytedeco.javacpp.opencv_ml.TrainData;
import org.opencv.ml.Ml;
import com.yuxue.constant.Constant;
import com.yuxue.easypr.core.Features;
import com.yuxue.easypr.core.SVMCallback;
import com.yuxue.util.FileUtil;
/**
* org.bytedeco.javacpp
*
*
*
*
* svm.xml
* 1res/model/svm.xml
* 2com.yuxue.easypr.core.PlateJudge.plateJudge(Mat)
*
* @author yuxue
* @date 2020-05-13 10:10
*/
public class PlateRecoTrain1 {
private SVMCallback callback = new Features();
// 默认的训练操作的根目录
private static final String DEFAULT_PATH = "D:/PlateDetect/train/plate_detect_svm/";
// 训练模型文件保存位置
private static final String MODEL_PATH = DEFAULT_PATH + "svm.xml";
public static void main(String[] arg) {
// 训练, 生成svm.xml库文件
// train();
// 识别,判断样本文件是否是车牌
pridect();
}
public static void train() {
// 正样本 // 136 × 36 像素 训练的源图像文件要相同大小
List<File> imgList0 = FileUtil.listFile(new File(DEFAULT_PATH + "/learn/HasPlate"), Constant.DEFAULT_TYPE, false);
// 负样本 // 136 × 36 像素 训练的源图像文件要相同大小
List<File> imgList1 = FileUtil.listFile(new File(DEFAULT_PATH + "/learn/NoPlate"), Constant.DEFAULT_TYPE, false);
// 标记:正样本用 0 表示,负样本用 1 表示。
int labels[] = createLabelArray(imgList0.size(), imgList1.size());
int sample_num = labels.length; // 图片数量
// 用于存放所有样本的矩阵
Mat trainingDataMat = null;
// 存放标记的Mat,每个图片都要给一个标记
Mat labelsMat = new Mat(sample_num, 1, opencv_core.CV_32FC1);
// labelsMat.put(0, 0, labels);
for (int i = 0; i < sample_num; i++) { // 遍历所有的正负样本,处理样本用于生成训练的库文件
String path = "";
if(i < imgList0.size()) {
path = imgList0.get(i).getAbsolutePath();
} else {
path = imgList1.get(i - imgList0.size()).getAbsolutePath();
}
Mat inMat = opencv_imgcodecs.imread(path); // 读取样本文件
// 创建一个行数为sample_num, 列数为 rows*cols 的矩阵; 用于存放样本
if (trainingDataMat == null) {
trainingDataMat = new Mat(sample_num, inMat.rows() * inMat.cols(), opencv_core.CV_32FC1);// CV_32FC1 是规定的训练用的图片格式。
}
// 样本文件处理,这里是为了过滤不需要的特征,减少训练时间 // 根据实际情况需要进行处理
Mat greyMat = new Mat();
opencv_imgproc.cvtColor(inMat, greyMat, opencv_imgproc.COLOR_BGR2GRAY); // 转成灰度图
Mat dst = new Mat(inMat.rows(), inMat.cols(), inMat.type());
opencv_imgproc.Canny(greyMat, dst, 130, 250); // 边缘检测
// 将样本矩阵转换成只有一行的矩阵保存为float数组
float[] arr = new float[dst.rows() * dst.cols()];
int l = 0;
for (int j = 0; j < dst.rows(); j++) { // 遍历行
for (int k = 0; k < dst.cols(); k++) { // 遍历列
double[] a = null;//dst.get(j, k);
arr[l] = (float) a[0];
l++;
}
}
// trainingDataMat.put(i, 0, arr); // 多张图合并到一张
}
// opencv_imgcodecs.imwrite(DEFAULT_PATH + "trainingDataMat.jpg", trainingDataMat);
// 配置SVM训练器参数
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 20000, 0.0001);
SVM svm = SVM.create();
svm.setTermCriteria(criteria); // 指定
svm.setKernel(SVM.RBF); // 使用预先定义的内核初始化
svm.setType(SVM.C_SVC); // SVM的类型,默认是SVM.C_SVC
svm.setGamma(0.1); // 核函数的参数
svm.setNu(0.1); // SVM优化问题参数
svm.setC(1); // SVM优化问题的参数C
svm.setP(0.1);
svm.setDegree(0.1);
svm.setCoef0(0.1);
TrainData td = TrainData.create(trainingDataMat, Ml.ROW_SAMPLE, labelsMat);// 类封装的训练数据
boolean success = svm.train(td.getSamples(), Ml.ROW_SAMPLE, td.getResponses());// 训练统计模型
System.out.println("svm training result: " + success);
svm.save(MODEL_PATH);// 保存模型
}
public static void pridect() {
// 加载训练得到的 xml 模型文件
SVM svm = SVM.load(MODEL_PATH);
// 136 × 36 像素 需要跟训练的源图像文件保持相同大小
doPridect(svm, DEFAULT_PATH + "test/A01_NMV802_0.jpg");
doPridect(svm, DEFAULT_PATH + "test/debug_resize_1.jpg");
doPridect(svm, DEFAULT_PATH + "test/debug_resize_2.jpg");
doPridect(svm, DEFAULT_PATH + "test/debug_resize_3.jpg");
doPridect(svm, DEFAULT_PATH + "test/S22_KG2187_3.jpg");
doPridect(svm, DEFAULT_PATH + "test/S22_KG2187_5.jpg");
doPridect(svm, DEFAULT_PATH + "test/result_0.png");
doPridect(svm, DEFAULT_PATH + "test/result_1.png");
doPridect(svm, DEFAULT_PATH + "test/result_2.png");
doPridect(svm, DEFAULT_PATH + "test/result_3.png");
doPridect(svm, DEFAULT_PATH + "test/result_4.png");
doPridect(svm, DEFAULT_PATH + "test/result_5.png");
doPridect(svm, DEFAULT_PATH + "test/result_6.png");
doPridect(svm, DEFAULT_PATH + "test/result_7.png");
doPridect(svm, DEFAULT_PATH + "test/result_8.png");
}
public static void doPridect(SVM svm, String imgPath) {
Mat src = opencv_imgcodecs.imread(imgPath);// 图片大小要和样本一致
opencv_imgproc.cvtColor(src, src, opencv_imgproc.CV_RGB2GRAY);
Mat dst = new Mat();
opencv_imgproc.Canny(src, dst, 130, 250);
Mat samples = dst.reshape(1, 1);
samples.convertTo(samples, opencv_core.CV_32FC1);
// opencv_imgcodecs.imwrite(DEFAULT_PATH + "test_1.jpg", samples);
// 如果训练时使用这个标识那么符合的图像会返回9.0
float flag = svm.predict(samples);
System.err.println(flag);
if (flag == 0) {
System.err.println(imgPath + " 目标符合");
}
if (flag == 1) {
System.out.println(imgPath + " 目标不符合");
}
}
public static int[] createLabelArray(Integer i1, Integer i2) {
int labels[] = new int[i1 + i2];
for (int i = 0; i < labels.length; i++) {
if(i < i1) {
labels[i] = 0;
} else {
labels[i] = 1;
}
}
return labels;
}
}

@ -15,6 +15,7 @@ import com.yuxue.util.FileUtil;
/**
* org.bytedeco.javacpp
* JavaCPP Java 访 C++
*
*
*

Loading…
Cancel
Save