From 68d1979fd3e8f92d805e584e863a3b63ae66cf97 Mon Sep 17 00:00:00 2001 From: yuxue Date: Sun, 31 May 2020 21:33:38 +0800 Subject: [PATCH] no commit message --- src/main/java/com/yuxue/util/ImageUtil.java | 8 +- src/main/java/com/yuxue/util/PalteUtil.java | 115 ++++++++++++++++++-- 2 files changed, 106 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/yuxue/util/ImageUtil.java b/src/main/java/com/yuxue/util/ImageUtil.java index d7bbe75d..26cc0ec4 100644 --- a/src/main/java/com/yuxue/util/ImageUtil.java +++ b/src/main/java/com/yuxue/util/ImageUtil.java @@ -57,11 +57,6 @@ public class ImageUtil { debugMap.put("screenblock", 0); // 外部轮廓筛选 debugMap.put("crop", 0); // 切图 debugMap.put("resize", 0); // 切图resize - debugMap.put("char_threshold", 0); - debugMap.put("char_clearLiuDing", 0); // 去除柳钉 - debugMap.put("specMat", 0); - debugMap.put("chineseMat", 0); - debugMap.put("char_auxRoi", 0); // 设置index, 用于debug生成文件时候按名称排序 Integer index = 100; @@ -75,7 +70,7 @@ public class ImageUtil { Instant start = Instant.now(); String tempPath = DEFAULT_BASE_TEST_PATH + "test/"; String filename = tempPath + "/100_yuantu.jpg"; - filename = tempPath + "/100_yuantu4.jpg"; + filename = tempPath + "/100_yuantu3.jpg"; // filename = tempPath + "/109_crop_0.png"; Mat src = Imgcodecs.imread(filename); @@ -336,7 +331,6 @@ public class ImageUtil { if (checkPlateSize(mr) && angle <= DEFAULT_ANGLE) { // 判断尺寸及旋转角度 ±30°,排除不合法的图块 mv.add(contours.get(i)); - Size rect_size = new Size((int) mr.size.width, (int) mr.size.height); if (mr.size.width / mr.size.height < 1) { // 宽度小于高度 angle = 90 + angle; // 旋转90° diff --git a/src/main/java/com/yuxue/util/PalteUtil.java b/src/main/java/com/yuxue/util/PalteUtil.java index 2859f82b..c2c60414 100644 --- a/src/main/java/com/yuxue/util/PalteUtil.java +++ b/src/main/java/com/yuxue/util/PalteUtil.java @@ -1,6 +1,9 @@ package com.yuxue.util; +import java.util.List; +import java.util.Map; import java.util.Vector; +import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -10,6 +13,8 @@ import org.opencv.imgcodecs.Imgcodecs; import org.opencv.ml.ANN_MLP; import org.opencv.ml.SVM; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.yuxue.constant.Constant; import com.yuxue.enumtype.PlateColor; import com.yuxue.train.SVMTrain; @@ -23,9 +28,25 @@ import com.yuxue.train.SVMTrain; * @date 2020-05-28 15:11 */ public class PalteUtil { - + + // 车牌定位处理步骤,该map用于表示步骤图片的顺序 + private static Map debugMap = Maps.newLinkedHashMap(); static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + debugMap.put("colorMatch", 0); + debugMap.put("char_threshold", 0); + debugMap.put("char_clearLiuDing", 0); // 去除柳钉 + debugMap.put("specMat", 0); + debugMap.put("chineseMat", 0); + debugMap.put("char_auxRoi", 0); + + // 设置index, 用于debug生成文件时候按名称排序 + Integer index = 200; + for (Entry entry : debugMap.entrySet()) { + entry.setValue(index); + index ++; + } } private static SVM svm = SVM.create(); @@ -48,7 +69,6 @@ public class PalteUtil { /*System.err.println(PalteUtil.isPlate("粤AI234K")); System.err.println(PalteUtil.isPlate("鄂CD3098"));*/ - System.err.println("done!!!"); } @@ -61,8 +81,6 @@ public class PalteUtil { public static Boolean isPlate(String str) { Pattern p = Pattern.compile(Constant.plateReg); Boolean bl = false; - - //提取车牌 Matcher m = p.matcher(str); while(m.find()) { bl = true; @@ -82,14 +100,14 @@ public class PalteUtil { public static void hasPlate(Vector inMat, Vector dst, String modelPath, Boolean debug, String tempPath) { loadSvmModel(modelPath); - + int i = 0; for (Mat src : inMat) { if(src.rows() == DEFAULT_HEIGHT && src.cols() == DEFAULT_WIDTH) { Mat samples = SVMTrain.getFeature(src); - + float flag = svm.predict(samples); - + if (flag == 0) { dst.add(src); if(debug) { @@ -104,16 +122,93 @@ public class PalteUtil { } return; } - + + /** * 判断切图车牌颜色 * @param inMat * @return */ - public static PlateColor getPlateColor(Mat inMat) { + public static PlateColor getPlateColor(Mat inMat, Boolean adaptive_minsv, Boolean debug, String tempPath) { + // 判断阈值 + final float thresh = 0.49f; + + if(colorMatch(inMat, PlateColor.BLUE, adaptive_minsv, debug, tempPath) > thresh) { + return PlateColor.BLUE; + } + if(colorMatch(inMat, PlateColor.YELLOW, adaptive_minsv, debug, tempPath) > thresh) { + return PlateColor.YELLOW; + } + if(colorMatch(inMat, PlateColor.GREEN, adaptive_minsv, debug, tempPath) > thresh) { + return PlateColor.GREEN; + } + return PlateColor.UNKNOWN; + } + + + /** + * 颜色匹配计算 + * @param inMat + * @param r + * @param adaptive_minsv + * @param debug + * @param tempPath + * @return + */ + public static Float colorMatch(Mat inMat, PlateColor r, Boolean adaptive_minsv, Boolean debug, String tempPath) { + final float max_sv = 255; + final float minref_sv = 64; + final float minabs_sv = 95; + + Mat hsvMat = ImageUtil.rgb2Hsv(inMat, debug, tempPath); + + // 匹配模板基色,切换以查找想要的基色 + int min_h = r.minH; + int max_h = r.maxH; + float diff_h = (float) ((max_h - min_h) / 2); + int avg_h = (int) (min_h + diff_h); + + for (int i = 0; i < hsvMat.rows(); ++i) { + for (int j = 0; j < hsvMat.cols(); j += 3) { + int H = (int)hsvMat.get(i, j)[0]; + int S = (int)hsvMat.get(i, j)[1]; + int V = (int)hsvMat.get(i, j)[2]; + + boolean colorMatched = false; + + if ( min_h < H && H <= max_h) { + int Hdiff = Math.abs(H - avg_h); + float Hdiff_p = Hdiff / diff_h; + float min_sv = 0; + if (adaptive_minsv) { + min_sv = minref_sv - minref_sv / 2 * (1 - Hdiff_p); + } else { + min_sv = minabs_sv; + } + if ((min_sv < S && S <= max_sv) && (min_sv < V && V <= max_sv)) { + colorMatched = true; + } + } + if (colorMatched == true) { + hsvMat.put(i, j, 0, 0, 255); + } else { + hsvMat.put(i, j, 0, 0, 0); + } + } + } + + // 获取颜色匹配后的二值灰度图 + List hsvSplit = Lists.newArrayList(); + Core.split(hsvMat, hsvSplit); + Mat grey = hsvSplit.get(2); + + float percent = (float) Core.countNonZero(grey) / (grey.rows() * grey.cols()); + if (debug) { + Imgcodecs.imwrite(tempPath + debugMap.get("colorMatch") + "_colorMatch.jpg", grey); + } - return PlateColor.UNKNOWN; + return percent; } }