Browse Source

init

master
diven 2 years ago
parent
commit
3e7c8e4b19
  1. 2
      open-anpr-core/src/main/java/com/visual/open/anpr/core/base/PlateRecognition.java
  2. 54
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Clipper.java
  3. 691
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/ClipperBase.java
  4. 481
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/ClipperOffset.java
  5. 2518
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/DefaultClipper.java
  6. 339
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Edge.java
  7. 26
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/LongRect.java
  8. 414
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Path.java
  9. 125
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Paths.java
  10. 220
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Point.java
  11. 116
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/PolyNode.java
  12. 37
      open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/PolyTree.java
  13. 39
      open-anpr-core/src/main/java/com/visual/open/anpr/core/domain/Polygon.java
  14. 4
      open-anpr-core/src/main/java/com/visual/open/anpr/core/models/TorchPlateRecognition.java

2
open-anpr-core/src/main/java/com/visual/open/anpr/core/base/PlateRecognition.java

@ -6,5 +6,5 @@ import com.visual.open.anpr.core.domain.PlateInfo.ParseInfo;
public interface PlateRecognition { public interface PlateRecognition {
ParseInfo inference(ImageMat image, boolean single, Map<String, Object> params); ParseInfo inference(ImageMat image, Boolean single, Map<String, Object> params);
} }

54
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Clipper.java

@ -1,54 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
public interface Clipper {
enum ClipType {
INTERSECTION, UNION, DIFFERENCE, XOR
}
enum Direction {
RIGHT_TO_LEFT, LEFT_TO_RIGHT
}
enum EndType {
CLOSED_POLYGON, CLOSED_LINE, OPEN_BUTT, OPEN_SQUARE, OPEN_ROUND
}
enum JoinType {
SQUARE, ROUND, MITER
}
enum PolyFillType {
EVEN_ODD, NON_ZERO, POSITIVE, NEGATIVE
}
enum PolyType {
SUBJECT, CLIP
}
interface ZFillCallback {
void zFill(LongPoint bot1, LongPoint top1, LongPoint bot2, LongPoint top2, LongPoint pt);
}
//InitOptions that can be passed to the constructor ...
int REVERSE_SOLUTION = 1;
int STRICTLY_SIMPLE = 2;
int PRESERVE_COLINEAR = 4;
boolean addPath(Path pg, PolyType polyType, boolean Closed);
boolean addPaths(Paths ppg, PolyType polyType, boolean closed);
void clear();
boolean execute(ClipType clipType, Paths solution);
boolean execute(ClipType clipType, Paths solution, PolyFillType subjFillType, PolyFillType clipFillType);
boolean execute(ClipType clipType, PolyTree polytree);
boolean execute(ClipType clipType, PolyTree polytree, PolyFillType subjFillType, PolyFillType clipFillType);
}

691
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/ClipperBase.java

