diff --git a/open-anpr-core/src/main/java/com/visual/open/anpr/core/domain/PlateInfo.java b/open-anpr-core/src/main/java/com/visual/open/anpr/core/domain/PlateInfo.java new file mode 100755 index 0000000..24833ad --- /dev/null +++ b/open-anpr-core/src/main/java/com/visual/open/anpr/core/domain/PlateInfo.java @@ -0,0 +1,285 @@ +package com.visual.open.anpr.core.domain; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; + + +public class PlateInfo implements Comparable, Serializable { + /**车牌分数**/ + public float score; + /**车牌旋转角度**/ + public float angle; + /**车牌框**/ + public PlateBox box; + + /** + * 构造函数 + * @param score 车牌分数 + * @param box 车牌框 + * @param angle 车牌旋转角度 + */ + private PlateInfo(float score, PlateBox box, float angle) { + this.score = score; + this.angle = angle; + this.box = box; + } + + /** + * 构造一个车牌信息 + * @param score 车牌分数 + * @param box 车牌框 + */ + public static PlateInfo build(float score, PlateBox box){ + return new PlateInfo(score, box, 0); + } + + /** + * 构造一个车牌信息 + * @param score 车牌分数 + * @param box 车牌框 + * @param angle 车牌旋转角度 + */ + public static PlateInfo build(float score, PlateBox box, float angle){ + return new PlateInfo(score, box, angle); + } + + /** + * 对车牌框进行旋转对应的角度 + * @return + */ + public PlateBox rotateFaceBox(){ + return this.box.rotate(this.angle); + } + + @Override + public int compareTo(PlateInfo that) { + return Float.compare(that.score, this.score); + } + + /** + * 关键点 + */ + public static class Point implements Serializable { + /**坐标X的值**/ + public float x; + /**坐标Y的值**/ + public float y; + + /** + * 构造函数 + * @param x 坐标X的值 + * @param y 坐标Y的值 + */ + private Point(float x, float y){ + this.x = x; + this.y = y; + } + + /** + * 构造一个点 + * @param x 坐标X的值 + * @param y 坐标Y的值 + * @return + */ + public static Point build(float x, float y){ + return new Point(x, y); + } + + /** + * 对点进行中心旋转 + * @param center 中心点 + * @param angle 旋转角度 + * @return 旋转后的角 + */ + public Point rotation(Point center, float angle){ + double k = Math.toRadians(angle); + float nx1 = (float) ((this.x - center.x) * Math.cos(k) + (this.y - center.y) * Math.sin(k) + center.x); + float ny1 = (float) (-(this.x - center.x) * Math.sin(k) + (this.y - center.y) * Math.cos(k) + center.y); + return new Point(nx1, ny1); + } + + /** + * 计算两点之间的距离 + * @param that 点 + * @return 距离 + */ + public float distance(Point that){ + return (float) Math.sqrt(Math.pow((this.x-that.x), 2)+Math.pow((this.y-that.y), 2)); + } + } + + /** + * 标准坐标系下的车牌框 + */ + public static class PlateBox implements Serializable { + /**左上角坐标值**/ + public Point leftTop; + /**右上角坐标**/ + public Point rightTop; + /**右下角坐标**/ + public Point rightBottom; + /**左下角坐标**/ + public Point leftBottom; + + /** + * 构造函数 + * @param leftTop 左上角坐标值 + * @param rightTop 右上角坐标 + * @param rightBottom 右下角坐标 + * @param leftBottom 左下角坐标 + */ + public PlateBox(Point leftTop, Point rightTop, Point rightBottom, Point leftBottom) { + this.leftTop = leftTop; + this.rightTop = rightTop; + this.rightBottom = rightBottom; + this.leftBottom = leftBottom; + } + + /** + * 构造函数 + * @param x1 左上角坐标X的值 + * @param y1 左上角坐标Y的值 + * @param x2 右下角坐标X的值 + * @param y2 右下角坐标Y的值 + */ + private PlateBox(float x1, float y1, float x2, float y2){ + this.leftTop = Point.build(x1, y1); + this.rightTop = Point.build(x2, y1); + this.rightBottom = Point.build(x2, y2); + this.leftBottom = Point.build(x1, y2); + } + + /** + * 构造一个车牌框 + * @param x1 左上角坐标X的值 + * @param y1 左上角坐标Y的值 + * @param x2 右下角坐标X的值 + * @param y2 右下角坐标Y的值 + */ + public static PlateBox build(float x1, float y1, float x2, float y2){ + return new PlateBox((int)x1,(int)y1,(int)x2,(int)y2); + } + + /** + * x的最小坐标 + * @return + */ + public float x1(){ + return Math.min(Math.min(Math.min(leftTop.x, rightTop.x), rightBottom.x), leftBottom.x); + } + + /** + * y的最小坐标 + * @return + */ + public float y1(){ + return Math.min(Math.min(Math.min(leftTop.y, rightTop.y), rightBottom.y), leftBottom.y); + } + + /** + * x的最大坐标 + * @return + */ + public float x2(){ + return Math.max(Math.max(Math.max(leftTop.x, rightTop.x), rightBottom.x), leftBottom.x); + } + + /** + * y的最大坐标 + * @return + */ + public float y2(){ + return Math.max(Math.max(Math.max(leftTop.y, rightTop.y), rightBottom.y), leftBottom.y); + } + + /** + * 判断当前的车牌框是否是标准的车牌框,即非旋转后的车牌框。 + * @return 否是标准的车牌框 + */ + public boolean normal(){ + if((int)leftTop.x == (int)leftBottom.x && (int)leftTop.y == (int)rightTop.y){ + if((int)rightBottom.x == (int)rightTop.x && (int)rightBottom.y == (int)leftBottom.y){ + return true; + } + } + return false; + } + + /** + * 获取宽度 + * @return + */ + public float width(){ + return (float) Math.sqrt(Math.pow((rightTop.x-leftTop.x), 2)+Math.pow((rightTop.y-leftTop.y), 2)); + } + + /** + * 获取高度 + * @return + */ + public float height(){ + return (float) Math.sqrt(Math.pow((rightTop.x-rightBottom.x), 2)+Math.pow((rightTop.y-rightBottom.y), 2)); + } + + /** + * 获取面积 + * @return + */ + public float area(){ + return this.width() * this.height(); + } + + /** + * 中心点坐标 + * @return + */ + public Point center(){ + return Point.build((rightTop.x + leftBottom.x) / 2, (rightTop.y + leftBottom.y) / 2); + } + + /** + * 对车牌框进行旋转对应的角度 + * @param angle 旋转角 + * @return + */ + public PlateBox rotate(float angle){ + Point center = this.center(); + Point rPoint1 = this.leftTop.rotation(center, angle); + Point rPoint2 = this.rightTop.rotation(center, angle); + Point rPoint3 = this.rightBottom.rotation(center, angle); + Point rPoint4 = this.leftBottom.rotation(center, angle); + return new PlateBox(rPoint1, rPoint2, rPoint3, rPoint4); + } + + /** + * 中心缩放 + * @param scale + * @return + */ + public PlateBox scaling(float scale){ + //p1-p3 + float length_p1_p3 = leftTop.distance(rightBottom); + float x_diff_p1_p3 = leftTop.x-rightBottom.x; + float y_diff_p1_p3 = leftTop.y-rightBottom.y; + float change_p1_p3 = length_p1_p3 * (1-scale); + float change_x_p1_p3 = change_p1_p3 * x_diff_p1_p3 / length_p1_p3 / 2; + float change_y_p1_p3 = change_p1_p3 * y_diff_p1_p3 / length_p1_p3 / 2; + //p2-p4 + float length_p2_p4 = rightTop.distance(leftBottom); + float x_diff_p2_p4 = rightTop.x-leftBottom.x; + float y_diff_p2_p4 = rightTop.y-leftBottom.y; + float change_p2_p4 = length_p2_p4 * (1-scale); + float change_x_p2_p4 = change_p2_p4 * x_diff_p2_p4 / length_p2_p4 / 2; + float change_y_p2_p4 = change_p2_p4 * y_diff_p2_p4 / length_p2_p4 / 2; + //构造车牌框 + return new PlateBox( + new Point(leftTop.x - change_x_p1_p3, leftTop.y - change_y_p1_p3), + new Point(rightTop.x - change_x_p2_p4, rightTop.y - change_y_p2_p4), + new Point(rightBottom.x + change_x_p1_p3, rightBottom.y + change_y_p1_p3), + new Point(leftBottom.x + change_x_p2_p4, leftBottom.y + change_y_p2_p4) + ); + } + } + +}