Search in sources :

Example 26 with Shape

use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.

the class OriginalShapeLetterAssigner method onGuessSequence.

@Override
public void onGuessSequence(LetterSequence letterSequence) {
    stillValid = true;
    ShapeSequence shapeSequence = letterSequence.getUnderlyingShapeSequence();
    Shape previousOriginalShape = null;
    List<ShapeInSequence> subsequenceForPrevOriginalShape = new ArrayList<ShapeInSequence>();
    for (ShapeInSequence shapeInSequence : shapeSequence) {
        // cases that are possible:
        // 1) shapeInSequence is 1-to-1 with an original shape (A from original shape A)
        // 2) shapeInSequence shares an original shape with previous (B from original shape AB)
        // 3) shapeInSequence shares an original shape with next (A from original shape AB)
        // 4) shapeInSequence shares an original shape with previous and next (B from original shape ABC)
        // 5) shapeInSequence has two original shapes (A from original shapes |A A|)
        // 6) shapeInSequence has 3 original shapes (A from original shapes |A * A|)
        // 7) shapeInSequence shares with previous and has 2+ original shapes (A from |A A|B)
        // 8) shapeInSequence shares with next and has 2+ original shapes (B from A|B B|)
        // So, when we reach a new original shape,
        // either it coincides with a previous shape border, or it doesn't
        List<Shape> originalShapes = shapeInSequence.getOriginalShapes();
        for (Shape nextOriginalShape : originalShapes) {
            if (!nextOriginalShape.equals(previousOriginalShape)) {
                // new original shape, we need to populate the letters of the previous one
                if (previousOriginalShape != null)
                    this.assignLetter(previousOriginalShape, subsequenceForPrevOriginalShape);
                previousOriginalShape = nextOriginalShape;
                subsequenceForPrevOriginalShape = new ArrayList<ShapeInSequence>();
            }
            subsequenceForPrevOriginalShape.add(shapeInSequence);
        }
    // next original shape
    }
    // next underlying shape sequence shape
    if (previousOriginalShape != null)
        this.assignLetter(previousOriginalShape, subsequenceForPrevOriginalShape);
}
Also used : Shape(com.joliciel.jochre.graphics.Shape) ShapeSequence(com.joliciel.jochre.boundaries.ShapeSequence) ArrayList(java.util.ArrayList) ShapeInSequence(com.joliciel.jochre.boundaries.ShapeInSequence)

Example 27 with Shape

use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.

the class OriginalShapeLetterAssigner method assignLetter.

