修改svm训练算法,优化车牌识别过程

devA
yuxue 5 years ago
parent fb3ce75810
commit dd0aa0636c

@ -4,6 +4,7 @@ import java.io.File;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.TermCriteria;
@ -13,7 +14,9 @@ import org.opencv.ml.Ml;
import org.opencv.ml.SVM;
import org.opencv.ml.TrainData;
import com.google.common.collect.Lists;
import com.yuxue.constant.Constant;
import com.yuxue.enumtype.Direction;
import com.yuxue.util.FileUtil;
/**
@ -42,7 +45,7 @@ public class SVMTrain {
private static final String DEFAULT_PATH = "D:/PlateDetect/train/plate_detect_svm/";
// 训练模型文件保存位置
private static final String MODEL_PATH = DEFAULT_PATH + "svm.xml";
private static final String MODEL_PATH = DEFAULT_PATH + "svm2.xml";
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
@ -87,17 +90,25 @@ public class SVMTrain {
Mat inMat = Imgcodecs.imread(path); // 读取样本文件
// 创建一个行数为sample_num, 列数为 rows*cols 的矩阵; 用于存放样本
if (trainingDataMat == null) {
/*if (trainingDataMat == null) {
trainingDataMat = new Mat(sample_num, inMat.rows() * inMat.cols(), CvType.CV_32F);
}
}*/
// 样本文件处理,这里是为了过滤不需要的特征,减少训练时间 // 根据实际情况需要进行处理
Mat greyMat = new Mat();
/*Mat greyMat = new Mat();
Imgproc.cvtColor(inMat, greyMat, Imgproc.COLOR_BGR2GRAY); // 转成灰度图
Mat dst = new Mat(inMat.rows(), inMat.cols(), inMat.type());
Imgproc.Canny(greyMat, dst, 130, 250); // 边缘检测
Mat dst = new Mat();
Imgproc.threshold(greyMat, dst, 100, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY);
Mat dst = new Mat(inMat.rows(), inMat.cols(), inMat.type());
Imgproc.Canny(greyMat, dst, 130, 250);*/
Mat dst = getFeature(inMat);
if (trainingDataMat == null) {
trainingDataMat = new Mat(sample_num, dst.rows() * dst.cols(), CvType.CV_32F);
}
// 将样本矩阵转换成只有一行的矩阵保存为float数组
float[] arr = new float[dst.rows() * dst.cols()];
int l = 0;
@ -108,10 +119,11 @@ public class SVMTrain {
l++;
}
}
trainingDataMat.put(i, 0, arr); // 多张图合并到一张
}
// Imgcodecs.imwrite(DEFAULT_PATH + "trainingDataMat.jpg", trainingDataMat);
// 配置SVM训练器参数
@ -146,27 +158,24 @@ public class SVMTrain {
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 = Imgcodecs.imread(imgPath);// 图片大小要和样本一致
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
/*Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
Mat dst = new Mat();
Imgproc.threshold(src, dst, 100, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY);
Mat dst = new Mat();
Imgproc.Canny(src, dst, 130, 250);
Mat samples = dst.reshape(1, 1);
samples.convertTo(samples, CvType.CV_32F);
samples.convertTo(samples, CvType.CV_32F);*/
Mat dst = getFeature(src);
// 等价于上面两行代码
/*Mat samples = new Mat(1, dst.cols() * dst.rows(), CvType.CV_32F);
@ -180,14 +189,14 @@ public class SVMTrain {
}
}
samples.put(0, 0, arr);*/
// Imgcodecs.imwrite(DEFAULT_PATH + "test_1.jpg", samples);
// 如果训练时使用这个标识那么符合的图像会返回9.0
float flag = svm.predict(samples);
float flag = svm.predict(dst);
// System.err.println(flag);
System.err.println(flag);
if (flag == 0) {
System.err.println(imgPath + " 目标符合");
}
@ -209,4 +218,111 @@ public class SVMTrain {
return labels;
}
public static Mat getFeature(Mat inMat) {
Mat histogram = getHistogramFeatures(inMat);
Mat color = getColorFeatures(inMat);
List<Mat> list = Lists.newArrayList();
list.add(histogram);
list.add(color);
Mat dst = new Mat();
// hconcat 水平拼接 // vconcat 垂直拼接
Core.hconcat(list, dst);
return dst;
}
public static Mat getHistogramFeatures(Mat src) {
Mat img_grey = new Mat();
Imgproc.cvtColor(src, img_grey, Imgproc.COLOR_BGR2GRAY);
Mat img_threshold = new Mat();
Imgproc.threshold(img_grey, img_threshold, 0, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY);
// Histogram features
float[] vhist = projectedHistogram(img_threshold, Direction.VERTICAL);
float[] hhist = projectedHistogram(img_threshold, Direction.HORIZONTAL);
// Last 10 is the number of moments components
int numCols = vhist.length + hhist.length;
Mat features = Mat.zeros(1, numCols, CvType.CV_32F);
int j = 0;
for (int i = 0; i < vhist.length; i++) {
features.put(0, j, vhist[i]);
j++;
}
for (int i = 0; i < hhist.length; i++) {
features.put(0, j, hhist[i]);
j++;
}
return features;
}
public static float[] projectedHistogram(Mat inMat, Direction direction){
Mat img = new Mat();
inMat.copyTo(img);
int sz = img.rows();
if(Direction.VERTICAL.equals(direction)) {
sz = img.cols();
}
// 统计这一行或一列中非零元素的个数并保存到nonZeroMat中
float[] nonZeroMat = new float[sz];
Core.extractChannel(img, img, 0); // 提取0通道
for (int j = 0; j < sz; j++) {
Mat data = Direction.HORIZONTAL.equals(direction) ? img.row(j) : img.col(j);
int count = Core.countNonZero(data);
nonZeroMat[j] = count;
}
// Normalize histogram
float max = 1F;
for (int j = 0; j < nonZeroMat.length; j++) {
max = Math.max(max, nonZeroMat[j]);
}
for (int j = 0; j < nonZeroMat.length; j++) {
nonZeroMat[j] /= max;
}
return nonZeroMat;
}
public static Mat getColorFeatures(Mat src) {
Mat src_hsv = new Mat();
Imgproc.cvtColor(src, src_hsv, Imgproc.COLOR_BGR2GRAY);
int sz = 180;
int[] h = new int[180];
for (int i = 0; i < src_hsv.rows(); i++) {
for (int j = 0; j < src_hsv.cols(); j++) {
int H = (int) src_hsv.get(i, j)[0];// 0-180
if (H > sz - 1) {
H = sz - 1;
}
if (H < 0) {
H = 0;
}
h[H]++;
}
}
// 创建黑色的图
Mat features = Mat.zeros(1, sz, CvType.CV_32F);
for (int j = 0; j < sz; j++) {
features.put(0, j, (float)h[j]);
}
MinMaxLocResult m = Core.minMaxLoc(features);
double max = m.maxVal;
if (max > 0) {
features.convertTo(features, -1, 1.0f / max, 0);
}
return features;
}
}