@ -1,691 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Path.OutRec;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
public abstract class ClipperBase implements Clipper {
protected class LocalMinima {
long y;
Edge leftBound;
Edge rightBound;
LocalMinima next;
}
protected class Scanbeam {
long y;
Scanbeam next;
}
protected class Maxima {
long x;
Maxima next;
Maxima prev;
}
private static void initEdge(Edge e, Edge eNext, Edge ePrev, LongPoint pt ) {
e.next = eNext;
e.prev = ePrev;
e.setCurrent( new LongPoint( pt ) );
e.outIdx = Edge.UNASSIGNED;
}
private static void initEdge2(Edge e, PolyType polyType ) {
if (e.getCurrent().getY() >= e.next.getCurrent().getY()) {
e.setBot( new LongPoint( e.getCurrent() ) );
e.setTop( new LongPoint( e.next.getCurrent() ) );
}
else {
e.setTop( new LongPoint( e.getCurrent() ) );
e.setBot( new LongPoint( e.next.getCurrent() ) );
}
e.updateDeltaX();
e.polyTyp = polyType;
}
private static void rangeTest( LongPoint Pt ) {
if (Pt.getX() > LOW_RANGE || Pt.getY() > LOW_RANGE || -Pt.getX() > LOW_RANGE || -Pt.getY() > LOW_RANGE) {
if (Pt.getX() > HI_RANGE || Pt.getY() > HI_RANGE || -Pt.getX() > HI_RANGE || -Pt.getY() > HI_RANGE) {
throw new IllegalStateException( "Coordinate outside allowed range" );
}
}
}
private static Edge removeEdge(Edge e ) {
//removes e from double_linked_list (but without removing from memory)
e.prev.next = e.next;
e.next.prev = e.prev;
final Edge result = e.next;
e.prev = null; //flag as removed (see ClipperBase.Clear)
return result;
}
private final static long LOW_RANGE = 0x3FFFFFFF;
private final static long HI_RANGE = 0x3FFFFFFFFFFFFFFFL;
protected LocalMinima minimaList;
protected LocalMinima currentLM;
protected Scanbeam scanbeam;
protected final List<OutRec> polyOuts = new ArrayList<>();
protected Edge activeEdges;
protected boolean hasOpenPaths;
protected final boolean preserveCollinear;
private final static Logger LOGGER = Logger.getLogger( Clipper.class.getName() );
protected ClipperBase( boolean preserveCollinear ) //constructor (nb: no external instantiation)
{
this.preserveCollinear = preserveCollinear;
minimaList = null;
currentLM = null;
hasOpenPaths = false;
}
@Override
public boolean addPath(Path pg, PolyType polyType, boolean Closed ) {
if (!Closed && polyType == PolyType.CLIP) {
throw new IllegalStateException( "AddPath: Open paths must be subject." );
}
int highI = pg.size() - 1;
if (Closed) {
while (highI > 0 && pg.get( highI ).equals( pg.get( 0 ) )) {
--highI;
}
}
while (highI > 0 && pg.get( highI ).equals( pg.get( highI - 1 ) )) {
--highI;
}
if (Closed && highI < 2 || !Closed && highI < 1) {
return false;
}
//create a new edge array ...
final List<Edge> edges = new ArrayList<>( highI + 1 );
for (int i = 0; i <= highI; i++) {
edges.add( new Edge() );
}
boolean IsFlat = true;
//1. Basic (first) edge initialization ...
edges.get( 1 ).setCurrent( new LongPoint( pg.get( 1 ) ) );
rangeTest( pg.get( 0 ) );
rangeTest( pg.get( highI ) );
initEdge( edges.get( 0 ), edges.get( 1 ), edges.get( highI ), pg.get( 0 ) );
initEdge( edges.get( highI ), edges.get( 0 ), edges.get( highI - 1 ), pg.get( highI ) );
for (int i = highI - 1; i >= 1; --i) {
rangeTest( pg.get( i ) );
initEdge( edges.get( i ), edges.get( i + 1 ), edges.get( i - 1 ), pg.get( i ) );
}
Edge eStart = edges.get( 0 );
//2. Remove duplicate vertices, and (when closed) collinear edges ...
Edge e = eStart, eLoopStop = eStart;
for (;;) {
//nb: allows matching start and end points when not Closed ...
if (e.getCurrent().equals( e.next.getCurrent() ) && (Closed || !e.next.equals( eStart ))) {
if (e == e.next) {
break;
}
if (e == eStart) {
eStart = e.next;
}
e = removeEdge( e );
eLoopStop = e;
continue;
}
if (e.prev == e.next) {
break; //only two vertices
}
else if (Closed && Point.slopesEqual( e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent() )
&& (!isPreserveCollinear() || !Point.isPt2BetweenPt1AndPt3( e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent() ))) {
//Collinear edges are allowed for open paths but in closed paths
//the default is to merge adjacent collinear edges into a single edge.
//However, if the PreserveCollinear property is enabled, only overlapping
//collinear edges (ie spikes) will be removed from closed paths.
if (e == eStart) {
eStart = e.next;
}
e = removeEdge( e );
e = e.prev;
eLoopStop = e;
continue;
}
e = e.next;
if (e == eLoopStop || !Closed && e.next == eStart) {
break;
}
}
if (!Closed && e == e.next || Closed && e.prev == e.next) {
return false;
}
if (!Closed) {
hasOpenPaths = true;
eStart.prev.outIdx = Edge.SKIP;
}
//3. Do second stage of edge initialization ...
e = eStart;
do {
initEdge2( e, polyType );
e = e.next;
if (IsFlat && e.getCurrent().getY() != eStart.getCurrent().getY()) {
IsFlat = false;
}
}
while (e != eStart);
//4. Finally, add edge bounds to LocalMinima list ...
//Totally flat paths must be handled differently when adding them
//to LocalMinima list to avoid endless loops etc ...
if (IsFlat) {
if (Closed) {
return false;
}
e.prev.outIdx = Edge.SKIP;
final LocalMinima locMin = new LocalMinima();
locMin.next = null;
locMin.y = e.getBot().getY();
locMin.leftBound = null;
locMin.rightBound = e;
locMin.rightBound.side = Edge.Side.RIGHT;
locMin.rightBound.windDelta = 0;
for ( ; ; ) {
if (e.getBot().getX() != e.prev.getTop().getX()) {
e.reverseHorizontal();
}
if (e.next.outIdx == Edge.SKIP) break;
e.nextInLML = e.next;
e = e.next;
}
insertLocalMinima( locMin );
return true;
}
boolean leftBoundIsForward;
Edge EMin = null;
//workaround to avoid an endless loop in the while loop below when
//open paths have matching start and end points ...
if (e.prev.getBot().equals( e.prev.getTop() )) {
e = e.next;
}
for (;;) {
e = e.findNextLocMin();
if (e == EMin) {
break;
}
else if (EMin == null) {
EMin = e;
}
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
final LocalMinima locMin = new LocalMinima();
locMin.next = null;
locMin.y = e.getBot().getY();
if (e.deltaX < e.prev.deltaX) {
locMin.leftBound = e.prev;
locMin.rightBound = e;
leftBoundIsForward = false; //Q.nextInLML = Q.prev
}
else {
locMin.leftBound = e;
locMin.rightBound = e.prev;
leftBoundIsForward = true; //Q.nextInLML = Q.next
}
locMin.leftBound.side = Edge.Side.LEFT;
locMin.rightBound.side = Edge.Side.RIGHT;
if (!Closed) {
locMin.leftBound.windDelta = 0;
}
else if (locMin.leftBound.next == locMin.rightBound) {
locMin.leftBound.windDelta = -1;
}
else {
locMin.leftBound.windDelta = 1;
}
locMin.rightBound.windDelta = -locMin.leftBound.windDelta;
e = processBound( locMin.leftBound, leftBoundIsForward );
if (e.outIdx == Edge.SKIP) {
e = processBound( e, leftBoundIsForward );
}
Edge E2 = processBound( locMin.rightBound, !leftBoundIsForward );
if (E2.outIdx == Edge.SKIP) {
E2 = processBound( E2, !leftBoundIsForward );
}
if (locMin.leftBound.outIdx == Edge.SKIP) {
locMin.leftBound = null;
}
else if (locMin.rightBound.outIdx == Edge.SKIP) {
locMin.rightBound = null;
}
insertLocalMinima( locMin );
if (!leftBoundIsForward) {
e = E2;
}
}
return true;
}
@Override
public boolean addPaths(Paths paths, PolyType polyType, boolean closed ) {
boolean result = false;
for (Path path : paths) {
if (addPath(path, polyType, closed)) {
result = true;
}
}
return result;
}
@Override
public void clear() {
disposeLocalMinimaList();
hasOpenPaths = false;
}
private void disposeLocalMinimaList() {
while (minimaList != null) {
final LocalMinima tmpLm = minimaList.next;
minimaList = null;
minimaList = tmpLm;
}
currentLM = null;
}
private void insertLocalMinima( LocalMinima newLm ) {
if (minimaList == null) {
minimaList = newLm;
}
else if (newLm.y >= minimaList.y) {
newLm.next = minimaList;
minimaList = newLm;
}
else {
LocalMinima tmpLm = minimaList;
while (tmpLm.next != null && newLm.y < tmpLm.next.y) {
tmpLm = tmpLm.next;
}
newLm.next = tmpLm.next;
tmpLm.next = newLm;
}
}
private boolean isPreserveCollinear() {
return preserveCollinear;
}
protected boolean popLocalMinima( long y, LocalMinima[] current ) {
LOGGER.entering( ClipperBase.class.getName(), "popLocalMinima" );
current[0] = currentLM;
if (currentLM != null && currentLM.y == y) {
currentLM = currentLM.next;
return true;
}
return false;
}
private Edge processBound(Edge e, boolean LeftBoundIsForward ) {
Edge EStart, result = e;
Edge Horz;
if (result.outIdx == Edge.SKIP) {
//check if there are edges beyond the skip edge in the bound and if so
//create another LocMin and calling ProcessBound once more ...
e = result;
if (LeftBoundIsForward) {
while (e.getTop().getY() == e.next.getBot().getY()) {
e = e.next;
}
while (e != result && e.deltaX == Edge.HORIZONTAL) {
e = e.prev;
}
}
else {
while (e.getTop().getY() == e.prev.getBot().getY()) {
e = e.prev;
}
while (e != result && e.deltaX == Edge.HORIZONTAL) {
e = e.next;
}
}
if (e == result) {
if (LeftBoundIsForward) {
result = e.next;
}
else {
result = e.prev;
}
}
else {
//there are more edges in the bound beyond result starting with E
if (LeftBoundIsForward) {
e = result.next;
}
else {
e = result.prev;
}
final LocalMinima locMin = new LocalMinima();
locMin.next = null;
locMin.y = e.getBot().getY();
locMin.leftBound = null;
locMin.rightBound = e;
e.windDelta = 0;
result = processBound( e, LeftBoundIsForward );
insertLocalMinima( locMin );
}
return result;
}
if (e.deltaX == Edge.HORIZONTAL) {
//We need to be careful with open paths because this may not be a
//true local minima (ie E may be following a skip edge).
//Also, consecutive horz. edges may start heading left before going right.
if (LeftBoundIsForward) {
EStart = e.prev;
}
else {
EStart = e.next;
}
if (EStart.deltaX == Edge.HORIZONTAL) //ie an adjoining horizontal skip edge
{
if (EStart.getBot().getX() != e.getBot().getX() && EStart.getTop().getX() != e.getBot().getX()) {
e.reverseHorizontal();
}
}
else if (EStart.getBot().getX() != e.getBot().getX()) {
e.reverseHorizontal();
}
}
EStart = e;
if (LeftBoundIsForward) {
while (result.getTop().getY() == result.next.getBot().getY() && result.next.outIdx != Edge.SKIP) {
result = result.next;
}
if (result.deltaX == Edge.HORIZONTAL && result.next.outIdx != Edge.SKIP) {
//nb: at the top of a bound, horizontals are added to the bound
//only when the preceding edge attaches to the horizontal's left vertex
//unless a Skip edge is encountered when that becomes the top divide
Horz = result;
while (Horz.prev.deltaX == Edge.HORIZONTAL) {
Horz = Horz.prev;
}
if (Horz.prev.getTop().getX() > result.next.getTop().getX()) {
result = Horz.prev;
}
}
while (e != result) {
e.nextInLML = e.next;
if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
e.reverseHorizontal();
}
e = e.next;
}
if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
e.reverseHorizontal();
}
result = result.next; //move to the edge just beyond current bound
}
else {
while (result.getTop().getY() == result.prev.getBot().getY() && result.prev.outIdx != Edge.SKIP) {
result = result.prev;
}
if (result.deltaX == Edge.HORIZONTAL && result.prev.outIdx != Edge.SKIP) {
Horz = result;
while (Horz.next.deltaX == Edge.HORIZONTAL) {
Horz = Horz.next;
}
if (Horz.next.getTop().getX() == result.prev.getTop().getX() ||
Horz.next.getTop().getX() > result.prev.getTop().getX()) {
result = Horz.next;
}
}
while (e != result) {
e.nextInLML = e.prev;
if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
e.reverseHorizontal();
}
e = e.prev;
}
if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
e.reverseHorizontal();
}
result = result.prev; //move to the edge just beyond current bound
}
return result;
}
protected void reset() {
currentLM = minimaList;
if (currentLM == null) {
return; //ie nothing to process
}
//reset all edges ...
scanbeam = null;
LocalMinima lm = minimaList;
while (lm != null) {
insertScanbeam(lm.y);
Edge e = lm.leftBound;
if (e != null) {
e.setCurrent( new LongPoint( e.getBot() ) );
e.outIdx = Edge.UNASSIGNED;
}
e = lm.rightBound;
if (e != null) {
e.setCurrent( new LongPoint( e.getBot() ) );
e.outIdx = Edge.UNASSIGNED;
}
lm = lm.next;
}
activeEdges = null;
}
protected void insertScanbeam( long y ) {
LOGGER.entering( ClipperBase.class.getName(), "insertScanbeam" );
//single-linked list: sorted descending, ignoring dups.
if (scanbeam == null) {
scanbeam = new Scanbeam();
scanbeam.next = null;
scanbeam.y = y;
}
else if (y > scanbeam.y) {
final Scanbeam newSb = new Scanbeam();
newSb.y = y;
newSb.next = scanbeam;
scanbeam = newSb;
}
else {
Scanbeam sb2 = scanbeam;
while (sb2.next != null && (y <= sb2.next.y)) {
sb2 = sb2.next;
}
if (y == sb2.y) {
return; //ie ignores duplicates
}
final Scanbeam newSb = new Scanbeam();
newSb.y = y;
newSb.next = sb2.next;
sb2.next = newSb;
}
}
protected boolean popScanbeam( long[] y ) {
if (scanbeam == null) {
y[0] = 0;
return false;
}
y[0] = scanbeam.y;
scanbeam = scanbeam.next;
return true;
}
protected final boolean localMinimaPending() {
return currentLM != null;
}
protected OutRec createOutRec() {
OutRec result = new OutRec();
result.Idx = Edge.UNASSIGNED;
result.isHole = false;
result.isOpen = false;
result.firstLeft = null;
result.setPoints( null );
result.bottomPt = null;
result.polyNode = null;
polyOuts.add( result );
result.Idx = polyOuts.size() - 1;
return result;
}
protected void disposeOutRec( int index ) {
OutRec outRec = polyOuts.get( index );
outRec.setPoints( null );
outRec = null;
polyOuts.set( index, null );
}
protected void updateEdgeIntoAEL( Edge e ) {
if (e.nextInLML == null) {
throw new IllegalStateException("UpdateEdgeIntoAEL: invalid call");
}
final Edge aelPrev = e.prevInAEL;
final Edge aelNext = e.nextInAEL;
e.nextInLML.outIdx = e.outIdx;
if (aelPrev != null) {
aelPrev.nextInAEL = e.nextInLML;
}
else {
activeEdges = e.nextInLML;
}
if (aelNext != null) {
aelNext.prevInAEL = e.nextInLML;
}
e.nextInLML.side = e.side;
e.nextInLML.windDelta = e.windDelta;
e.nextInLML.windCnt = e.windCnt;
e.nextInLML.windCnt2 = e.windCnt2;
e = e.nextInLML;
e.setCurrent(e.getBot());
e.prevInAEL = aelPrev;
e.nextInAEL = aelNext;
if (e.isHorizontal()) {
insertScanbeam(e.getTop().getY());
}
}
protected void swapPositionsInAEL(Edge edge1, Edge edge2 ) {
LOGGER.entering( ClipperBase.class.getName(), "swapPositionsInAEL" );
//check that one or other edge hasn't already been removed from AEL ...
if (edge1.nextInAEL == edge1.prevInAEL || edge2.nextInAEL == edge2.prevInAEL) {
return;
}
if (edge1.nextInAEL == edge2) {
final Edge next = edge2.nextInAEL;
if (next != null) {
next.prevInAEL = edge1;
}
final Edge prev = edge1.prevInAEL;
if (prev != null) {
prev.nextInAEL = edge2;
}
edge2.prevInAEL = prev;
edge2.nextInAEL = edge1;
edge1.prevInAEL = edge2;
edge1.nextInAEL = next;
}
else if (edge2.nextInAEL == edge1) {
final Edge next = edge1.nextInAEL;
if (next != null) {
next.prevInAEL = edge2;
}
final Edge prev = edge2.prevInAEL;
if (prev != null) {
prev.nextInAEL = edge1;
}
edge1.prevInAEL = prev;
edge1.nextInAEL = edge2;
edge2.prevInAEL = edge1;
edge2.nextInAEL = next;
}
else {
final Edge next = edge1.nextInAEL;
final Edge prev = edge1.prevInAEL;
edge1.nextInAEL = edge2.nextInAEL;
if (edge1.nextInAEL != null) {
edge1.nextInAEL.prevInAEL = edge1;
}
edge1.prevInAEL = edge2.prevInAEL;
if (edge1.prevInAEL != null) {
edge1.prevInAEL.nextInAEL = edge1;
}
edge2.nextInAEL = next;
if (edge2.nextInAEL != null) {
edge2.nextInAEL.prevInAEL = edge2;
}
edge2.prevInAEL = prev;
if (edge2.prevInAEL != null) {
edge2.prevInAEL.nextInAEL = edge2;
}
}
if (edge1.prevInAEL == null) {
activeEdges = edge1;
}
else if (edge2.prevInAEL == null) {
activeEdges = edge2;
}
LOGGER.exiting( ClipperBase.class.getName(), "swapPositionsInAEL" );
}
protected void deleteFromAEL( Edge e ) {
LOGGER.entering( ClipperBase.class.getName(), "deleteFromAEL" );
Edge aelPrev = e.prevInAEL;
Edge aelNext = e.nextInAEL;
if (aelPrev == null && aelNext == null && (e != activeEdges)) {
return; //already deleted
}
if (aelPrev != null) {
aelPrev.nextInAEL = aelNext;
}
else {
activeEdges = aelNext;
}
if (aelNext != null) {
aelNext.prevInAEL = aelPrev;
}
e.nextInAEL = null;
e.prevInAEL = null;
LOGGER.exiting( ClipperBase.class.getName(), "deleteFromAEL" );
}
}

