diff --git a/src/main/java/com/yuxue/constant/Constant.java b/src/main/java/com/yuxue/constant/Constant.java index 4e05e489..b855d035 100644 --- a/src/main/java/com/yuxue/constant/Constant.java +++ b/src/main/java/com/yuxue/constant/Constant.java @@ -13,11 +13,11 @@ public class Constant { public static final String UTF8 = "UTF-8"; // 车牌识别, 默认车牌图片保存路径 - // public static String DEFAULT_DIR = "./PlateDetect/"; // 使用项目的相对路径 + //public static String DEFAULT_DIR = "./PlateDetect/"; // 使用项目的相对路径 public static String DEFAULT_DIR = "D:/PlateDetect/"; // 使用盘符的绝对路径 // 车牌识别, 默认车牌图片处理过程temp路径 - // public static String DEFAULT_TEMP_DIR = "./PlateDetect/temp/"; // 使用项目的相对路径 + //public static String DEFAULT_TEMP_DIR = "./PlateDetect/temp/"; // 使用项目的相对路径 public static String DEFAULT_TEMP_DIR = "D:/PlateDetect/temp/"; // 使用盘符的绝对路径 // 车牌识别,默认处理图片类型 @@ -26,7 +26,7 @@ public class Constant { public static String DEFAULT_ANN_PATH = "res/model/ann.xml"; //public static String DEFAULT_ANN_PATH = "D:/PlateDetect/train/chars_recognise_ann/ann.xml"; - public static String DEFAULT_SVM_PATH = "res/model/svm.xml"; + public static String DEFAULT_SVM_PATH = "res/model/svm.xml"; //svm2.xml为测试用 public static final int DEFAULT_WIDTH = 136; // cols public static final int DEFAULT_HEIGHT = 36; // rows diff --git a/src/main/java/com/yuxue/easypr/core/CoreFunc.java b/src/main/java/com/yuxue/easypr/core/CoreFunc.java index e0f8c226..200c03f6 100644 --- a/src/main/java/com/yuxue/easypr/core/CoreFunc.java +++ b/src/main/java/com/yuxue/easypr/core/CoreFunc.java @@ -119,7 +119,7 @@ public class CoreFunc { * * @param src * 车牌mat - * @param r + * @param color * 颜色模板 * @param adaptive_minsv * S和V的最小值由adaptive_minsv这个bool值判断 @@ -159,7 +159,10 @@ public class CoreFunc { return PlateColor.YELLOW; } else if (plateColorJudge(src, PlateColor.GREEN, adaptive_minsv) == true) { return PlateColor.GREEN; - } else { + } else if (plateColorJudge(src, PlateColor.BLACK, adaptive_minsv) == true) { + return PlateColor.BLACK; + } + else { return PlateColor.UNKNOWN; } } diff --git a/src/main/java/com/yuxue/easypr/core/PlateJudge.java b/src/main/java/com/yuxue/easypr/core/PlateJudge.java index a743ea45..9a2f35d0 100644 --- a/src/main/java/com/yuxue/easypr/core/PlateJudge.java +++ b/src/main/java/com/yuxue/easypr/core/PlateJudge.java @@ -1,6 +1,8 @@ package com.yuxue.easypr.core; +import com.yuxue.train.SVMTrain; import org.bytedeco.javacpp.opencv_core; + import org.bytedeco.javacpp.opencv_imgproc; import java.util.Vector; @@ -10,9 +12,11 @@ import org.bytedeco.javacpp.opencv_core.Rect; import org.bytedeco.javacpp.opencv_core.Size; import org.bytedeco.javacpp.opencv_ml.SVM; + import com.yuxue.constant.Constant; + /** * 车牌判断 * @author yuxue @@ -28,7 +32,7 @@ public class PlateJudge { public void loadSVM(String path) { svm.clear(); - // svm=SVM.loadSVM(path, "svm"); + //svm=SVM.loadSVM(path, "svm"); svm=SVM.load(path); } @@ -36,7 +40,7 @@ public class PlateJudge { * EasyPR的getFeatures回调函数, 用于从车牌的image生成svm的训练特征features */ private SVMCallback features = new Features(); - + /** * 对单幅图像进行SVM判断 @@ -47,12 +51,13 @@ public class PlateJudge { int ret = 1; // 使用com.yuxue.train.SVMTrain 生成的训练库文件 Mat features = this.features.getHistogramFeatures(inMat); - /*Mat samples = features.reshape(1, 1); - samples.convertTo(samples, opencv_core.CV_32F);*/ - - Mat p = features.reshape(1, 1); - p.convertTo(p, opencv_core.CV_32FC1); - ret = (int) svm.predict(features); + //Mat features = SVMTrain.getFeature(inMat); + Mat samples = features.reshape(1, 1); + samples.convertTo(samples, opencv_core.CV_32F); + + /*Mat p = features.reshape(1, 1); + p.convertTo(p, opencv_core.CV_32FC1);*/ + ret = (int) svm.predict(samples); return ret; // 使用com.yuxue.train.PlateRecoTrain 生成的训练库文件 @@ -62,13 +67,13 @@ public class PlateJudge { Mat dst = new Mat(); opencv_imgproc.Canny(grayImage, dst, 130, 250); Mat samples = dst.reshape(1, 1); - samples.convertTo(samples, opencv_core.CV_32F);*/ + samples.convertTo(samples, opencv_core.CV_32F); // 正样本为0 负样本为1 - /*if(svm.predict(samples) <= 0) { + if(svm.predict(samples) <= 0) { ret = 1; - }*/ - /*ret = (int)svm.predict(samples); + } + ret = (int)svm.predict(samples); System.err.println(ret); return ret ;*/ diff --git a/src/main/java/com/yuxue/easypr/core/PlateLocate.java b/src/main/java/com/yuxue/easypr/core/PlateLocate.java index c889d80d..d76d55dd 100644 --- a/src/main/java/com/yuxue/easypr/core/PlateLocate.java +++ b/src/main/java/com/yuxue/easypr/core/PlateLocate.java @@ -6,6 +6,7 @@ import static org.bytedeco.javacpp.opencv_core.*; import static org.bytedeco.javacpp.opencv_imgproc.*; import com.yuxue.constant.Constant; +import org.bytedeco.javacpp.opencv_highgui; import org.bytedeco.javacpp.opencv_imgcodecs; import org.bytedeco.javacpp.opencv_core.CvPoint2D32f; @@ -17,7 +18,6 @@ import org.bytedeco.javacpp.opencv_core.RotatedRect; import org.bytedeco.javacpp.opencv_core.Scalar; import org.bytedeco.javacpp.opencv_core.Size; - /** * 车牌定位 * @author yuxue @@ -117,12 +117,16 @@ public class PlateLocate { // 高斯模糊。Size中的数字影响车牌定位的效果。 GaussianBlur(src, src_blur, new Size(gaussianBlurSize, gaussianBlurSize), 0, 0, BORDER_DEFAULT); if (debug) { + //opencv_highgui.imshow("Plate Detected", src_blur); + //opencv_highgui.waitKey(0); opencv_imgcodecs.imwrite(tempPath + "debug_GaussianBlur.jpg", src_blur); } // Convert it to gray 将图像进行灰度化 cvtColor(src_blur, src_gray, CV_RGB2GRAY); if (debug) { + //opencv_highgui.imshow("Plate Detected", src_gray); + //opencv_highgui.waitKey(0); opencv_imgcodecs.imwrite(tempPath + "debug_gray.jpg", src_gray); } @@ -144,6 +148,8 @@ public class PlateLocate { addWeighted(abs_grad_x, SOBEL_X_WEIGHT, abs_grad_y, SOBEL_Y_WEIGHT, 0, grad); if (debug) { + //opencv_highgui.imshow("Plate Detected", grad); + //opencv_highgui.waitKey(0); opencv_imgcodecs.imwrite(tempPath + "debug_Sobel.jpg", grad); } @@ -153,6 +159,8 @@ public class PlateLocate { threshold(grad, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); if (debug) { + //opencv_highgui.imshow("Plate Detected", img_threshold); + //opencv_highgui.waitKey(0); opencv_imgcodecs.imwrite(tempPath + "debug_threshold.jpg", img_threshold); } @@ -162,6 +170,8 @@ public class PlateLocate { morphologyEx(img_threshold, img_threshold, MORPH_CLOSE, element); if (debug) { + //opencv_highgui.imshow("Plate Detected", img_threshold); + //opencv_highgui.waitKey(0); opencv_imgcodecs.imwrite(tempPath + "debug_morphology.jpg", img_threshold); } @@ -178,6 +188,8 @@ public class PlateLocate { // 将轮廓描绘到图上输出 drawContours(result, contours, -1, new Scalar(0, 0, 255, 255)); opencv_imgcodecs.imwrite(tempPath + "debug_Contours.jpg", result); + //opencv_highgui.imshow("Plate Detected", result); + //opencv_highgui.waitKey(0); } // Start to iterate to each contour founded @@ -275,6 +287,7 @@ public class PlateLocate { Mat resultResized = new Mat(); resultResized.create(HEIGHT, WIDTH, TYPE); + //大小调整,训练之前要保证图像大小一致 resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC); if (debug) { opencv_imgcodecs.imwrite(tempPath + "debug_resize_" + index + ".jpg", resultResized); diff --git a/src/main/java/com/yuxue/enumtype/PlateColor.java b/src/main/java/com/yuxue/enumtype/PlateColor.java index c305c2cf..d619d1c9 100644 --- a/src/main/java/com/yuxue/enumtype/PlateColor.java +++ b/src/main/java/com/yuxue/enumtype/PlateColor.java @@ -11,12 +11,14 @@ public enum PlateColor { BLUE("BLUE","蓝牌", 100, 130), GREEN("GREEN","绿牌", 38, 100), YELLOW("YELLOW","黄牌", 15, 40), + BLACK("BLACK", "黑牌", 0, 180), UNKNOWN("UNKNOWN","未知", 0, 0); public final String code; public final String desc; // opencv颜色识别的HSV中各个颜色所对应的H的范围: Orange 0-22 Yellow 22- 38 Green 38-75 Blue 75-130 + //新增黑牌H范围0-180,S范围0-255,V范围0-46 public final int minH; public final int maxH; diff --git a/src/main/java/com/yuxue/train/SVMTrain.java b/src/main/java/com/yuxue/train/SVMTrain.java index 98effbd6..93175d0c 100644 --- a/src/main/java/com/yuxue/train/SVMTrain.java +++ b/src/main/java/com/yuxue/train/SVMTrain.java @@ -1,5 +1,8 @@ package com.yuxue.train; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.WritableRaster; import java.io.File; import java.util.List; @@ -140,6 +143,9 @@ 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/BE_16888.jpg"); + doPridect(svm, DEFAULT_PATH + "test/BS_36359.jpg"); + doPridect(svm, DEFAULT_PATH + "test/1.png"); } public static void doPridect(SVM svm, String imgPath) { @@ -170,6 +176,26 @@ public class SVMTrain { } + /** + * org.opencv.core.Mat转java.awt.image.BufferedImage + * @param matrix + * @return + */ + public static BufferedImage toBufferedImage(Mat matrix) { + int type = BufferedImage.TYPE_BYTE_GRAY; + if (matrix.channels() > 1) { + type = BufferedImage.TYPE_3BYTE_BGR; + } + int bufferSize = matrix.channels() * matrix.cols() * matrix.rows(); + byte[] buffer = new byte[bufferSize]; + matrix.get(0, 0, buffer); // get all pixel from martix + BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type); + final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + System.arraycopy(buffer, 0, targetPixels, 0, buffer.length); + return image; + } + + public static Mat getFeature(Mat inMat) { Mat histogram = getHistogramFeatures(inMat); diff --git a/src/test/java/com/yuxue/test/PlateRecoTest.java b/src/test/java/com/yuxue/test/PlateRecoTest.java index 175324a5..020a666a 100644 --- a/src/test/java/com/yuxue/test/PlateRecoTest.java +++ b/src/test/java/com/yuxue/test/PlateRecoTest.java @@ -18,6 +18,11 @@ import com.yuxue.easypr.core.PlateLocate; import com.yuxue.enumtype.Direction; import com.yuxue.enumtype.PlateColor; +import static org.bytedeco.javacpp.opencv_core.CV_32F; +import static org.bytedeco.javacpp.opencv_core.CV_8UC3; +import static org.bytedeco.javacpp.opencv_imgproc.INTER_CUBIC; +import static org.bytedeco.javacpp.opencv_imgproc.resize; + /** * EasyPr车牌识别测试类 * - https://gitee.com/easypr/EasyPR 很老的项目了 @@ -89,9 +94,10 @@ public class PlateRecoTest { Mat img = matVector.get(i); // 弹窗显示 opencv_highgui.imshow("Plate Detected", img); - + opencv_highgui.waitKey(0); String str = "d:/test/" + i + ".png"; opencv_imgcodecs.imwrite(str, img); + } } } @@ -104,7 +110,7 @@ public class PlateRecoTest { */ @Test public void testPlateLocate() { - String imgPath = "res/image/test_image/test.jpg"; + String imgPath = "res/image/test_image/test3.jpg"; Mat src = opencv_imgcodecs.imread(imgPath); @@ -177,7 +183,27 @@ public class PlateRecoTest { System.out.println(result); } + /** + * 切图 + */ + @Test + public void testCut() { + String path = "D:/PlateDetect/train/plate_detect_svm/test/"; + Mat inMat = opencv_imgcodecs.imread(path + "BS_36359.jpg"); + Mat grayImage = new Mat(); + opencv_imgproc.cvtColor(inMat, grayImage, opencv_imgproc.CV_RGB2GRAY); + Mat dst = new Mat(); + opencv_imgproc.Canny(grayImage, dst, 130, 250); + Mat samples = dst.reshape(1, 1); + samples.convertTo(samples, CV_32F); + + //Mat resultResized = new Mat(); + //resultResized.create(36,136, CV_8UC3); + //大小调整,训练之前要保证图像大小一致 + //resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC); + opencv_imgcodecs.imwrite("D:/" + "debug_resize" + ".jpg", samples); + } /**