@ -21,6 +21,7 @@ import org.opencv.imgproc.Imgproc;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yuxue.constant.Constant;
/**
@ -40,14 +41,14 @@ public class ImageUtil {
// 车牌定位处理步骤该map用于表示步骤图片的顺序
private static Map<String, Integer> debugMap = Maps.newLinkedHashMap();
static {
debugMap.put("yuantu", 0); // 高斯模糊
debugMap.put("yuantu", 0); // 原图
debugMap.put("gaussianBlur", 1); // 高斯模糊
debugMap.put("gray", 2); // 图像灰度化
debugMap.put("sobel", 3); // Sobel 算子
debugMap.put("sobel", 3); // Sobel 运算,得到图像的一阶水平方向导数
debugMap.put("threshold", 4); //图像二值化
debugMap.put("morphology", 5); // 图像闭操作
debugMap.put("contours", 6); // 提取外部轮廓
debugMap.put("screenblock", 7); // 提取外部轮廓
debugMap.put("screenblock", 7); // 外部轮廓筛选
debugMap.put("result", 8); // 原图处理结果
debugMap.put("crop", 9); // 切图
debugMap.put("resize", 10); // 切图resize
@ -68,7 +69,7 @@ public class ImageUtil {
String tempPath = DEFAULT_BASE_TEST_PATH + "test/";
String filename = tempPath + "/100_yuantu.jpg";
filename = tempPath + "/100_yuantu2.jpg";
filename = tempPath + "/100_yuantu1.jpg";
//filename = tempPath + "/109_crop_0.png";
Mat src = Imgcodecs.imread(filename);
@ -89,6 +90,11 @@ public class ImageUtil {
List<MatOfPoint> contours = ImageUtil.contours(src, morphology, debug, tempPath);
Vector<Mat> rects = ImageUtil.screenBlock(src, contours, debug, tempPath);
Vector<Mat> dst = new Vector<Mat>();
PalteUtil.hasPlate(rects, dst, "D:/PlateDetect/train/plate_detect_svm/svm2.xml", debug, tempPath);
System.err.println("识别到的车牌数量:" + dst.size());
// ImageUtil.rgb2Hsv(src, debug, tempPath);
// ImageUtil.getHSVValue(src, debug, tempPath);
@ -254,7 +260,7 @@ public class ImageUtil {
Imgcodecs.imwrite(tempPath + (debugMap.get("morphology") + 100) + "_morphology0.jpg", dst);
}
// 去除小连通区域
/*// 去除小连通区域
Mat a = clearSmallConnArea(dst, 3, 10, false, tempPath);
Mat b = clearSmallConnArea(a, 10, 3, false, tempPath);
// 去除孔洞
@ -263,8 +269,8 @@ public class ImageUtil {
if (debug) {
Imgcodecs.imwrite(tempPath + (debugMap.get("morphology") + 100) + "_morphology1.jpg", d);
}
return d;
}*/
return dst;
}