481
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/ClipperOffset.java

@ -1,481 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Clipper.*;
import com.visual.open.anpr.core.clipper.Point.DoublePoint;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ClipperOffset {
private static boolean nearZero( double val ) {
return val > -TOLERANCE && val < TOLERANCE;
}
private Paths destPolys;
private Path srcPoly;
private Path destPoly;
private final List<DoublePoint> normals;
private double delta, inA, sin, cos;
private double miterLim, stepsPerRad;
private LongPoint lowest;
private final PolyNode polyNodes;
private final double arcTolerance;
private final double miterLimit;
private final static double TWO_PI = Math.PI * 2;
private final static double DEFAULT_ARC_TOLERANCE = 0.25;
private final static double TOLERANCE = 1.0E-20;
public ClipperOffset() {
this( 2, DEFAULT_ARC_TOLERANCE );
}
public ClipperOffset( double miterLimit, double arcTolerance ) {
this.miterLimit = miterLimit;
this.arcTolerance = arcTolerance;
lowest = new LongPoint();
lowest.setX( -1L );
polyNodes = new PolyNode();
normals = new ArrayList<>();
}
public void addPath(Path path, JoinType joinType, EndType endType ) {
int highI = path.size() - 1;
if (highI < 0) {
return;
}
final PolyNode newNode = new PolyNode();
newNode.setJoinType( joinType );
newNode.setEndType( endType );
//strip duplicate points from path and also get index to the lowest point ...
if (endType == EndType.CLOSED_LINE || endType == EndType.CLOSED_POLYGON) {
while (highI > 0 && path.get( 0 ) == path.get( highI )) {
highI--;
}
}
newNode.getPolygon().add( path.get( 0 ) );
int j = 0, k = 0;
for (int i = 1; i <= highI; i++) {
if (newNode.getPolygon().get( j ) != path.get( i )) {
j++;
newNode.getPolygon().add( path.get( i ) );
if (path.get( i ).getY() > newNode.getPolygon().get( k ).getY() || path.get( i ).getY() == newNode.getPolygon().get( k ).getY()
&& path.get( i ).getX() < newNode.getPolygon().get( k ).getX()) {
k = j;
}
}
}
if (endType == EndType.CLOSED_POLYGON && j < 2) {
return;
}
polyNodes.addChild( newNode );
//if this path's lowest pt is lower than all the others then update m_lowest
if (endType != EndType.CLOSED_POLYGON) {
return;
}
if (lowest.getX() < 0) {
lowest = new LongPoint( polyNodes.getChildCount() - 1, k );
}
else {
final LongPoint ip = polyNodes.getChilds().get( (int) lowest.getX() ).getPolygon().get( (int) lowest.getY() );
if (newNode.getPolygon().get( k ).getY() > ip.getY() || newNode.getPolygon().get( k ).getY() == ip.getY()
&& newNode.getPolygon().get( k ).getX() < ip.getX()) {
lowest = new LongPoint( polyNodes.getChildCount() - 1, k );
}
}
}
public void addPaths(Paths paths, JoinType joinType, EndType endType ) {
for (final Path p : paths) {
addPath( p, joinType, endType );
}
}
public void clear() {
polyNodes.getChilds().clear();
lowest.setX( -1L );
}
private void doMiter( int j, int k, double r ) {
final double q = delta / r;
destPoly.add( new LongPoint( Math.round( srcPoly.get( j ).getX() + (normals.get( k ).getX() + normals.get( j ).getX()) * q ), Math
.round( srcPoly.get( j ).getY() + (normals.get( k ).getY() + normals.get( j ).getY()) * q ) ) );
}
private void doOffset( double delta ) {
destPolys = new Paths();
this.delta = delta;
//if Zero offset, just copy any CLOSED polygons to m_p and return ...
if (nearZero( delta )) {
for (int i = 0; i < polyNodes.getChildCount(); i++) {
final PolyNode node = polyNodes.getChilds().get( i );
if (node.getEndType() == EndType.CLOSED_POLYGON) {
destPolys.add( node.getPolygon() );
}
}
return;
}
//see offset_triginometry3.svg in the documentation folder ...
if (miterLimit > 2) {
miterLim = 2 / (miterLimit * miterLimit);
}
else {
miterLim = 0.5;
}
double y;
if (arcTolerance <= 0.0) {
y = DEFAULT_ARC_TOLERANCE;
}
else if (arcTolerance > Math.abs( delta ) * DEFAULT_ARC_TOLERANCE) {
y = Math.abs( delta ) * DEFAULT_ARC_TOLERANCE;
}
else {
y = arcTolerance;
}
//see offset_triginometry2.svg in the documentation folder ...
final double steps = Math.PI / Math.acos( 1 - y / Math.abs( delta ) );
sin = Math.sin( TWO_PI / steps );
cos = Math.cos( TWO_PI / steps );
stepsPerRad = steps / TWO_PI;
if (delta < 0.0) {
sin = -sin;
}
for (int i = 0; i < polyNodes.getChildCount(); i++) {
final PolyNode node = polyNodes.getChilds().get( i );
srcPoly = node.getPolygon();
final int len = srcPoly.size();
if (len == 0 || delta <= 0 && (len < 3 || node.getEndType() != EndType.CLOSED_POLYGON)) {
continue;
}
destPoly = new Path();
if (len == 1) {
if (node.getJoinType() == JoinType.ROUND) {
double X = 1.0, Y = 0.0;
for (int j = 1; j <= steps; j++) {
destPoly.add( new LongPoint( Math.round( srcPoly.get( 0 ).getX() + X * delta ), Math.round( srcPoly.get( 0 ).getY() + Y
* delta ) ) );
final double X2 = X;
X = X * cos - sin * Y;
Y = X2 * sin + Y * cos;
}
}
else {
double X = -1.0, Y = -1.0;
for (int j = 0; j < 4; ++j) {
destPoly.add( new LongPoint( Math.round( srcPoly.get( 0 ).getX() + X * delta ), Math.round( srcPoly.get( 0 ).getY() + Y
* delta ) ) );
if (X < 0) {
X = 1;
}
else if (Y < 0) {
Y = 1;
}
else {
X = -1;
}
}
}
destPolys.add( destPoly );
continue;
}
//build m_normals ...
normals.clear();
for (int j = 0; j < len - 1; j++) {
normals.add( Point.getUnitNormal( srcPoly.get( j ), srcPoly.get( j + 1 ) ) );
}
if (node.getEndType() == EndType.CLOSED_LINE || node.getEndType() == EndType.CLOSED_POLYGON) {
normals.add( Point.getUnitNormal( srcPoly.get( len - 1 ), srcPoly.get( 0 ) ) );
}
else {
normals.add( new DoublePoint( normals.get( len - 2 ) ) );
}
if (node.getEndType() == EndType.CLOSED_POLYGON) {
final int[] k = new int[] { len - 1 };
for (int j = 0; j < len; j++) {
offsetPoint( j, k, node.getJoinType() );
}
destPolys.add( destPoly );
}
else if (node.getEndType() == EndType.CLOSED_LINE) {
final int[] k = new int[] { len - 1 };
for (int j = 0; j < len; j++) {
offsetPoint( j, k, node.getJoinType() );
}
destPolys.add( destPoly );
destPoly = new Path();
//re-build m_normals ...
final DoublePoint n = normals.get( len - 1 );
for (int j = len - 1; j > 0; j--) {
normals.set( j, new DoublePoint( -normals.get( j - 1 ).getX(), -normals.get( j - 1 ).getY() ) );
}
normals.set( 0, new DoublePoint( -n.getX(), -n.getY(), 0 ) );
k[0] = 0;
for (int j = len - 1; j >= 0; j--) {
offsetPoint( j, k, node.getJoinType() );
}
destPolys.add( destPoly );
}
else {
final int[] k = new int[1];
for (int j = 1; j < len - 1; ++j) {
offsetPoint( j, k, node.getJoinType() );
}
LongPoint pt1;
if (node.getEndType() == EndType.OPEN_BUTT) {
final int j = len - 1;
pt1 = new LongPoint( Math.round( srcPoly.get( j ).getX() + normals.get( j ).getX() * delta ), Math.round( srcPoly.get( j )
.getY() + normals.get( j ).getY() * delta ), 0 );
destPoly.add( pt1 );
pt1 = new LongPoint( Math.round( srcPoly.get( j ).getX() - normals.get( j ).getX() * delta ), Math.round( srcPoly.get( j )
.getY() - normals.get( j ).getY() * delta ), 0 );
destPoly.add( pt1 );
}
else {
final int j = len - 1;
k[0] = len - 2;
inA = 0;
normals.set( j, new DoublePoint( -normals.get( j ).getX(), -normals.get( j ).getY() ) );
if (node.getEndType() == EndType.OPEN_SQUARE) {
doSquare( j, k[0] );
}
else {
doRound( j, k[0] );
}
}
//re-build m_normals ...
for (int j = len - 1; j > 0; j--) {
normals.set( j, new DoublePoint( -normals.get( j - 1 ).getX(), -normals.get( j - 1 ).getY() ) );
}
normals.set( 0, new DoublePoint( -normals.get( 1 ).getX(), -normals.get( 1 ).getY() ) );
k[0] = len - 1;
for (int j = k[0] - 1; j > 0; --j) {
offsetPoint( j, k, node.getJoinType() );
}
if (node.getEndType() == EndType.OPEN_BUTT) {
pt1 = new LongPoint( Math.round( srcPoly.get( 0 ).getX() - normals.get( 0 ).getX() * delta ), Math.round( srcPoly.get( 0 )
.getY() - normals.get( 0 ).getY() * delta ) );
destPoly.add( pt1 );
pt1 = new LongPoint( Math.round( srcPoly.get( 0 ).getX() + normals.get( 0 ).getX() * delta ), Math.round( srcPoly.get( 0 )
.getY() + normals.get( 0 ).getY() * delta ) );
destPoly.add( pt1 );
}
else {
k[0] = 1;
inA = 0;
if (node.getEndType() == EndType.OPEN_SQUARE) {
doSquare( 0, 1 );
}
else {
doRound( 0, 1 );
}
}
destPolys.add( destPoly );
}
}
}
private void doRound( int j, int k ) {
final double a = Math.atan2( inA, normals.get( k ).getX() * normals.get( j ).getX() + normals.get( k ).getY() * normals.get( j ).getY() );
final int steps = Math.max( (int) Math.round( stepsPerRad * Math.abs( a ) ), 1 );
double X = normals.get( k ).getX(), Y = normals.get( k ).getY(), X2;
for (int i = 0; i < steps; ++i) {
destPoly.add( new LongPoint( Math.round( srcPoly.get( j ).getX() + X * delta ), Math.round( srcPoly.get( j ).getY() + Y * delta ) ) );
X2 = X;
X = X * cos - sin * Y;
Y = X2 * sin + Y * cos;
}
destPoly.add( new LongPoint( Math.round( srcPoly.get( j ).getX() + normals.get( j ).getX() * delta ), Math.round( srcPoly.get( j ).getY()
+ normals.get( j ).getY() * delta ) ) );
}
private void doSquare( int j, int k ) {
final double nkx = normals.get( k ).getX();
final double nky = normals.get( k ).getY();
final double njx = normals.get( j ).getX();
final double njy = normals.get( j ).getY();
final double sjx = srcPoly.get( j ).getX();
final double sjy = srcPoly.get( j ).getY();
final double dx = Math.tan( Math.atan2( inA, nkx * njx + nky * njy ) / 4 );
destPoly.add( new LongPoint( Math.round( sjx + delta * (nkx - nky * dx) ), Math.round( sjy + delta * (nky + nkx * dx) ), 0 ) );
destPoly.add( new LongPoint( Math.round( sjx + delta * (njx + njy * dx) ), Math.round( sjy + delta * (njy - njx * dx) ), 0 ) );
}
//------------------------------------------------------------------------------
public void execute(Paths solution, double delta ) {
solution.clear();
fixOrientations();
doOffset( delta );
//now clean up 'corners' ...
final DefaultClipper clpr = new DefaultClipper( Clipper.REVERSE_SOLUTION );
clpr.addPaths( destPolys, PolyType.SUBJECT, true );
if (delta > 0) {
clpr.execute( ClipType.UNION, solution, PolyFillType.POSITIVE, PolyFillType.POSITIVE );
}
else {
final LongRect r = destPolys.getBounds();
final Path outer = new Path( 4 );
outer.add( new LongPoint( r.left - 10, r.bottom + 10, 0 ) );
outer.add( new LongPoint( r.right + 10, r.bottom + 10, 0 ) );
outer.add( new LongPoint( r.right + 10, r.top - 10, 0 ) );
outer.add( new LongPoint( r.left - 10, r.top - 10, 0 ) );
clpr.addPath( outer, PolyType.SUBJECT, true );
clpr.execute( ClipType.UNION, solution, PolyFillType.NEGATIVE, PolyFillType.NEGATIVE );
if (solution.size() > 0) {
solution.remove( 0 );
}
}
}
//------------------------------------------------------------------------------
public void execute(PolyTree solution, double delta ) {
solution.Clear();
fixOrientations();
doOffset( delta );
//now clean up 'corners' ...
final DefaultClipper clpr = new DefaultClipper( Clipper.REVERSE_SOLUTION );
clpr.addPaths( destPolys, PolyType.SUBJECT, true );
if (delta > 0) {
clpr.execute( ClipType.UNION, solution, PolyFillType.POSITIVE, PolyFillType.POSITIVE );
}
else {
final LongRect r = destPolys.getBounds();
final Path outer = new Path( 4 );
outer.add( new LongPoint( r.left - 10, r.bottom + 10, 0 ) );
outer.add( new LongPoint( r.right + 10, r.bottom + 10, 0 ) );
outer.add( new LongPoint( r.right + 10, r.top - 10, 0 ) );
outer.add( new LongPoint( r.left - 10, r.top - 10, 0 ) );
clpr.addPath( outer, PolyType.SUBJECT, true );
clpr.execute( ClipType.UNION, solution, PolyFillType.NEGATIVE, PolyFillType.NEGATIVE );
//remove the outer PolyNode rectangle ...
if (solution.getChildCount() == 1 && solution.getChilds().get( 0 ).getChildCount() > 0) {
final PolyNode outerNode = solution.getChilds().get( 0 );
solution.getChilds().set( 0, outerNode.getChilds().get( 0 ) );
solution.getChilds().get( 0 ).setParent( solution );
for (int i = 1; i < outerNode.getChildCount(); i++) {
solution.addChild( outerNode.getChilds().get( i ) );
}
}
else {
solution.Clear();
}
}
}
//------------------------------------------------------------------------------
private void fixOrientations() {
//fixup orientations of all closed paths if the orientation of the
//closed path with the lowermost vertex is wrong ...
if (lowest.getX() >= 0 && !polyNodes.childs.get( (int) lowest.getX() ).getPolygon().orientation()) {
for (int i = 0; i < polyNodes.getChildCount(); i++) {
final PolyNode node = polyNodes.childs.get( i );
if (node.getEndType() == EndType.CLOSED_POLYGON || node.getEndType() == EndType.CLOSED_LINE && node.getPolygon().orientation()) {
Collections.reverse( node.getPolygon() );
}
}
}
else {
for (int i = 0; i < polyNodes.getChildCount(); i++) {
final PolyNode node = polyNodes.childs.get( i );
if (node.getEndType() == EndType.CLOSED_LINE && !node.getPolygon().orientation()) {
Collections.reverse( node.getPolygon() );
}
}
}
}
private void offsetPoint( int j, int[] kV, JoinType jointype ) {
//cross product ...
final int k = kV[0];
final double nkx = normals.get( k ).getX();
final double nky = normals.get( k ).getY();
final double njy = normals.get( j ).getY();
final double njx = normals.get( j ).getX();
final long sjx = srcPoly.get( j ).getX();
final long sjy = srcPoly.get( j ).getY();
inA = nkx * njy - njx * nky;
if (Math.abs( inA * delta ) < 1.0) {
//dot product ...
final double cosA = nkx * njx + njy * nky;
if (cosA > 0) // angle ==> 0 degrees
{
destPoly.add( new LongPoint( Math.round( sjx + nkx * delta ), Math.round( sjy + nky * delta ), 0 ) );
return;
}
//else angle ==> 180 degrees
}
else if (inA > 1.0) {
inA = 1.0;
}
else if (inA < -1.0) {
inA = -1.0;
}
if (inA * delta < 0) {
destPoly.add( new LongPoint( Math.round( sjx + nkx * delta ), Math.round( sjy + nky * delta ) ) );
destPoly.add( srcPoly.get( j ) );
destPoly.add( new LongPoint( Math.round( sjx + njx * delta ), Math.round( sjy + njy * delta ) ) );
}
else {
switch (jointype) {
case MITER: {
final double r = 1 + njx * nkx + njy * nky;
if (r >= miterLim) {
doMiter( j, k, r );
}
else {
doSquare( j, k );
}
break;
}
case SQUARE:
doSquare( j, k );
break;
case ROUND:
doRound( j, k );
break;
}
}
kV[0] = j;
}
//------------------------------------------------------------------------------
}

