|
|
package com.yuxue.train;
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
import static org.bytedeco.javacpp.opencv_core.*;
|
|
|
import static org.bytedeco.javacpp.opencv_ml.*;
|
|
|
|
|
|
import org.bytedeco.javacpp.opencv_core;
|
|
|
import org.bytedeco.javacpp.opencv_imgcodecs;
|
|
|
|
|
|
import com.yuxue.easypr.core.Features;
|
|
|
import com.yuxue.easypr.core.SVMCallback;
|
|
|
import com.yuxue.util.Convert;
|
|
|
import com.yuxue.util.FileUtil;
|
|
|
|
|
|
/**
|
|
|
* 鍩轰簬org.bytedeco.javacpp鍖呭疄鐜扮殑璁粌
|
|
|
* JavaCPP 鏄竴涓紑婧愬簱锛屽畠鎻愪緵浜嗗湪 Java 涓珮鏁堣闂湰鍦<E6B9B0> C++鐨勬柟娉<E69F9F>
|
|
|
*
|
|
|
* 鍥剧墖璇嗗埆杞︾墝璁粌
|
|
|
* 璁粌鍑烘潵鐨勫簱鏂囦欢锛岀敤浜庡垽鏂垏鍥炬槸鍚﹀寘鍚溅鐗<E6BA85>
|
|
|
*
|
|
|
* 璁粌鐨剆vm.xml搴旂敤锛<E695A4>
|
|
|
* 1銆佹浛鎹es/model/svm.xml鏂囦欢
|
|
|
* 2銆佷慨鏀筩om.yuxue.easypr.core.PlateJudge.plateJudge(Mat) 鏂规硶
|
|
|
* 灏嗘牱鏈鐞嗘柟娉曞垏鎹竴涓嬶紝鍗冲皢瀵瑰簲琚敞閲婃帀鐨勬ā鍧椾唬鐮佸彇娑堟敞閲<E6959E>
|
|
|
* @author yuxue
|
|
|
* @date 2020-05-14 22:16
|
|
|
*/
|
|
|
public class SVMTrain1 {
|
|
|
|
|
|
private SVMCallback callback = new Features();
|
|
|
|
|
|
// 榛樿鐨勮缁冩搷浣滅殑鏍圭洰褰<E6B4B0>
|
|
|
private static final String DEFAULT_PATH = "D:/PlateDetect/train/plate_detect_svm/";
|
|
|
|
|
|
// 璁粌妯″瀷鏂囦欢淇濆瓨浣嶇疆
|
|
|
private static final String MODEL_PATH = DEFAULT_PATH + "svm4.xml";
|
|
|
|
|
|
private static final String hasPlate = "HasPlate";
|
|
|
private static final String noPlate = "NoPlate";
|
|
|
|
|
|
public SVMTrain1() {
|
|
|
}
|
|
|
|
|
|
public SVMTrain1(SVMCallback callback) {
|
|
|
this.callback = callback;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 灏唋earn鏂囦欢澶逛笅鐨勫浘鐗囷紝杞瓨鍒皌ain test鏂囦欢澶逛笅锛屽尯鍒唄asPalte noPlate
|
|
|
* 闅忔満閫夊彇bound%浣滀负璁粌鏁版嵁锛<E5B581>30%浣滀负娴嬭瘯鏁版嵁
|
|
|
* @param bound
|
|
|
* @param name
|
|
|
*/
|
|
|
private void learn2Plate(float bound, final String name) {
|
|
|
final String filePath = DEFAULT_PATH + "learn/" + name;
|
|
|
Vector<String> files = new Vector<String>();
|
|
|
|
|
|
//// 鑾峰彇璇ヨ矾寰勪笅鐨勬墍鏈夋枃浠<E69E83>
|
|
|
FileUtil.getFiles(filePath, files);
|
|
|
int size = files.size();
|
|
|
if (0 == size) {
|
|
|
System.err.println("褰撳墠鐩綍涓嬫病鏈夋枃浠<E69E83>: " + filePath);
|
|
|
return;
|
|
|
}
|
|
|
Collections.shuffle(files, new Random(new Date().getTime()));
|
|
|
|
|
|
//// 闅忔満閫夊彇70%浣滀负璁粌鏁版嵁锛<E5B581>30%浣滀负娴嬭瘯鏁版嵁
|
|
|
int boundry = (int) (bound * size);
|
|
|
|
|
|
// 閲嶆柊鍒涘缓鐩綍
|
|
|
FileUtil.recreateDir(DEFAULT_PATH + "train/" + name);
|
|
|
FileUtil.recreateDir(DEFAULT_PATH + "test/" + name);
|
|
|
|
|
|
for (int i = 0; i < boundry; i++) {
|
|
|
Mat img = opencv_imgcodecs.imread(files.get(i));
|
|
|
String str = DEFAULT_PATH + "train/" + name + "/" + name + "_" + Integer.valueOf(i).toString() + ".jpg";
|
|
|
opencv_imgcodecs.imwrite(str, img);
|
|
|
}
|
|
|
|
|
|
for (int i = boundry; i < size; i++) {
|
|
|
Mat img = opencv_imgcodecs.imread(files.get(i));
|
|
|
String str = DEFAULT_PATH + "test/" + name + "/" + name + "_" + Integer.valueOf(i).toString() + ".jpg";
|
|
|
opencv_imgcodecs.imwrite(str, img);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 鑾峰彇璁粌鍥剧墖
|
|
|
* @param trainingImages
|
|
|
* @param trainingLabels
|
|
|
* @param name
|
|
|
*/
|
|
|
private void getPlateTrain(Mat trainingImages, Vector<Integer> trainingLabels, final String name, int label) {
|
|
|
// int label = 1;
|
|
|
final String filePath = DEFAULT_PATH + "train/" + name;
|
|
|
Vector<String> files = new Vector<String>();
|
|
|
|
|
|
// 鑾峰彇璇ヨ矾寰勪笅鐨勬墍鏈夋枃浠<E69E83>
|
|
|
FileUtil.getFiles(filePath, files);
|
|
|
|
|
|
int size = files.size();
|
|
|
if (null == files || size <= 0) {
|
|
|
System.out.println("File not found in " + filePath);
|
|
|
return;
|
|
|
}
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
// System.out.println(files.get(i));
|
|
|
Mat inMat = opencv_imgcodecs.imread(files.get(i));
|
|
|
// 璋冪敤鍥炶皟鍑芥暟鍐冲畾鐗瑰緛
|
|
|
// Mat features = this.callback.getHisteqFeatures(inMat);
|
|
|
Mat features = this.callback.getHistogramFeatures(inMat);
|
|
|
// 閫氳繃鐩存柟鍥惧潎琛″寲鍚庣殑褰╄壊鍥捐繘琛岄娴<EE95A9>
|
|
|
Mat p = features.reshape(1, 1);
|
|
|
p.convertTo(p, opencv_core.CV_32F);
|
|
|
|
|
|
// 136 36 14688 1 鍙樻崲灏哄
|
|
|
// System.err.println(inMat.cols() + "\t" + inMat.rows() + "\t" + p.cols() + "\t" + p.rows());
|
|
|
|
|
|
trainingImages.push_back(p); // 鍚堝苟鎴愪竴寮犲浘鐗<E6B598>
|
|
|
trainingLabels.add(label);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void getPlateTest(MatVector testingImages, Vector<Integer> testingLabels, final String name, int label) {
|
|
|
// int label = 1;
|
|
|
final String filePath = DEFAULT_PATH + "test/" + name;
|
|
|
Vector<String> files = new Vector<String>();
|
|
|
FileUtil.getFiles(filePath, files);
|
|
|
|
|
|
int size = files.size();
|
|
|
if (0 == size) {
|
|
|
System.out.println("File not found in " + filePath);
|
|
|
return;
|
|
|
}
|
|
|
System.out.println("get " + name + " test!");
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
Mat inMat = opencv_imgcodecs.imread(files.get(i));
|
|
|
testingImages.push_back(inMat);
|
|
|
testingLabels.add(label);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ! 娴嬭瘯SVM鐨勫噯纭巼锛屽洖褰掔巼浠ュ強FScore
|
|
|
public void getAccuracy(Mat testingclasses_preditc, Mat testingclasses_real) {
|
|
|
int channels = testingclasses_preditc.channels();
|
|
|
System.out.println("channels: " + Integer.valueOf(channels).toString());
|
|
|
int nRows = testingclasses_preditc.rows();
|
|
|
System.out.println("nRows: " + Integer.valueOf(nRows).toString());
|
|
|
int nCols = testingclasses_preditc.cols() * channels;
|
|
|
System.out.println("nCols: " + Integer.valueOf(nCols).toString());
|
|
|
int channels_real = testingclasses_real.channels();
|
|
|
System.out.println("channels_real: " + Integer.valueOf(channels_real).toString());
|
|
|
int nRows_real = testingclasses_real.rows();
|
|
|
System.out.println("nRows_real: " + Integer.valueOf(nRows_real).toString());
|
|
|
int nCols_real = testingclasses_real.cols() * channels;
|
|
|
System.out.println("nCols_real: " + Integer.valueOf(nCols_real).toString());
|
|
|
|
|
|
double count_all = 0;
|
|
|
double ptrue_rtrue = 0;
|
|
|
double ptrue_rfalse = 0;
|
|
|
double pfalse_rtrue = 0;
|
|
|
double pfalse_rfalse = 0;
|
|
|
|
|
|
for (int i = 0; i < nRows; i++) {
|
|
|
|
|
|
final float predict = Convert.toFloat(testingclasses_preditc.ptr(i));
|
|
|
final float real = Convert.toFloat(testingclasses_real.ptr(i));
|
|
|
|
|
|
count_all++;
|
|
|
|
|
|
// System.out.println("predict:" << predict).toString());
|
|
|
// System.out.println("real:" << real).toString());
|
|
|
|
|
|
if (predict == 1.0 && real == 1.0)
|
|
|
ptrue_rtrue++;
|
|
|
if (predict == 1.0 && real == 0)
|
|
|
ptrue_rfalse++;
|
|
|
if (predict == 0 && real == 1.0)
|
|
|
pfalse_rtrue++;
|
|
|
if (predict == 0 && real == 0)
|
|
|
pfalse_rfalse++;
|
|
|
}
|
|
|
|
|
|
System.out.println("count_all: " + Double.valueOf(count_all).toString());
|
|
|
System.out.println("ptrue_rtrue: " + Double.valueOf(ptrue_rtrue).toString());
|
|
|
System.out.println("ptrue_rfalse: " + Double.valueOf(ptrue_rfalse).toString());
|
|
|
System.out.println("pfalse_rtrue: " + Double.valueOf(pfalse_rtrue).toString());
|
|
|
System.out.println("pfalse_rfalse: " + Double.valueOf(pfalse_rfalse).toString());
|
|
|
|
|
|
double precise = 0;
|
|
|
if (ptrue_rtrue + ptrue_rfalse != 0) {
|
|
|
precise = ptrue_rtrue / (ptrue_rtrue + ptrue_rfalse);
|
|
|
System.out.println("precise: " + Double.valueOf(precise).toString());
|
|
|
} else {
|
|
|
System.out.println("precise: NA");
|
|
|
}
|
|
|
|
|
|
double recall = 0;
|
|
|
if (ptrue_rtrue + pfalse_rtrue != 0) {
|
|
|
recall = ptrue_rtrue / (ptrue_rtrue + pfalse_rtrue);
|
|
|
System.out.println("recall: " + Double.valueOf(recall).toString());
|
|
|
} else {
|
|
|
System.out.println("recall: NA");
|
|
|
}
|
|
|
|
|
|
if (precise + recall != 0) {
|
|
|
double F = (precise * recall) / (precise + recall);
|
|
|
System.out.println("F: " + Double.valueOf(F).toString());
|
|
|
} else {
|
|
|
System.out.println("F: NA");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 璁粌
|
|
|
* @param dividePrepared
|
|
|
* @return
|
|
|
*/
|
|
|
public int svmTrain(boolean dividePrepared) {
|
|
|
|
|
|
Mat classes = new Mat();
|
|
|
Mat trainingData = new Mat();
|
|
|
Mat trainingImages = new Mat();
|
|
|
Vector<Integer> trainingLabels = new Vector<Integer>();
|
|
|
|
|
|
// 鍒嗗壊learn閲岀殑鏁版嵁鍒皌rain鍜宼est閲<74> // 浠庡簱閲岄潰閫夊彇璁粌鏍锋湰
|
|
|
if (!dividePrepared) {
|
|
|
learn2Plate(0.1f, hasPlate); // 鎬ц兘涓嶅ソ鐨勬満鍣紝鏈<E7B49D>濂戒笉瑕佹寫閫夊お澶氱殑鏍锋湰锛岃繖涓柟妗堝お娑堣<E5A891>楄祫婧愪簡銆<E7B0A1>
|
|
|
learn2Plate(0.1f, noPlate);
|
|
|
}
|
|
|
|
|
|
// System.err.println("Begin to get train data to memory");
|
|
|
|
|
|
getPlateTrain(trainingImages, trainingLabels, hasPlate, 0);
|
|
|
getPlateTrain(trainingImages, trainingLabels, noPlate, 1);
|
|
|
|
|
|
// System.err.println(trainingImages.cols());
|
|
|
|
|
|
trainingImages.copyTo(trainingData);
|
|
|
trainingData.convertTo(trainingData, CV_32F);
|
|
|
|
|
|
int[] labels = new int[trainingLabels.size()];
|
|
|
for (int i = 0; i < trainingLabels.size(); ++i) {
|
|
|
labels[i] = trainingLabels.get(i).intValue();
|
|
|
}
|
|
|
new Mat(labels).copyTo(classes);
|
|
|
|
|
|
TrainData train_data = TrainData.create(trainingData, ROW_SAMPLE, classes);
|
|
|
|
|
|
SVM svm = SVM.create();
|
|
|
|
|
|
try {
|
|
|
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 20000, 0.0001);
|
|
|
svm.setTermCriteria(criteria); // 鎸囧畾
|
|
|
svm.setKernel(SVM.RBF); // 浣跨敤棰勫厛瀹氫箟鐨勫唴鏍稿垵濮嬪寲
|
|
|
svm.setType(SVM.C_SVC); // SVM鐨勭被鍨<E8A2AB>,榛樿鏄細SVM.C_SVC
|
|
|
svm.setGamma(0.1); // 鏍稿嚱鏁扮殑鍙傛暟
|
|
|
svm.setNu(0.1); // SVM浼樺寲闂鍙傛暟
|
|
|
svm.setC(1); // SVM浼樺寲闂鐨勫弬鏁癈
|
|
|
svm.setP(0.1);
|
|
|
svm.setDegree(0.1);
|
|
|
svm.setCoef0(0.1);
|
|
|
|
|
|
svm.trainAuto(train_data, 10,
|
|
|
SVM.getDefaultGrid(SVM.C),
|
|
|
SVM.getDefaultGrid(SVM.GAMMA),
|
|
|
SVM.getDefaultGrid(SVM.P),
|
|
|
SVM.getDefaultGrid(SVM.NU),
|
|
|
SVM.getDefaultGrid(SVM.COEF),
|
|
|
SVM.getDefaultGrid(SVM.DEGREE),
|
|
|
true);
|
|
|
|
|
|
} catch (Exception err) {
|
|
|
System.out.println(err.getMessage());
|
|
|
}
|
|
|
|
|
|
System.out.println("Svm generate done!");
|
|
|
|
|
|
/*FileStorage fsTo = new FileStorage(MODEL_PATH, FileStorage.WRITE);
|
|
|
svm.write(fsTo, "svm");*/
|
|
|
svm.save(MODEL_PATH);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// 娴嬭瘯
|
|
|
public int svmPredict() {
|
|
|
SVM svm = SVM.create();
|
|
|
try {
|
|
|
svm.clear();
|
|
|
// svm = SVM.loadSVM(MODEL_PATH, "svm");
|
|
|
svm = SVM.load(MODEL_PATH);
|
|
|
} catch (Exception err) {
|
|
|
System.err.println(err.getMessage());
|
|
|
return 0; // next predict requires svm
|
|
|
}
|
|
|
|
|
|
System.out.println("Begin to predict");
|
|
|
// Test SVM
|
|
|
MatVector testingImages = new MatVector();
|
|
|
Vector<Integer> testingLabels_real = new Vector<Integer>();
|
|
|
|
|
|
// 灏嗘祴璇曟暟鎹姞杞藉叆鍐呭瓨
|
|
|
getPlateTest(testingImages, testingLabels_real, hasPlate, 0);
|
|
|
getPlateTest(testingImages, testingLabels_real, noPlate, 1);
|
|
|
|
|
|
double count_all = 0;
|
|
|
double ptrue_rtrue = 0;
|
|
|
double ptrue_rfalse = 0;
|
|
|
double pfalse_rtrue = 0;
|
|
|
double pfalse_rfalse = 0;
|
|
|
|
|
|
long size = testingImages.size();
|
|
|
System.err.println(size);
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
Mat inMat = testingImages.get(i);
|
|
|
|
|
|
// Mat features = callback.getHisteqFeatures(inMat);
|
|
|
Mat features = callback.getHistogramFeatures(inMat);
|
|
|
Mat p = features.reshape(1, 1);
|
|
|
p.convertTo(p, opencv_core.CV_32F);
|
|
|
|
|
|
// System.out.println(p.cols() + "\t" + p.rows() + "\t" + p.type());
|
|
|
|
|
|
// samples.cols == var_count && samples.type() == CV_32F
|
|
|
// var_count 鐨勫<E990A8>间細鍦╯vm.xml搴撴枃浠朵腑鏈変綋鐜<E7B68B>
|
|
|
float predoct = svm.predict(features);
|
|
|
|
|
|
int predict = (int) predoct; // 棰勬湡鍊<E6B9A1>
|
|
|
int real = testingLabels_real.get(i); // 瀹為檯鍊<E6AAAF>
|
|
|
|
|
|
if (predict == 1 && real == 1)
|
|
|
ptrue_rtrue++;
|
|
|
if (predict == 1 && real == 0)
|
|
|
ptrue_rfalse++;
|
|
|
if (predict == 0 && real == 1)
|
|
|
pfalse_rtrue++;
|
|
|
if (predict == 0 && real == 0)
|
|
|
pfalse_rfalse++;
|
|
|
}
|
|
|
|
|
|
count_all = size;
|
|
|
System.out.println("Get the Accuracy!");
|
|
|
|
|
|
System.out.println("count_all: " + Double.valueOf(count_all).toString());
|
|
|
System.out.println("ptrue_rtrue: " + Double.valueOf(ptrue_rtrue).toString());
|
|
|
System.out.println("ptrue_rfalse: " + Double.valueOf(ptrue_rfalse).toString());
|
|
|
System.out.println("pfalse_rtrue: " + Double.valueOf(pfalse_rtrue).toString());
|
|
|
System.out.println("pfalse_rfalse: " + Double.valueOf(pfalse_rfalse).toString());
|
|
|
|
|
|
double precise = 0;
|
|
|
if (ptrue_rtrue + ptrue_rfalse != 0) {
|
|
|
precise = ptrue_rtrue / (ptrue_rtrue + ptrue_rfalse);
|
|
|
System.out.println("precise: " + Double.valueOf(precise).toString());
|
|
|
} else
|
|
|
System.out.println("precise: NA");
|
|
|
|
|
|
double recall = 0;
|
|
|
if (ptrue_rtrue + pfalse_rtrue != 0) {
|
|
|
recall = ptrue_rtrue / (ptrue_rtrue + pfalse_rtrue);
|
|
|
System.out.println("recall: " + Double.valueOf(recall).toString());
|
|
|
} else
|
|
|
System.out.println("recall: NA");
|
|
|
|
|
|
double Fsocre = 0;
|
|
|
if (precise + recall != 0) {
|
|
|
Fsocre = 2 * (precise * recall) / (precise + recall);
|
|
|
System.out.println("Fsocre: " + Double.valueOf(Fsocre).toString());
|
|
|
} else
|
|
|
System.out.println("Fsocre: NA");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
SVMTrain1 s = new SVMTrain1();
|
|
|
s.svmTrain(true);
|
|
|
s.svmPredict();
|
|
|
}
|
|
|
|
|
|
}
|