@ -5,14 +5,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.ml.ANN_MLP;
import org.opencv.ml.SVM;
import com.yuxue.constant.Constant;
import com.yuxue.enumtype.PlateColor;
import com.yuxue.train.SVMTrain;
/**
@ -23,11 +23,11 @@ import com.yuxue.enumtype.PlateColor;
* @date 2020-05-28 15:11
*/
public class PalteUtil {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private static SVM svm = SVM.create();
private static ANN_MLP ann=ANN_MLP.create();
@ -42,17 +42,17 @@ public class PalteUtil {
ann.clear();
ann = ANN_MLP.load(path);
}
public static void main(String[] args) {
/*System.err.println(PalteUtil.isPlate("粤AI234K"));
System.err.println(PalteUtil.isPlate("鄂CD3098"));*/
System.err.println("done!!!");
}
/**
*
* @param str
@ -70,8 +70,8 @@ public class PalteUtil {
}
return bl;
}
/**
*
* @param inMat
@ -79,39 +79,39 @@ public class PalteUtil {
*/
public static final int DEFAULT_WIDTH = 136;
public static final int DEFAULT_HEIGHT = 36;
public static void hasPlate(Vector<Mat> inMat, Vector<Mat> dst, String modelPath) {
public static void hasPlate(Vector<Mat> inMat, Vector<Mat> dst, String modelPath,
Boolean debug, String tempPath) {
loadSvmModel(modelPath);
inMat.stream().forEach(src -> {
int i = 0;
for (Mat src : inMat) {
if(src.rows() == DEFAULT_HEIGHT && src.cols() == DEFAULT_WIDTH) {
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
Imgproc.Canny(src, src, 130, 250);
Mat samples = src.reshape(1, 1);
samples.convertTo(samples, CvType.CV_32F);
Mat samples = SVMTrain.getFeature(src);
float flag = svm.predict(samples);
if (flag == 0) {
// System.out.println("目标符合");
System.err.println("目标符合");
dst.add(src);
Imgcodecs.imwrite(tempPath + "199_plate_reco_" + i + ".png", src);
i++;
} else {
// System.out.println("目标不符合");
System.out.println("目标不符合");
}
}
});
}
return;
}
/**
*
* @param inMat
* @return
*/
public static PlateColor getPlateColor(Mat inMat) {
return PlateColor.UNKNOWN;
}
}

Loading…
Cancel
Save