2518
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/DefaultClipper.java

File diff suppressed because it is too large

339
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Edge.java

@ -1,339 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Clipper.ClipType;
import com.visual.open.anpr.core.clipper.Clipper.Direction;
import com.visual.open.anpr.core.clipper.Clipper.PolyFillType;
import com.visual.open.anpr.core.clipper.Clipper.PolyType;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
import java.util.logging.Logger;
class Edge {
enum Side {
LEFT, RIGHT
}
static boolean doesE2InsertBeforeE1(Edge e1, Edge e2 ) {
if (e2.current.getX() == e1.current.getX()) {
if (e2.top.getY() > e1.top.getY()) {
return e2.top.getX() < topX( e1, e2.top.getY() );
}
else {
return e1.top.getX() > topX( e2, e1.top.getY() );
}
}
else {
return e2.current.getX() < e1.current.getX();
}
}
static boolean slopesEqual(Edge e1, Edge e2 ) {
return e1.getDelta().getY() * e2.getDelta().getX() == e1.getDelta().getX() * e2.getDelta().getY();
}
static void swapPolyIndexes(Edge edge1, Edge edge2 ) {
final int outIdx = edge1.outIdx;
edge1.outIdx = edge2.outIdx;
edge2.outIdx = outIdx;
}
static void swapSides(Edge edge1, Edge edge2 ) {
final Side side = edge1.side;
edge1.side = edge2.side;
edge2.side = side;
}
static long topX(Edge edge, long currentY ) {
if (currentY == edge.getTop().getY()) {
return edge.getTop().getX();
}
return edge.getBot().getX() + Math.round( edge.deltaX * (currentY - edge.getBot().getY()) );
}
private final LongPoint bot;
private final LongPoint current; //current (updated for every new scanbeam)
private final LongPoint top;
private final LongPoint delta;
double deltaX;
PolyType polyTyp;
Side side; //side only refers to current side of solution poly
int windDelta; //1 or -1 depending on winding direction
int windCnt;
int windCnt2; //winding count of the opposite polytype
int outIdx;
Edge next;
Edge prev;
Edge nextInLML;
Edge nextInAEL;
Edge prevInAEL;
Edge nextInSEL;
Edge prevInSEL;
protected final static int SKIP = -2;
protected final static int UNASSIGNED = -1;
protected final static double HORIZONTAL = -3.4E+38;
private final static Logger LOGGER = Logger.getLogger( Edge.class.getName() );
public Edge() {
delta = new LongPoint();
top = new LongPoint();
bot = new LongPoint();
current = new LongPoint();
}
public Edge findNextLocMin() {
Edge e = this;
Edge e2;
for (;;) {
while (!e.bot.equals( e.prev.bot ) || e.current.equals( e.top )) {
e = e.next;
}
if (e.deltaX != Edge.HORIZONTAL && e.prev.deltaX != Edge.HORIZONTAL) {
break;
}
while (e.prev.deltaX == Edge.HORIZONTAL) {
e = e.prev;
}
e2 = e;
while (e.deltaX == Edge.HORIZONTAL) {
e = e.next;
}
if (e.top.getY() == e.prev.bot.getY()) {
continue; //ie just an intermediate horz.
}
if (e2.prev.bot.getX() < e.bot.getX()) {
e = e2;
}
break;
}
return e;
}
public LongPoint getBot() {
return bot;
}
public LongPoint getCurrent() {
return current;
}
public LongPoint getDelta() {
return delta;
}
public Edge getMaximaPair() {
if (next.top.equals( top ) && next.nextInLML == null) {
return next;
}
else if (prev.top.equals( top ) && prev.nextInLML == null) {
return prev;
}
return null;
}
Edge getMaximaPairEx() {
//as above but returns null if MaxPair isn't in AEL (unless it's horizontal)
Edge result = getMaximaPair();
if (result == null || result.outIdx == Edge.SKIP ||
((result.nextInAEL == result.prevInAEL) && !result.isHorizontal())) {
return null;
}
return result;
}
public Edge getNextInAEL(Direction direction ) {
return direction == Direction.LEFT_TO_RIGHT ? nextInAEL : prevInAEL;
}
public LongPoint getTop() {
return top;
}
public boolean isContributing(PolyFillType clipFillType, PolyFillType subjFillType, ClipType clipType ) {
LOGGER.entering( Edge.class.getName(), "isContributing" );
PolyFillType pft, pft2;
if (polyTyp == PolyType.SUBJECT) {
pft = subjFillType;
pft2 = clipFillType;
}
else {
pft = clipFillType;
pft2 = subjFillType;
}
switch (pft) {
case EVEN_ODD:
//return false if a subj line has been flagged as inside a subj polygon
if (windDelta == 0 && windCnt != 1) {
return false;
}
break;
case NON_ZERO:
if (Math.abs( windCnt ) != 1) {
return false;
}
break;
case POSITIVE:
if (windCnt != 1) {
return false;
}
break;
default: //PolyFillType.pftNegative
if (windCnt != -1) {
return false;
}
break;
}
switch (clipType) {
case INTERSECTION:
switch (pft2) {
case EVEN_ODD:
case NON_ZERO:
return windCnt2 != 0;
case POSITIVE:
return windCnt2 > 0;
default:
return windCnt2 < 0;
}
case UNION:
switch (pft2) {
case EVEN_ODD:
case NON_ZERO:
return windCnt2 == 0;
case POSITIVE:
return windCnt2 <= 0;
default:
return windCnt2 >= 0;
}
case DIFFERENCE:
if (polyTyp == PolyType.SUBJECT) {
switch (pft2) {
case EVEN_ODD:
case NON_ZERO:
return windCnt2 == 0;
case POSITIVE:
return windCnt2 <= 0;
default:
return windCnt2 >= 0;
}
}
else {
switch (pft2) {
case EVEN_ODD:
case NON_ZERO:
return windCnt2 != 0;
case POSITIVE:
return windCnt2 > 0;
default:
return windCnt2 < 0;
}
}
case XOR:
if (windDelta == 0) {
switch (pft2) {
case EVEN_ODD:
case NON_ZERO:
return windCnt2 == 0;
case POSITIVE:
return windCnt2 <= 0;
default:
return windCnt2 >= 0;
}
}
else {
return true;
}
}
return true;
}
public boolean isEvenOddAltFillType(PolyFillType clipFillType, PolyFillType subjFillType ) {
if (polyTyp == PolyType.SUBJECT) {
return clipFillType == PolyFillType.EVEN_ODD;
}
else {
return subjFillType == PolyFillType.EVEN_ODD;
}
}
public boolean isEvenOddFillType(PolyFillType clipFillType, PolyFillType subjFillType ) {
if (polyTyp == PolyType.SUBJECT) {
return subjFillType == PolyFillType.EVEN_ODD;
}
else {
return clipFillType == PolyFillType.EVEN_ODD;
}
}
public boolean isHorizontal() {
return delta.getY() == 0;
}
public boolean isIntermediate( double y ) {
return top.getY() == y && nextInLML != null;
}
public boolean isMaxima( double Y ) {
return top.getY() == Y && nextInLML == null;
}
public void reverseHorizontal() {
//swap horizontal edges' top and bottom x's so they follow the natural
//progression of the bounds - ie so their xbots will align with the
//adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
long temp = top.getX();
top.setX( bot.getX() );
bot.setX( temp );
temp = top.getZ();
top.setZ( bot.getZ() );
bot.setZ( temp );
}
public void setBot( LongPoint bot ) {
this.bot.set( bot );
}
public void setCurrent( LongPoint current ) {
this.current.set( current );
}
public void setTop( LongPoint top ) {
this.top.set( top );
}
@Override
public String toString() {
return "TEdge [Bot=" + bot + ", Curr=" + current + ", Top=" + top + ", Delta=" + delta + ", Dx=" + deltaX + ", PolyTyp=" + polyTyp + ", Side=" + side
+ ", WindDelta=" + windDelta + ", WindCnt=" + windCnt + ", WindCnt2=" + windCnt2 + ", OutIdx=" + outIdx + ", Next=" + next + ", Prev="
+ prev + ", NextInLML=" + nextInLML + ", NextInAEL=" + nextInAEL + ", PrevInAEL=" + prevInAEL + ", NextInSEL=" + nextInSEL
+ ", PrevInSEL=" + prevInSEL + "]";
}
public void updateDeltaX() {
delta.setX( top.getX() - bot.getX() );
delta.setY( top.getY() - bot.getY() );
if (delta.getY() == 0) {
deltaX = Edge.HORIZONTAL;
}
else {
deltaX = (double) delta.getX() / delta.getY();
}
}
}

