no commit message

devA
yuxue 5 years ago
parent 1bd4dfe821
commit 910398c8ab

@ -24,6 +24,7 @@ import org.opencv.imgproc.Imgproc;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yuxue.enumtype.PlateColor;
/**
@ -69,8 +70,8 @@ public class ImageUtil {
public static void main(String[] args) {
Instant start = Instant.now();
String tempPath = DEFAULT_BASE_TEST_PATH + "test/";
String filename = tempPath + "/100_yuantu.jpg";
filename = tempPath + "/100_yuantu3.jpg";
String filename = tempPath + "/100_yuantu.jpg";
filename = tempPath + "/100_yuantu1.jpg";
// filename = tempPath + "/109_crop_0.png";
Mat src = Imgcodecs.imread(filename);
@ -79,10 +80,10 @@ public class ImageUtil {
Mat gsMat = ImageUtil.gaussianBlur(src, debug, tempPath);
Mat grey = ImageUtil.grey(gsMat, debug, tempPath);
Mat gray = ImageUtil.gray(gsMat, debug, tempPath);
Mat sobel = ImageUtil.sobel(grey, debug, tempPath);
// Mat sobel = ImageUtil.scharr(grey, debug, tempPath);
Mat sobel = ImageUtil.sobel(gray, debug, tempPath);
// Mat sobel = ImageUtil.scharr(gray, debug, tempPath);
Mat threshold = ImageUtil.threshold(sobel, debug, tempPath);
@ -92,17 +93,32 @@ public class ImageUtil {
Vector<Mat> rects = ImageUtil.screenBlock(src, contours, debug, tempPath);
PlateUtil.loadSvmModel("D:/PlateDetect/train/plate_detect_svm/svm2.xml");
PlateUtil.loadAnnModel("D:/PlateDetect/train/chars_recognise_ann/ann.xml");
Vector<Mat> dst = new Vector<Mat>();
PalteUtil.hasPlate(rects, dst, "D:/PlateDetect/train/plate_detect_svm/svm2.xml", debug, tempPath);
PlateUtil.hasPlate(rects, dst, debug, tempPath);
System.err.println("识别到的车牌数量:" + dst.size());
dst.stream().forEach(inMat -> {
PlateColor color = PlateUtil.getPlateColor(inMat, true, debug, tempPath);
System.err.println(color.desc);
Vector<Mat> charMat = new Vector<Mat>();
PlateUtil.charsSegment(inMat, color, charMat, debug, tempPath);
});
/*String filename = tempPath + "/hsvMat_1590994270425.jpg";
Mat src = Imgcodecs.imread(filename);
Vector<Mat> charMat = new Vector<Mat>();
PlateUtil.charsSegment(src, PlateColor.BLUE, charMat, true, tempPath);*/
// ImageUtil.rgb2Hsv(src, debug, tempPath);
// ImageUtil.getHSVValue(src, debug, tempPath);
Instant end = Instant.now();
System.err.println("总耗时:" + Duration.between(start, end).toMillis());
}
@ -131,7 +147,7 @@ public class ImageUtil {
* @param tempPath
* @return
*/
public static Mat grey(Mat inMat, Boolean debug, String tempPath) {
public static Mat gray(Mat inMat, Boolean debug, String tempPath) {
Mat dst = new Mat();
Imgproc.cvtColor(inMat, dst, Imgproc.COLOR_BGR2GRAY);
if (debug) {
@ -291,7 +307,6 @@ public class ImageUtil {
// CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
Imgproc.findContours(inMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
// 在小连接处分割轮廓
if (debug) {
Mat result = new Mat();
src.copyTo(result); // 复制一张图,不在原图上进行操作,防止后续需要使用原图
@ -346,7 +361,7 @@ public class ImageUtil {
Mat img_crop = new Mat();
Imgproc.getRectSubPix(src, rect_size, mr.center, img_crop);
if (debug) {
Imgcodecs.imwrite(tempPath + debugMap.get("crop") + "_crop_" + j + ".png", img_crop);
// Imgcodecs.imwrite(tempPath + debugMap.get("crop") + "_crop_" + j + ".png", img_crop);
}
// 处理切图,调整为指定大小
Mat resized = new Mat(HEIGHT, WIDTH, TYPE);
@ -424,7 +439,7 @@ public class ImageUtil {
Core.merge(hsvSplit, dst);
if (debug) {
Imgcodecs.imwrite(tempPath + "hsvMat_"+System.currentTimeMillis()+".jpg", dst);
// Imgcodecs.imwrite(tempPath + "hsvMat_"+System.currentTimeMillis()+".jpg", dst);
}
return dst;
}

@ -1,15 +1,22 @@
package com.yuxue.util;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;
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.core.MatOfPoint;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.ANN_MLP;
import org.opencv.ml.SVM;
@ -27,15 +34,18 @@ import com.yuxue.train.SVMTrain;
* @author yuxue
* @date 2020-05-28 15:11
*/
public class PalteUtil {
public class PlateUtil {
// 车牌定位处理步骤该map用于表示步骤图片的顺序
private static Map<String, Integer> debugMap = Maps.newLinkedHashMap();
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
debugMap.put("platePredict", 0);
debugMap.put("colorMatch", 0);
debugMap.put("char_threshold", 0);
debugMap.put("plateThreshold", 0);
debugMap.put("plateContours", 0);
debugMap.put("plateCrop", 0);
debugMap.put("char_clearLiuDing", 0); // 去除柳钉
debugMap.put("specMat", 0);
debugMap.put("chineseMat", 0);
@ -47,6 +57,9 @@ public class PalteUtil {
entry.setValue(index);
index ++;
}
/*loadSvmModel("D:/PlateDetect/train/plate_detect_svm/svm2.xml");
loadAnnModel("D:/PlateDetect/train/chars_recognise_ann/ann.xml");*/
}
private static SVM svm = SVM.create();
@ -97,22 +110,17 @@ 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,
Boolean debug, String tempPath) {
loadSvmModel(modelPath);
public static void hasPlate(Vector<Mat> inMat, Vector<Mat> dst, Boolean debug, String tempPath) {
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) {
System.err.println("目标符合");
Imgcodecs.imwrite(tempPath + "199_plate_reco_" + i + ".png", src);
Imgcodecs.imwrite(tempPath + debugMap.get("platePredict") + "_platePredict" + i + ".png", src);
}
i++;
} else {
@ -122,8 +130,8 @@ public class PalteUtil {
}
return;
}
/**
*
* @param inMat
@ -132,7 +140,7 @@ public class PalteUtil {
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;
}
@ -145,7 +153,7 @@ public class PalteUtil {
return PlateColor.UNKNOWN;
}
/**
*
* @param inMat
@ -197,18 +205,161 @@ public class PalteUtil {
}
}
}
// 获取颜色匹配后的二值灰度图
List<Mat> hsvSplit = Lists.newArrayList();
Core.split(hsvMat, hsvSplit);
Mat grey = hsvSplit.get(2);
float percent = (float) Core.countNonZero(grey) / (grey.rows() * grey.cols());
Mat gray = hsvSplit.get(2);
float percent = (float) Core.countNonZero(gray) / (gray.rows() * gray.cols());
if (debug) {
Imgcodecs.imwrite(tempPath + debugMap.get("colorMatch") + "_colorMatch.jpg", grey);
Imgcodecs.imwrite(tempPath + debugMap.get("colorMatch") + "_colorMatch.jpg", gray);
}
return percent;
}
/**
*
* @param inMat
* @param charMat vector
* @param debug
* @param tempPath
*/
public static final int DEFAULT_ANGLE = 30; // 角度判断所用常量
public static void charsSegment(Mat inMat, PlateColor color, Vector<Mat> charMat, Boolean debug, String tempPath) {
Mat gray = new Mat();
Imgproc.cvtColor(inMat, gray, Imgproc.COLOR_BGR2GRAY);
Mat threshold = new Mat();
switch (color) {
case BLUE:
Imgproc.threshold(gray, threshold, 10, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY);
break;
case YELLOW:
Imgproc.threshold(gray, threshold, 10, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY_INV);
break;
case GREEN:
Imgproc.threshold(gray, threshold, 10, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY_INV);
break;
default:
return;
}
// 图片处理,降噪等
if (debug) {
Imgcodecs.imwrite(tempPath + debugMap.get("plateThreshold") + "_plateThreshold.jpg", threshold);
}
// 获取轮廓
Mat contour = new Mat();
threshold.copyTo(contour);
List<MatOfPoint> contours = Lists.newArrayList();
// 提取外部轮廓
Imgproc.findContours(contour, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
if (debug) {
Mat result = new Mat();
inMat.copyTo(result);
Imgproc.drawContours(result, contours, -1, new Scalar(0, 0, 255, 255));
Imgcodecs.imwrite(tempPath + debugMap.get("plateContours") + "_plateContours.jpg", result);
}
Vector<Rect> rt = new Vector<Rect>();
for (int i = 0; i < contours.size(); i++) {
Rect mr = Imgproc.boundingRect(contours.get(i));
if (checkCharSizes(mr)) {
rt.add(mr);
}
}
if(null == rt || rt.size() <= 0) {
return;
}
Vector<Rect> sorted = new Vector<Rect>();
sortRect(rt, sorted);
Vector<Mat> dst = new Vector<Mat>();
for (int i = 0; i < sorted.size(); i++) {
Mat img_crop = new Mat(threshold, sorted.get(i));
img_crop = preprocessChar(img_crop);
dst.add(img_crop);
Imgcodecs.imwrite(tempPath + debugMap.get("plateCrop") + "_plateCrop_" + i + ".jpg", img_crop);
}
return;
}
/**
* :
*
* @param in
* @return
*/
final static int CHAR_SIZE = 20;
private static Mat preprocessChar(Mat in) {
int h = in.rows();
int w = in.cols();
Mat transformMat = Mat.eye(2, 3, CvType.CV_32F);
int m = Math.max(w, h);
transformMat.put(0, 2, (m - w) / 2f);
transformMat.put(1, 2, (m - h) / 2f);
Mat warpImage = new Mat(m, m, in.type());
Imgproc.warpAffine(in, warpImage, transformMat, warpImage.size(), Imgproc.INTER_LINEAR, Core.BORDER_CONSTANT, new Scalar(0));
Mat resized = new Mat(CHAR_SIZE, CHAR_SIZE, CvType.CV_8UC3);
Imgproc.resize(warpImage, resized, resized.size(), 0, 0, Imgproc.INTER_CUBIC);
return resized;
}
/**
*
* 1
* @param r
* @return
*/
public static Boolean checkCharSizes(Rect r) {
float minHeight = 15f;
float maxHeight = 35f;
double charAspect = r.size().width / r.size().height;
return charAspect <1 && minHeight <= r.size().height && r.size().height < maxHeight;
}
/**
* Rect
* @param vecRect
* @param out
* @return
*/
public static void sortRect(Vector<Rect> vecRect, Vector<Rect> out) {
Map<Integer, Integer> map = Maps.newHashMap();
for (int i = 0; i < vecRect.size(); ++i) {
map.put(vecRect.get(i).x, i);
}
Set<Integer> set = map.keySet();
Object[] arr = set.toArray();
Arrays.sort(arr);
for (Object key : arr) {
out.add(vecRect.get(map.get(key)));
}
return;
}
}
Loading…
Cancel
Save