测试工具类

devA
yuxue 5 years ago
parent 19575f5e9b
commit c5d6723405

@ -24,7 +24,7 @@ import org.bytedeco.javacpp.opencv_core.Size;
* @date 2020-04-24 15:33
*/
public class PlateLocate {
// PlateLocate所用常量
public static final int DEFAULT_GAUSSIANBLUR_SIZE = 5;
public static final int SOBEL_SCALE = 1;
@ -46,7 +46,7 @@ public class PlateLocate {
final float DEFAULT_ERROR = 0.6f;
final float DEFAULT_ASPECT = 3.75f;
// 角度判断所用常量
public static final int DEFAULT_ANGLE = 30;
@ -68,7 +68,7 @@ public class PlateLocate {
// 是否开启调试模式0关闭非0开启
protected boolean debug = true;
// 开启调试模式之后,切图文件保存路径
protected String tempPath = Constant.DEFAULT_TEMP_DIR + System.currentTimeMillis() + "/";
@ -193,51 +193,45 @@ public class PlateLocate {
int k = 1;
for (int i = 0; i < rects.size(); i++) {
RotatedRect minRect = rects.get(i);
if (verifySizes(minRect)) {
if (debug) {
Point2f rect_points = new Point2f(4);
minRect.points(rect_points);
for (int j = 0; j < 4; j++) {
Point pt1 = new Point(new CvPoint2D32f(rect_points.position(j)));
Point pt2 = new Point(new CvPoint2D32f(rect_points.position((j + 1) % 4)));
line(result, pt1, pt2, new Scalar(0, 255, 255, 255), 1, 8, 0);
}
}
if (debug) {
Point2f rect_points = new Point2f(4);
minRect.points(rect_points);
// rotated rectangle drawing
// 旋转这部分代码确实可以将某些倾斜的车牌调整正,但是它也会误将更多正的车牌搞成倾斜!所以综合考虑,还是不使用这段代码。
// 2014-08-14,由于新到的一批图片中发现有很多车牌是倾斜的,因此决定再次尝试这段代码。
for (int j = 0; j < 4; j++) {
Point pt1 = new Point(new CvPoint2D32f(rect_points.position(j)));
Point pt2 = new Point(new CvPoint2D32f(rect_points.position((j + 1) % 4)));
float r = minRect.size().width() / minRect.size().height();
float angle = minRect.angle();
Size rect_size = new Size((int) minRect.size().width(), (int) minRect.size().height());
if (r < 1) {
angle = 90 + angle;
rect_size = new Size(rect_size.height(), rect_size.width());
}
// 如果抓取的方块旋转超过m_angle角度则不是车牌放弃处理
if (angle - this.angle < 0 && angle + this.angle > 0) {
// Create and rotate image
Mat rotmat = getRotationMatrix2D(minRect.center(), angle, 1);
Mat img_rotated = new Mat();
warpAffine(src, img_rotated, rotmat, src.size()); // CV_INTER_CUBIC
Mat resultMat = showResultMat(img_rotated, rect_size, minRect.center(), k++);
resultVec.add(resultMat);
line(result, pt1, pt2, new Scalar(0, 255, 255, 255), 1, 8, 0);
}
}
}
if (debug) {
opencv_imgcodecs.imwrite(tempPath + "debug_result.jpg", result);
// rotated rectangle drawing
// 旋转这部分代码确实可以将某些倾斜的车牌调整正,但是它也会误将更多正的车牌搞成倾斜!所以综合考虑,还是不使用这段代码。
// 2014-08-14,由于新到的一批图片中发现有很多车牌是倾斜的,因此决定再次尝试这段代码。
float r = minRect.size().width() / minRect.size().height();
float angle = minRect.angle();
Size rect_size = new Size((int) minRect.size().width(), (int) minRect.size().height());
if (r < 1) {
angle = 90 + angle;
rect_size = new Size(rect_size.height(), rect_size.width());
}
// 如果抓取的方块旋转超过m_angle角度则不是车牌放弃处理
if (angle - this.angle < 0 && angle + this.angle > 0) {
// Create and rotate image
Mat rotmat = getRotationMatrix2D(minRect.center(), angle, 1);
Mat img_rotated = new Mat();
warpAffine(src, img_rotated, rotmat, src.size()); // CV_INTER_CUBIC
Mat resultMat = showResultMat(img_rotated, rect_size, minRect.center(), k++);
resultVec.add(resultMat);
}
}
return resultVec;
}
/**
* minAreaRect
*
@ -251,7 +245,7 @@ public class PlateLocate {
float aspect = this.aspect;
int min = 44 * 14 * verifyMin; // minimum area
int max = 44 * 14 * verifyMax; // maximum area
// Get only patchs that match to a respect ratio.
float rmin = aspect - aspect * error;
float rmax = aspect + aspect * error;
@ -260,7 +254,7 @@ public class PlateLocate {
float r = mr.size().width() / mr.size().height();
if (r < 1)
r = mr.size().height() / mr.size().width();
return area >= min && area <= max && r >= rmin && r <= rmax;
}
@ -289,8 +283,8 @@ public class PlateLocate {
return resultResized;
}
public String getTempPath() {
return tempPath;
}
@ -298,7 +292,7 @@ public class PlateLocate {
public void setTempPath(String tempPath) {
this.tempPath = tempPath;
}
public void setGaussianBlurSize(int gaussianBlurSize) {
this.gaussianBlurSize = gaussianBlurSize;
}
@ -357,5 +351,5 @@ public class PlateLocate {
public boolean getDebug() {
return debug;
}
}

@ -1,6 +1,5 @@
package com.yuxue.util;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
@ -19,7 +18,6 @@ import org.bytedeco.javacpp.opencv_imgcodecs;
import org.bytedeco.javacpp.opencv_imgproc;
import com.google.common.collect.Maps;
import com.yuxue.constant.Constant;
/**
@ -30,23 +28,23 @@ import com.yuxue.constant.Constant;
public class ImageUtil {
private static SVM svm = SVM.create();
private static ANN_MLP ann=ANN_MLP.create();
private static String DEFAULT_BASE_TEST_PATH = "D:/PlateDetect/temp/";
public static void loadSVM(String path) {
public static void loadSvmModel(String path) {
svm.clear();
svm=SVM.load(path);
}
// 加载ann配置文件 图像转文字的训练库文件
public static void loadModel(String path) {
public static void loadAnnModel(String path) {
ann.clear();
ann = ANN_MLP.load(path);
}
// 车牌定位处理步骤该map用于表示步骤图片的顺序
private static Map<String, Integer> debugMap = Maps.newLinkedHashMap();
static {
@ -67,36 +65,40 @@ public class ImageUtil {
// debugMap.put("specMat", 11);
// debugMap.put("chineseMat", 12);
// debugMap.put("char_auxRoi", 13);
// 加载训练库文件
//loadModel(Constant.DEFAULT_ANN_PATH);
//loadSVM(Constant.DEFAULT_SVM_PATH);
//loadAnnModel(Constant.DEFAULT_ANN_PATH);
//loadSvmModel(Constant.DEFAULT_SVM_PATH);
}
public static void main(String[] args) {
String tempPath = DEFAULT_BASE_TEST_PATH + "test/";
String filename = tempPath + "/100_yuantu.jpg";
Mat inMat = opencv_imgcodecs.imread(filename);
Mat src = opencv_imgcodecs.imread(filename);
Boolean debug = true;
Mat gsMat = ImageUtil.gaussianBlur(inMat, debug, tempPath);
Mat gsMat = ImageUtil.gaussianBlur(src, debug, tempPath);
Mat grey = ImageUtil.grey(gsMat, debug, tempPath);
Mat sobel = ImageUtil.sobel(grey, debug, tempPath);
Mat threshold = ImageUtil.threshold(sobel, debug, tempPath);
Mat morphology = ImageUtil.morphology(threshold, debug, tempPath);
MatVector contours = ImageUtil.contours(inMat, morphology, debug, tempPath);
MatVector contours = ImageUtil.contours(src, morphology, debug, tempPath);
Vector<Mat> rects = ImageUtil.screenBlock(src, contours, debug, tempPath);
// ImageUtil.rgb2Hsv(inMat, debug, tempPath);
System.err.println("done!!!");
}
@ -117,7 +119,7 @@ public class ImageUtil {
return dst;
}
/**
*
* @param inMat
@ -200,7 +202,7 @@ public class ImageUtil {
public static Mat morphology(Mat inMat, Boolean debug, String tempPath) {
Mat dst = new Mat();
Size size = new Size(DEFAULT_MORPH_SIZE_WIDTH, DEFAULT_MORPH_SIZE_HEIGHT);
Mat element = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, size);
opencv_imgproc.morphologyEx(inMat, dst, opencv_imgproc.MORPH_CLOSE, element);
@ -209,8 +211,8 @@ public class ImageUtil {
}
return dst;
}
/**
* Find of possibles plates
*
@ -222,20 +224,21 @@ public class ImageUtil {
*/
public static MatVector contours(Mat src, Mat inMat, Boolean debug, String tempPath) {
MatVector contours = new MatVector();
opencv_imgproc.findContours(inMat, contours, // a vector of contours
opencv_imgproc.CV_RETR_EXTERNAL, // 提取外部轮廓
opencv_imgproc.CV_CHAIN_APPROX_NONE); // all pixels of each contours
// 提取外部轮廓
opencv_imgproc.findContours(inMat, contours, opencv_imgproc.CV_RETR_EXTERNAL, opencv_imgproc.CV_CHAIN_APPROX_NONE);
if (debug) {
Mat result = new Mat();
src.copyTo(result); // 复制一张图,不在原图上进行操作,防止后续需要使用原图
// 将轮廓描绘到原图
opencv_imgproc.drawContours(src, contours, -1, new Scalar(0, 0, 255, 255));
opencv_imgproc.drawContours(result, contours, -1, new Scalar(0, 0, 255, 255));
// 输出带轮廓的原图
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("contours") + 100) + "_contours.jpg", src);
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("contours") + 100) + "_contours.jpg", result);
}
return contours;
}
/**
*
* @param src
@ -249,78 +252,94 @@ public class ImageUtil {
public static final int DEFAULT_VERIFY_MIN = 3;
public static final int DEFAULT_VERIFY_MAX = 20;
public static final int DEFAULT_ANGLE = 30; // 角度判断所用常量
public static final int WIDTH = 136;
public static final int HEIGHT = 36;
public static final int TYPE = opencv_core.CV_8UC3;
@SuppressWarnings("resource")
public static Vector<Mat> screenBlock(Mat src, MatVector contours, Boolean debug, String tempPath){
MatVector rects = new MatVector();
// Vector<RotatedRect> rects = new Vector<RotatedRect>();
Vector<Mat> dst = new Vector<Mat>();
MatVector mv = new MatVector();
for (int i = 0; i < contours.size(); ++i) {
// RotatedRect 该类表示平面上的旋转矩形,有三个属性: 矩形中心点(质心); 边长(长和宽); 旋转角度
RotatedRect mr = opencv_imgproc.minAreaRect(contours.get(i));
float angle = Math.abs(mr.angle());
if (verifySizes(mr)) {
// rects.add(mr);
// 判断旋转角度 ±30°
if (angle <= DEFAULT_ANGLE) {
rects.put(mr);
// 旋转角度
Mat rotmat = opencv_imgproc.getRotationMatrix2D(mr.center(), angle, 1);
Mat img_rotated = new Mat();
opencv_imgproc.warpAffine(src, img_rotated, rotmat, src.size()); // CV_INTER_CUBIC
if (verifySizes(mr) && angle <= DEFAULT_ANGLE) { // 判断尺寸及旋转角度 ±30°排除不合法的图块
if (debug) { // 描绘出筛选后的轮廓
mv.put(contours.get(i));
Mat result = new Mat();
src.copyTo(result); // 复制一张图,不在原图上进行操作,防止后续需要使用原图
// 将轮廓描绘到原图
opencv_imgproc.drawContours(result, mv, -1, new Scalar(0, 0, 255, 255));
// 输出带轮廓的原图
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("screenblock") + 100) + "_screenblock.jpg", result);
}
// 旋转角度,根据需要是否进行角度旋转
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°
rect_size = new Size(rect_size.height(), rect_size.width());
}
Mat rotmat = opencv_imgproc.getRotationMatrix2D(mr.center(), angle, 1);
Mat img_rotated = new Mat();
opencv_imgproc.warpAffine(src, img_rotated, rotmat, src.size()); // CV_INTER_CUBIC
// 切图
Mat img_crop = new Mat();
opencv_imgproc.getRectSubPix(src, rect_size, mr.center(), img_crop);
if (debug) {
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("crop") + 100) + "_crop_" + i + ".jpg", img_crop);
}
// 处理切图,调整为指定大小
Mat resized = new Mat(HEIGHT, WIDTH, TYPE);
opencv_imgproc.resize(img_crop, resized, resized.size(), 0, 0, opencv_imgproc.INTER_CUBIC);
if (debug) {
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("resize") + 100) + "_resize_" + i + ".jpg", resized);
}
dst.add(resized);
}
}
if (debug) {
// 将轮廓描绘到原图
opencv_imgproc.drawContours(src, rects, -1, new Scalar(0, 0, 255, 255));
// 输出带轮廓的原图
opencv_imgcodecs.imwrite(tempPath + (debugMap.get("screenblock") + 100) + "_screenblock.jpg", src);
}
return null;
return dst;
}
/**
* minAreaRect
* @param mr
* @return
*/
private static boolean verifySizes(RotatedRect mr) {
// China car plate size: 440mm*140mmaspect 3.142857
int min = 44 * 14 * DEFAULT_VERIFY_MIN;
int max = 44 * 14 * DEFAULT_VERIFY_MAX;
// Get only patchs that match to a respect ratio.
float rmin = DEFAULT_ASPECT - DEFAULT_ASPECT * DEFAULT_ERROR;
float rmax = DEFAULT_ASPECT + DEFAULT_ASPECT * DEFAULT_ERROR;
// 计算面积
int area = (int) (mr.size().height() * mr.size().width());
// 计算纵横比
float r = mr.size().width() / mr.size().height();
if (r < 1) {
r = mr.size().height() / mr.size().width();
}
return min <= area && area <= max && rmin <= r && r <= rmax;
}
* minAreaRect
* @param mr
* @return
*/
private static boolean verifySizes(RotatedRect mr) {
// China car plate size: 440mm*140mmaspect 3.142857
int min = 44 * 14 * DEFAULT_VERIFY_MIN;
int max = 44 * 14 * DEFAULT_VERIFY_MAX;
// Get only patchs that match to a respect ratio.
float rmin = DEFAULT_ASPECT - DEFAULT_ASPECT * DEFAULT_ERROR;
float rmax = DEFAULT_ASPECT + DEFAULT_ASPECT * DEFAULT_ERROR;
// 计算面积
int area = (int) (mr.size().height() * mr.size().width());
// 计算纵横比
float r = mr.size().width() / mr.size().height();
if (r < 1) {
r = mr.size().height() / mr.size().width();
}
return min <= area && area <= max && rmin <= r && r <= rmax;
}
/**
* rgbhsv

Loading…
Cancel
Save