26
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/LongRect.java

@ -1,26 +0,0 @@
package com.visual.open.anpr.core.clipper;
public class LongRect {
public long left;
public long top;
public long right;
public long bottom;
public LongRect() {
}
public LongRect( long l, long t, long r, long b ) {
left = l;
top = t;
right = r;
bottom = b;
}
public LongRect( LongRect ir ) {
left = ir.left;
top = ir.top;
right = ir.right;
bottom = ir.bottom;
}
}

414
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Path.java

@ -1,414 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
import java.util.ArrayList;
import java.util.Collections;
/**
* A pure convenience class to avoid writing List<IntPoint> everywhere.
*
* @author Tobias Mahlmann
*
*/
public class Path extends ArrayList<LongPoint> {
static class Join {
OutPt outPt1;
OutPt outPt2;
private LongPoint offPt;
public LongPoint getOffPt() {
return offPt;
}
public void setOffPt( LongPoint offPt ) {
this.offPt = offPt;
}
}
static class OutPt {
public static OutRec getLowerMostRec( OutRec outRec1, OutRec outRec2 ) {
//work out which polygon fragment has the correct hole state ...
if (outRec1.bottomPt == null) {
outRec1.bottomPt = outRec1.pts.getBottomPt();
}
if (outRec2.bottomPt == null) {
outRec2.bottomPt = outRec2.pts.getBottomPt();
}
final OutPt bPt1 = outRec1.bottomPt;
final OutPt bPt2 = outRec2.bottomPt;
if (bPt1.getPt().getY() > bPt2.getPt().getY()) {
return outRec1;
}
else if (bPt1.getPt().getY() < bPt2.getPt().getY()) {
return outRec2;
}
else if (bPt1.getPt().getX() < bPt2.getPt().getX()) {
return outRec1;
}
else if (bPt1.getPt().getX() > bPt2.getPt().getX()) {
return outRec2;
}
else if (bPt1.next == bPt1) {
return outRec2;
}
else if (bPt2.next == bPt2) {
return outRec1;
}
else if (isFirstBottomPt( bPt1, bPt2 )) {
return outRec1;
}
else {
return outRec2;
}
}
private static boolean isFirstBottomPt(OutPt btmPt1, OutPt btmPt2 ) {
OutPt p = btmPt1.prev;
while (p.getPt().equals( btmPt1.getPt() ) && !p.equals( btmPt1 )) {
p = p.prev;
}
final double dx1p = Math.abs( LongPoint.getDeltaX( btmPt1.getPt(), p.getPt() ) );
p = btmPt1.next;
while (p.getPt().equals( btmPt1.getPt() ) && !p.equals( btmPt1 )) {
p = p.next;
}
final double dx1n = Math.abs( LongPoint.getDeltaX( btmPt1.getPt(), p.getPt() ) );
p = btmPt2.prev;
while (p.getPt().equals( btmPt2.getPt() ) && !p.equals( btmPt2 )) {
p = p.prev;
}
final double dx2p = Math.abs( LongPoint.getDeltaX( btmPt2.getPt(), p.getPt() ) );
p = btmPt2.next;
while (p.getPt().equals( btmPt2.getPt() ) && p.equals( btmPt2 )) {
p = p.next;
}
final double dx2n = Math.abs( LongPoint.getDeltaX( btmPt2.getPt(), p.getPt() ) );
if (Math.max( dx1p, dx1n ) == Math.max( dx2p, dx2n ) && Math.min( dx1p, dx1n ) == Math.min( dx2p, dx2n )) {
return btmPt1.area() > 0; //if otherwise identical use orientation
}
else {
return dx1p >= dx2p && dx1p >= dx2n || dx1n >= dx2p && dx1n >= dx2n;
}
}
int idx;
private LongPoint pt;
OutPt next;
OutPt prev;
public OutPt duplicate(boolean InsertAfter ) {
final OutPt result = new OutPt();
result.setPt( new LongPoint( getPt() ) );
result.idx = idx;
if (InsertAfter) {
result.next = next;
result.prev = this;
next.prev = result;
next = result;
}
else {
result.prev = prev;
result.next = this;
prev.next = result;
prev = result;
}
return result;
}
OutPt getBottomPt() {
OutPt dups = null;
OutPt p = next;
OutPt pp = this;
while (p != pp) {
if (p.getPt().getY() > pp.getPt().getY()) {
pp = p;
dups = null;
}
else if (p.getPt().getY() == pp.getPt().getY() && p.getPt().getX() <= pp.getPt().getX()) {
if (p.getPt().getX() < pp.getPt().getX()) {
dups = null;
pp = p;
}
else {
if (p.next != pp && p.prev != pp) {
dups = p;
}
}
}
p = p.next;
}
if (dups != null) {
//there appears to be at least 2 vertices at bottomPt so ...
while (dups != p) {
if (!isFirstBottomPt( p, dups )) {
pp = dups;
}
dups = dups.next;
while (!dups.getPt().equals( pp.getPt() )) {
dups = dups.next;
}
}
}
return pp;
}
public static int getPointCount( OutPt pts ) {
if (pts == null) return 0;
int result = 0;
OutPt p = pts;
do {
result++;
p = p.next;
}
while (p != pts);
return result;
}
public LongPoint getPt() {
return pt;
}
public void reversePolyPtLinks() {
OutPt pp1;
OutPt pp2;
pp1 = this;
do {
pp2 = pp1.next;
pp1.next = pp1.prev;
pp1.prev = pp2;
pp1 = pp2;
}
while (pp1 != this);
}
public void setPt( LongPoint pt ) {
this.pt = pt;
}
private double area() {
OutPt op = this;
double a = 0;
do {
a = a + (double) (op.prev.getPt().getX() + op.getPt().getX()) * (double) (op.prev.getPt().getY() - op.getPt().getY());
op = op.next;
} while (op != this);
return a * 0.5;
}
}
/** OutRec: contains a path in the clipping solution. Edges in the AEL will
carry a pointer to an OutRec when they are part of the clipping solution.*/
static class OutRec {
int Idx;
boolean isHole;
boolean isOpen;
OutRec firstLeft; //see comments in clipper.pas
private OutPt pts;
OutPt bottomPt;
PolyNode polyNode;
public double area() {
return pts.area();
}
public void fixHoleLinkage() {
//skip if an outermost polygon or
//already already points to the correct FirstLeft ...
if (firstLeft == null || isHole != firstLeft.isHole && firstLeft.pts != null) {
return;
}
OutRec orfl = firstLeft;
while (orfl != null && (orfl.isHole == isHole || orfl.pts == null)) {
orfl = orfl.firstLeft;
}
firstLeft = orfl;
}
public OutPt getPoints() {
return pts;
}
public static OutRec parseFirstLeft( OutRec firstLeft ) {
while (firstLeft != null && firstLeft.getPoints() == null) {
firstLeft = firstLeft.firstLeft;
}
return firstLeft;
}
public void setPoints( OutPt pts ) {
this.pts = pts;
}
}
private static OutPt excludeOp(OutPt op ) {
final OutPt result = op.prev;
result.next = op.next;
op.next.prev = result;
result.idx = 0;
return result;
}
/**
*
*/
private static final long serialVersionUID = -7120161578077546673L;
public Path() {
super();
}
public Path( int cnt ) {
super( cnt );
}
public double area() {
final int cnt = size();
if (cnt < 3) {
return 0;
}
double a = 0;
for (int i = 0, j = cnt - 1; i < cnt; ++i) {
a += ((double) get( j ).getX() + get( i ).getX()) * ((double) get( j ).getY() - get( i ).getY());
j = i;
}
return -a * 0.5;
}
public Path cleanPolygon() {
return cleanPolygon( 1.415 );
}
public Path cleanPolygon(double distance ) {
//distance = proximity in units/pixels below which vertices will be stripped.
//Default ~= sqrt(2) so when adjacent vertices or semi-adjacent vertices have
//both x & y coords within 1 unit, then the second vertex will be stripped.
int cnt = size();
if (cnt == 0) {
return new Path();
}
OutPt[] outPts = new OutPt[cnt];
for (int i = 0; i < cnt; ++i) {
outPts[i] = new OutPt();
}
for (int i = 0; i < cnt; ++i) {
outPts[i].pt = get( i );
outPts[i].next = outPts[(i + 1) % cnt];
outPts[i].next.prev = outPts[i];
outPts[i].idx = 0;
}
final double distSqrd = distance * distance;
OutPt op = outPts[0];
while (op.idx == 0 && op.next != op.prev) {
if (Point.arePointsClose( op.pt, op.prev.pt, distSqrd )) {
op = excludeOp( op );
cnt--;
}
else if (Point.arePointsClose( op.prev.pt, op.next.pt, distSqrd )) {
excludeOp( op.next );
op = excludeOp( op );
cnt -= 2;
}
else if (Point.slopesNearCollinear( op.prev.pt, op.pt, op.next.pt, distSqrd )) {
op = excludeOp( op );
cnt--;
}
else {
op.idx = 1;
op = op.next;
}
}
if (cnt < 3) {
cnt = 0;
}
final Path result = new Path( cnt );
for (int i = 0; i < cnt; ++i) {
result.add( op.pt );
op = op.next;
}
outPts = null;
return result;
}
public int isPointInPolygon( LongPoint pt ) {
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
int result = 0;
final int cnt = size();
if (cnt < 3) {
return 0;
}
LongPoint ip = get( 0 );
for (int i = 1; i <= cnt; ++i) {
final LongPoint ipNext = i == cnt ? get( 0 ) : get( i );
if (ipNext.getY() == pt.getY()) {
if (ipNext.getX() == pt.getX() || ip.getY() == pt.getY() && ipNext.getX() > pt.getX() == ip.getX() < pt.getX()) {
return -1;
}
}
if (ip.getY() < pt.getY() != ipNext.getY() < pt.getY()) {
if (ip.getX() >= pt.getX()) {
if (ipNext.getX() > pt.getX()) {
result = 1 - result;
}
else {
final double d = (double) (ip.getX() - pt.getX()) * (ipNext.getY() - pt.getY()) - (double) (ipNext.getX() - pt.getX())
* (ip.getY() - pt.getY());
if (d == 0) {
return -1;
}
else if (d > 0 == ipNext.getY() > ip.getY()) {
result = 1 - result;
}
}
}
else {
if (ipNext.getX() > pt.getX()) {
final double d = (double) (ip.getX() - pt.getX()) * (ipNext.getY() - pt.getY()) - (double) (ipNext.getX() - pt.getX())
* (ip.getY() - pt.getY());
if (d == 0) {
return -1;
}
else if (d > 0 == ipNext.getY() > ip.getY()) {
result = 1 - result;
}
}
}
}
ip = ipNext;
}
return result;
}
public boolean orientation() {
return area() >= 0;
}
public void reverse() {
Collections.reverse( this );
}
public Path TranslatePath(LongPoint delta ) {
final Path outPath = new Path( size() );
for (int i = 0; i < size(); i++) {
outPath.add( new LongPoint( get( i ).getX() + delta.getX(), get( i ).getY() + delta.getY() ) );
}
return outPath;
}
}