void assignLetter(Shape originalShape, List<ShapeInSequence> subsequenceForOriginalShape) {
    String guessedLetter = "";
    for (ShapeInSequence shapeInSubSequence : subsequenceForOriginalShape) {
        if (shapeInSubSequence.getOriginalShapes().size() == 1) {
            // if this subsequence shape has only one original shape,
            // we can go ahead and add the subsequence shape's letter to the original shape
            guessedLetter += shapeInSubSequence.getShape().getOriginalGuess();
        } else {
            // the subsequence shape has multiple original shapes, so its letter has to be
            // split among all of them (these original shapes were joined into a single new shape)
            int j = 0;
            int myIndex = -1;
            for (Shape myOriginalShape : shapeInSubSequence.getOriginalShapes()) {
                if (myOriginalShape.equals(originalShape)) {
                    myIndex = j;
                    break;
                }
                j++;
            }
            if (myIndex == 0) {
                // the original shape starts this subsequence shape
                if (shapeInSubSequence.getShape().getOriginalGuess().length() > 0)
                    guessedLetter += "|" + shapeInSubSequence.getShape().getOriginalGuess();
            } else if (myIndex == shapeInSubSequence.getOriginalShapes().size() - 1) {
                // the original shape ends this subsequence shape
                if (shapeInSubSequence.getShape().getOriginalGuess().length() > 0)
                    guessedLetter += shapeInSubSequence.getShape().getOriginalGuess() + "|";
            } else {
            // the original shape is in the middle of this subsequence shape
            // nothing to do here, since we leave these blank
            }
        // if more than one, where is the original shape in this subsequence's original shapes
        }
    // only one original shape for this subsequence shape, or more?
    }
    // next shape in subsequence for this original shape
    originalShape.setOriginalGuess(guessedLetter);
    if (currentImage.getImageStatus().equals(ImageStatus.AUTO_NEW))
        originalShape.setLetter(guessedLetter);
    if (save)
        originalShape.save();
    if (evaluate && stillValid) {
        if (letterValidator == null) {
            throw new JochreException("Cannot evaluate without a letter validator.");
        }
        String realLetter = originalShape.getLetter();
        String realLetterForCheck = realLetter.replace("|", "");
        if (letterValidator.validate(realLetterForCheck)) {
            if (guessedLetter.startsWith("|") && guessedLetter.length() == 3 && realLetter.equals("" + guessedLetter.charAt(1))) {
                // the guessed letter is the first half of a split dual letter, and is the same as a real letter
                this.incrementFScore(realLetter, realLetter);
            } else if (guessedLetter.endsWith("|") && guessedLetter.length() == 3 && realLetter.equals("" + guessedLetter.charAt(1))) {
                // the guessed letter is the second half of a split dual letter, and is the same as a real letter
                this.incrementFScore(realLetter, realLetter);
            } else if (realLetter.startsWith("|") && realLetter.length() == 3 && guessedLetter.equals("" + realLetter.charAt(1))) {
                // the real letter is the first half of a split dual letter, and we correctly guessed the first letter of the two
                this.incrementFScore(realLetter, realLetter);
            } else if (realLetter.endsWith("|") && realLetter.length() == 3 && guessedLetter.equals("" + realLetter.charAt(1))) {
                // the real letter is the second half of a split dual letter, and we correctly guessed the second letter of the two
                this.incrementFScore(realLetter, realLetter);
            } else {
                this.incrementFScore(realLetter, guessedLetter);
                if (realLetter.equals(guessedLetter))
                    hasError = true;
            }
        } else {
            // check if there are any invalid characters
            String prevChar = "";
            for (int i = 0; i < realLetterForCheck.length(); i++) {
                String nextChar = "" + realLetterForCheck.charAt(i);
                if (letterValidator.validate(nextChar)) {
                // do nothing
                } else if (letterValidator.validate(prevChar + nextChar)) {
                // do nothing
                } else {
                    stillValid = false;
                    break;
                }
                prevChar = nextChar;
            }
            if (stillValid) {
                this.incrementFScore(realLetter, guessedLetter);
            }
        }
    }
}
Also used : Shape(com.joliciel.jochre.graphics.Shape) JochreException(com.joliciel.jochre.utils.JochreException) ShapeInSequence(com.joliciel.jochre.boundaries.ShapeInSequence)

Example 28 with Shape

use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.

the class SimpleLetterFScoreObserver method onGuessLetter.

@Override
public void onGuessLetter(ShapeInSequence shapeInSequence, String bestGuess) {
    if (stillValid) {
        Shape shape = shapeInSequence.getShape();
        String realLetter = shape.getLetter();
        if (letterValidator.validate(realLetter)) {
            if (realLetter.length() == 0)
                realLetter = "■";
            else if (!jochreSession.getLinguistics().getValidLetters().contains(realLetter)) {
                if (realLetter.contains("|"))
                    realLetter = "□" + realLetter;
                else
                    realLetter = "■" + realLetter;
            }
            if (bestGuess.length() == 0)
                bestGuess = "■";
            else if (!jochreSession.getLinguistics().getValidLetters().contains(bestGuess))
                if (bestGuess.contains("|"))
                    bestGuess = "□" + bestGuess;
                else
                    bestGuess = "■" + bestGuess;
            fScoreCalculator.increment(realLetter, bestGuess);
            if (!realLetter.equals(bestGuess))
                hasError = true;
        } else {
            stillValid = false;
        }
    }
}
Also used : Shape(com.joliciel.jochre.graphics.Shape)