125
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Paths.java

@ -1,125 +0,0 @@
package com.visual.open.anpr.core.clipper;
import java.util.ArrayList;
/**
* A pure convenience class to avoid writing List<Path> everywhere.
*
* @author Tobias Mahlmann
*
*/
public class Paths extends ArrayList<Path> {
public static Paths closedPathsFromPolyTree(PolyTree polytree ) {
final Paths result = new Paths();
// result.Capacity = polytree.Total;
result.addPolyNode( polytree, PolyNode.NodeType.CLOSED );
return result;
}
public static Paths makePolyTreeToPaths(PolyTree polytree ) {
final Paths result = new Paths();
// result.Capacity = polytree.Total;
result.addPolyNode( polytree, PolyNode.NodeType.ANY );
return result;
}
public static Paths openPathsFromPolyTree(PolyTree polytree ) {
final Paths result = new Paths();
// result.Capacity = polytree.ChildCount;
for (final PolyNode c : polytree.getChilds()) {
if (c.isOpen()) {
result.add( c.getPolygon() );
}
}
return result;
}
/**
*
*/
private static final long serialVersionUID = 1910552127810480852L;
public Paths() {
super();
}
public Paths( int initialCapacity ) {
super( initialCapacity );
}
public void addPolyNode(PolyNode polynode, PolyNode.NodeType nt ) {
boolean match = true;
switch (nt) {
case OPEN:
return;
case CLOSED:
match = !polynode.isOpen();
break;
default:
break;
}
if (polynode.getPolygon().size() > 0 && match) {
add( polynode.getPolygon() );
}
for (final PolyNode pn : polynode.getChilds()) {
addPolyNode( pn, nt );
}
}
public Paths cleanPolygons() {
return cleanPolygons( 1.415 );
}
public Paths cleanPolygons(double distance ) {
final Paths result = new Paths( size() );
for (int i = 0; i < size(); i++) {
result.add( get( i ).cleanPolygon( distance ) );
}
return result;
}
public LongRect getBounds() {
int i = 0;
final int cnt = size();
final LongRect result = new LongRect();
while (i < cnt && get( i ).isEmpty()) {
i++;
}
if (i == cnt) {
return result;
}
result.left = get( i ).get( 0 ).getX();
result.right = result.left;
result.top = get( i ).get( 0 ).getY();
result.bottom = result.top;
for (; i < cnt; i++) {
for (int j = 0; j < get( i ).size(); j++) {
if (get( i ).get( j ).getX() < result.left) {
result.left = get( i ).get( j ).getX();
}
else if (get( i ).get( j ).getX() > result.right) {
result.right = get( i ).get( j ).getX();
}
if (get( i ).get( j ).getY() < result.top) {
result.top = get( i ).get( j ).getY();
}
else if (get( i ).get( j ).getY() > result.bottom) {
result.bottom = get( i ).get( j ).getY();
}
}
}
return result;
}
public void reversePaths() {
for (final Path poly : this) {
poly.reverse();
}
}
}