Example 29 with Shape

use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.

the class JochreMergeEventStream method hasNext.

@Override
public boolean hasNext() {
    this.initialiseStream();
    while (mergeCandidate == null && group != null) {
        if (shapeIndex < group.getShapes().size() - 1) {
            Shape shape1 = group.getShapes().get(shapeIndex);
            Shape shape2 = group.getShapes().get(shapeIndex + 1);
            ShapePair shapePair = new ShapePair(shape1, shape2);
            double widthRatio = (double) shapePair.getWidth() / (double) shapePair.getXHeight();
            double distanceRatio = (double) shapePair.getInnerDistance() / (double) shapePair.getXHeight();
            if (widthRatio <= maxWidthRatio && distanceRatio <= maxDistanceRatio) {
                belowRatioCount++;
                mergeCandidate = shapePair;
            } else {
                aboveRatioCount++;
                mergeCandidate = null;
            }
            shapeIndex++;
        } else {
            group = null;
            shapeIndex = 0;
            if (groupReader.hasNext())
                group = groupReader.next();
        }
    }
    if (mergeCandidate == null) {
        LOG.debug("aboveRatioCount: " + aboveRatioCount);
        LOG.debug("belowRatioCount: " + belowRatioCount);
        LOG.debug("yesCount: " + yesCount);
        LOG.debug("noCount: " + noCount);
    }
    return mergeCandidate != null;
}
Also used : Shape(com.joliciel.jochre.graphics.Shape)

Example 30 with Shape

use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.

the class LetterByLetterBoundaryDetector method findBoundaries.

@Override
public List<ShapeSequence> findBoundaries(GroupOfShapes group) {
    // find the possible shape sequences that make up this group
    ShapeSequence emptySequence = new ShapeSequence();
    PriorityQueue<ShapeSequence> heap = new PriorityQueue<ShapeSequence>();
    heap.add(emptySequence);
    for (Shape shape : group.getShapes()) {
        PriorityQueue<ShapeSequence> previousHeap = heap;
        heap = new PriorityQueue<ShapeSequence>();
        // check if shape is wide enough to bother with
        double widthRatio = (double) shape.getWidth() / (double) shape.getXHeight();
        double heightRatio = (double) shape.getHeight() / (double) shape.getXHeight();
        // Splitting/merging shapes as required
        List<ShapeSequence> splitSequences = null;
        if (this.shapeSplitter != null && widthRatio >= minWidthRatioForSplit && heightRatio >= minHeightRatioForSplit) {
            splitSequences = shapeSplitter.split(shape);
        } else {
            // create a sequence containing only this shape
            ShapeSequence singleShapeSequence = new ShapeSequence();
            singleShapeSequence.addShape(shape);
            splitSequences = new ArrayList<ShapeSequence>();
            splitSequences.add(singleShapeSequence);
        }
        // limit the breadth to K
        int maxSequences = previousHeap.size() > this.beamWidth ? this.beamWidth : previousHeap.size();
        for (int j = 0; j < maxSequences; j++) {
            ShapeSequence history = previousHeap.poll();
            for (ShapeSequence splitSequence : splitSequences) {
                ShapeInSequence previousShapeInSequence = null;
                Shape previousShape = null;
                if (history.size() > 0) {
                    previousShapeInSequence = history.get(history.size() - 1);
                    previousShape = previousShapeInSequence.getShape();
                }
                ShapeInSequence firstShapeInSequence = splitSequence.get(0);
                Shape firstShape = firstShapeInSequence.getShape();
                double mergeProb = 0;
                if (this.shapeMerger != null && previousShape != null) {
                    ShapePair mergeCandidate = new ShapePair(previousShape, shape);
                    double mergeCandidateWidthRatio = 0;
                    double mergeCandidateDistanceRatio = 0;
                    mergeCandidateWidthRatio = (double) mergeCandidate.getWidth() / (double) mergeCandidate.getXHeight();
                    mergeCandidateDistanceRatio = (double) mergeCandidate.getInnerDistance() / (double) mergeCandidate.getXHeight();
                    if (mergeCandidateWidthRatio <= maxWidthRatioForMerge && mergeCandidateDistanceRatio <= maxDistanceRatioForMerge) {
                        mergeProb = shapeMerger.checkMerge(previousShape, firstShape);
                    }
                }
                if (mergeProb > 0) {
                    Shape mergedShape = shapeMerger.merge(previousShape, firstShape);
                    ShapeSequence mergedSequence = new ShapeSequence(history);
                    mergedSequence.remove(mergedSequence.size() - 1);
                    List<Shape> originalShapesForMerge = new ArrayList<Shape>();
                    originalShapesForMerge.addAll(previousShapeInSequence.getOriginalShapes());
                    originalShapesForMerge.addAll(firstShapeInSequence.getOriginalShapes());
                    mergedSequence.addShape(mergedShape, originalShapesForMerge);
                    boolean isFirstShape = true;
                    for (ShapeInSequence splitShape : splitSequence) {
                        if (!isFirstShape)
                            mergedSequence.add(splitShape);
                        isFirstShape = false;
                    }
                    heap.add(mergedSequence);
                    Decision mergeDecision = new Decision(MergeOutcome.DO_MERGE.name(), mergeProb);
                    mergedSequence.addDecision(mergeDecision);
                    for (Decision splitDecision : splitSequence.getDecisions()) mergedSequence.addDecision(splitDecision);
                }
                if (mergeProb < 1) {
                    ShapeSequence totalSequence = new ShapeSequence(history);
                    if (mergeProb > 0) {
                        Decision mergeDecision = new Decision(MergeOutcome.DO_NOT_MERGE.name(), 1 - mergeProb);
                        totalSequence.addDecision(mergeDecision);
                    }
                    for (Decision splitDecision : splitSequence.getDecisions()) totalSequence.addDecision(splitDecision);
                    for (ShapeInSequence splitShape : splitSequence) {
                        totalSequence.add(splitShape);
                    }
                    heap.add(totalSequence);
                }
            }
        // next split sequence for this shape
        }
    // next history from previous heap
    }
    // next shape in group
    List<ShapeSequence> result = new ArrayList<ShapeSequence>();
    for (int i = 0; i < this.beamWidth; i++) {
        if (heap.isEmpty())
            break;
        ShapeSequence nextSequence = heap.poll();
        result.add(nextSequence);
    }
    return result;
}
Also used : Shape(com.joliciel.jochre.graphics.Shape) ArrayList(java.util.ArrayList) PriorityQueue(java.util.PriorityQueue) Decision(com.joliciel.talismane.machineLearning.Decision)

Aggregations

Shape (com.joliciel.jochre.graphics.Shape)74 ArrayList (java.util.ArrayList)22 GroupOfShapes (com.joliciel.jochre.graphics.GroupOfShapes)14 JochreImage (com.joliciel.jochre.graphics.JochreImage)13 Paragraph (com.joliciel.jochre.graphics.Paragraph)9 RowOfShapes (com.joliciel.jochre.graphics.RowOfShapes)9 Decision (com.joliciel.talismane.machineLearning.Decision)8 Test (org.junit.Test)8 JochreSession (com.joliciel.jochre.JochreSession)7 JochrePage (com.joliciel.jochre.doc.JochrePage)7 Config (com.typesafe.config.Config)7 TreeSet (java.util.TreeSet)7 JochreDocument (com.joliciel.jochre.doc.JochreDocument)6 BufferedImage (java.awt.image.BufferedImage)6 ShapeInSequence (com.joliciel.jochre.boundaries.ShapeInSequence)5 ShapeSequence (com.joliciel.jochre.boundaries.ShapeSequence)5 GraphicsDao (com.joliciel.jochre.graphics.GraphicsDao)5 RuntimeEnvironment (com.joliciel.talismane.machineLearning.features.RuntimeEnvironment)5 SplitFeature (com.joliciel.jochre.boundaries.features.SplitFeature)4 JochreException (com.joliciel.jochre.utils.JochreException)4