220
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/Point.java

@ -1,220 +0,0 @@
package com.visual.open.anpr.core.clipper;
import java.util.Comparator;
public abstract class Point<T extends Number & Comparable<T>> {
public static class DoublePoint extends Point<Double> {
public DoublePoint() {
this( 0, 0 );
}
public DoublePoint( double x, double y ) {
this( x, y, 0 );
}
public DoublePoint( double x, double y, double z ) {
super( x, y, z );
}
public DoublePoint( DoublePoint other ) {
super( other );
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
}
public static class LongPoint extends Point<Long> {
public static double getDeltaX(LongPoint pt1, LongPoint pt2 ) {
if (pt1.getY() == pt2.getY()) {
return Edge.HORIZONTAL;
}
else {
return (double) (pt2.getX() - pt1.getX()) / (pt2.getY() - pt1.getY());
}
}
public LongPoint() {
this( 0, 0 );
}
public LongPoint( long x, long y ) {
this( x, y, 0 );
}
public LongPoint( long x, long y, long z ) {
super( x, y, z );
}
public LongPoint( LongPoint other ) {
super( other );
}
public long getX() {
return x;
}
public long getY() {
return y;
}
public long getZ() {
return z;
}
}
private static class NumberComparator<T extends Number & Comparable<T>> implements Comparator<T> {
@Override
public int compare( T a, T b ) throws ClassCastException {
return a.compareTo( b );
}
}
static boolean arePointsClose(Point<? extends Number> pt1, Point<? extends Number> pt2, double distSqrd ) {
final double dx = pt1.x.doubleValue() - pt2.x.doubleValue();
final double dy = pt1.y.doubleValue() - pt2.y.doubleValue();
return dx * dx + dy * dy <= distSqrd;
}
static double distanceFromLineSqrd(Point<? extends Number> pt, Point<? extends Number> ln1, Point<? extends Number> ln2 ) {
//The equation of a line in general form (Ax + By + C = 0)
//given 2 points (x¹,y¹) & (x²,y²) is ...
//(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
//A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
//see http://en.wikipedia.org/wiki/Perpendicular_distance
final double A = ln1.y.doubleValue() - ln2.y.doubleValue();
final double B = ln2.x.doubleValue() - ln1.x.doubleValue();
double C = A * ln1.x.doubleValue() + B * ln1.y.doubleValue();
C = A * pt.x.doubleValue() + B * pt.y.doubleValue() - C;
return C * C / (A * A + B * B);
}
static DoublePoint getUnitNormal( LongPoint pt1, LongPoint pt2 ) {
double dx = pt2.x - pt1.x;
double dy = pt2.y - pt1.y;
if (dx == 0 && dy == 0) {
return new DoublePoint();
}
final double f = 1 * 1.0 / Math.sqrt( dx * dx + dy * dy );
dx *= f;
dy *= f;
return new DoublePoint( dy, -dx );
}
protected static boolean isPt2BetweenPt1AndPt3( LongPoint pt1, LongPoint pt2, LongPoint pt3 ) {
if (pt1.equals( pt3 ) || pt1.equals( pt2 ) || pt3.equals( pt2 )) {
return false;
}
else if (pt1.x != pt3.x) {
return pt2.x > pt1.x == pt2.x < pt3.x;
}
else {
return pt2.y > pt1.y == pt2.y < pt3.y;
}
}
protected static boolean slopesEqual( LongPoint pt1, LongPoint pt2, LongPoint pt3 ) {
return (pt1.y - pt2.y) * (pt2.x - pt3.x) - (pt1.x - pt2.x) * (pt2.y - pt3.y) == 0;
}
protected static boolean slopesEqual( LongPoint pt1, LongPoint pt2, LongPoint pt3, LongPoint pt4 ) {
return (pt1.y - pt2.y) * (pt3.x - pt4.x) - (pt1.x - pt2.x) * (pt3.y - pt4.y) == 0;
}
static boolean slopesNearCollinear( LongPoint pt1, LongPoint pt2, LongPoint pt3, double distSqrd ) {
//this function is more accurate when the point that's GEOMETRICALLY
//between the other 2 points is the one that's tested for distance.
//nb: with 'spikes', either pt1 or pt3 is geometrically between the other pts
if (Math.abs( pt1.x - pt2.x ) > Math.abs( pt1.y - pt2.y )) {
if (pt1.x > pt2.x == pt1.x < pt3.x) {
return distanceFromLineSqrd( pt1, pt2, pt3 ) < distSqrd;
}
else if (pt2.x > pt1.x == pt2.x < pt3.x) {
return distanceFromLineSqrd( pt2, pt1, pt3 ) < distSqrd;
}
else {
return distanceFromLineSqrd( pt3, pt1, pt2 ) < distSqrd;
}
}
else {
if (pt1.y > pt2.y == pt1.y < pt3.y) {
return distanceFromLineSqrd( pt1, pt2, pt3 ) < distSqrd;
}
else if (pt2.y > pt1.y == pt2.y < pt3.y) {
return distanceFromLineSqrd( pt2, pt1, pt3 ) < distSqrd;
}
else {
return distanceFromLineSqrd( pt3, pt1, pt2 ) < distSqrd;
}
}
}
private final static NumberComparator NUMBER_COMPARATOR = new NumberComparator();
protected T x;
protected T y;
protected T z;
protected Point( Point<T> pt ) {
this( pt.x, pt.y, pt.z );
}
protected Point( T x, T y, T z ) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals( Object obj ) {
if (obj == null) {
return false;
}
if (obj instanceof Point<?>) {
final Point<?> a = (Point<?>) obj;
return NUMBER_COMPARATOR.compare( x, a.x ) == 0 && NUMBER_COMPARATOR.compare( y, a.y ) == 0;
}
else {
return false;
}
}
public void set( Point<T> other ) {
x = other.x;
y = other.y;
z = other.z;
}
public void setX( T x ) {
this.x = x;
}
public void setY( T y ) {
this.y = y;
}
public void setZ( T z ) {
this.z = z;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + ", z=" + z + "]";
}
}// end struct IntPoint

116
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/PolyNode.java

@ -1,116 +0,0 @@
package com.visual.open.anpr.core.clipper;
import com.visual.open.anpr.core.clipper.Clipper.EndType;
import com.visual.open.anpr.core.clipper.Clipper.JoinType;
import com.visual.open.anpr.core.clipper.Point.LongPoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PolyNode {
enum NodeType {
ANY, OPEN, CLOSED
}
private PolyNode parent;
private final Path polygon = new Path();
private int index;
private JoinType joinType;
private EndType endType;
final List<PolyNode> childs = new ArrayList<>();
private boolean isOpen;
public void addChild( PolyNode child ) {
final int cnt = childs.size();
childs.add( child );
child.parent = this;
child.index = cnt;
}
public int getChildCount() {
return childs.size();
}
public List<PolyNode> getChilds() {
return Collections.unmodifiableList( childs );
}
public List<LongPoint> getContour() {
return polygon;
}
public EndType getEndType() {
return endType;
}
public JoinType getJoinType() {
return joinType;
}
public PolyNode getNext() {
if (!childs.isEmpty()) {
return childs.get( 0 );
}
else {
return getNextSiblingUp();
}
}
private PolyNode getNextSiblingUp() {
if (parent == null) {
return null;
}
else if (index == parent.childs.size() - 1) {
return parent.getNextSiblingUp();
}
else {
return parent.childs.get( index + 1 );
}
}
public PolyNode getParent() {
return parent;
}
public Path getPolygon() {
return polygon;
}
public boolean isHole() {
return isHoleNode();
}
private boolean isHoleNode() {
boolean result = true;
PolyNode node = parent;
while (node != null) {
result = !result;
node = node.parent;
}
return result;
}
public boolean isOpen() {
return isOpen;
}
public void setEndType( EndType value ) {
endType = value;
}
public void setJoinType( JoinType value ) {
joinType = value;
}
public void setOpen( boolean isOpen ) {
this.isOpen = isOpen;
}
public void setParent( PolyNode n ) {
parent = n;
}
}

37
open-anpr-core/src/main/java/com/visual/open/anpr/core/clipper/PolyTree.java

@ -1,37 +0,0 @@
package com.visual.open.anpr.core.clipper;
import java.util.ArrayList;
import java.util.List;
public class PolyTree extends PolyNode {
private final List<PolyNode> allPolys = new ArrayList<PolyNode>();
public void Clear() {
allPolys.clear();
childs.clear();
}
public List<PolyNode> getAllPolys() {
return allPolys;
}
public PolyNode getFirst() {
if (!childs.isEmpty()) {
return childs.get( 0 );
}
else {
return null;
}
}
public int getTotalSize() {
int result = allPolys.size();
//with negative offsets, ignore the hidden outer polygon ...
if (result > 0 && childs.get( 0 ) != allPolys.get( 0 )) {
result--;
}
return result;
}
}

39
open-anpr-core/src/main/java/com/visual/open/anpr/core/domain/Polygon.java

@ -1,39 +0,0 @@
package com.visual.open.anpr.core.domain;
import org.opencv.core.Point;
import java.util.List;
public class Polygon {
private List<Point> points;
public Polygon(List<Point> points){
this.points = points;
}
public double getArea(){
int i, j;
double area = 0;
for (i = 0; i < this.points.size(); i++)
{
j = (i + 1) % this.points.size();
area += this.points.get(i).x * this.points.get(j).y;
area -= this.points.get(i).y * this.points.get(j).x;
}
area /= 2;
return Math.abs(area);
}
public double getLength(){
double result = 0;
for (int i = 0; i < this.points.size(); i++){
Point u = points.get(i);
Point v = (i+1==this.points.size()) ? points.get(0): points.get(i+1);
double m = u.x - v.x;
double n = u.y - v.y;
result += Math.sqrt(m * m + n * n);
}
return result;
}
}

4
open-anpr-core/src/main/java/com/visual/open/anpr/core/models/TorchPlateRecognition.java

@ -31,13 +31,13 @@ public class TorchPlateRecognition extends BaseOnnxInfer implements PlateRecogn
} }
@Override @Override
public ParseInfo inference(ImageMat image, boolean single, Map<String, Object> params) { public ParseInfo inference(ImageMat image, Boolean single, Map<String, Object> params) {
OnnxTensor tensor = null; OnnxTensor tensor = null;
OrtSession.Result output = null; OrtSession.Result output = null;
ImageMat imageMat = null; ImageMat imageMat = null;
try { try {
//图片处理 //图片处理
imageMat = single ? image.clone() : splitAndMergePlate(image); imageMat = null == single || single ? image.clone() : splitAndMergePlate(image);
//转换数据为张量 //转换数据为张量
tensor = imageMat.resizeAndNoReleaseMat(168, 48) tensor = imageMat.resizeAndNoReleaseMat(168, 48)
.blobFromImageAndDoReleaseMat(1.0/255, new Scalar(MEAN_VALUE, MEAN_VALUE, MEAN_VALUE), true) .blobFromImageAndDoReleaseMat(1.0/255, new Scalar(MEAN_VALUE, MEAN_VALUE, MEAN_VALUE), true)

Loading…
Cancel
Save