use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.
the class RecursiveShapeSplitterTest method testSplitShapeSplitMoreLikely.
/**
* If a split is always more likely (e.g. 60% likelihood), ensure the shape
* sequences are ordered correctly.
*/
@SuppressWarnings("unchecked")
@Test
public void testSplitShapeSplitMoreLikely() throws Exception {
System.setProperty("config.file", "src/test/resources/test.conf");
ConfigFactory.invalidateCaches();
Config config = ConfigFactory.load();
JochreSession jochreSession = new JochreSession(config);
BufferedImage originalImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
final JochreImage jochreImage = new JochreImage(originalImage, jochreSession);
final Shape shape = new Shape(jochreImage, 0, 0, 63, 15, jochreSession);
shape.setBaseLine(12);
shape.setMeanLine(4);
final Shape shape1 = new Shape(jochreImage, 0, 0, 31, 15, jochreSession);
shape1.setBaseLine(12);
shape1.setMeanLine(4);
final Shape shape2 = new Shape(jochreImage, 32, 0, 63, 15, jochreSession);
shape2.setBaseLine(12);
shape2.setMeanLine(4);
final SplitCandidateFinder splitCandidateFinder = mock(SplitCandidateFinder.class);
final DecisionMaker decisionMaker = mock(DecisionMaker.class);
Split split = new Split(shape, jochreSession);
split.setPosition(31);
List<Split> splits = new ArrayList<>();
splits.add(split);
when(splitCandidateFinder.findSplitCandidates(shape)).thenReturn(splits);
Decision yesDecision = new Decision(SplitOutcome.DO_SPLIT.name(), 0.6);
Decision noDecision = new Decision(SplitOutcome.DO_NOT_SPLIT.name(), 0.4);
List<Decision> decisions = new ArrayList<>();
decisions.add(yesDecision);
decisions.add(noDecision);
when(decisionMaker.decide(anyList())).thenReturn(decisions);
Split split1 = new Split(shape1, jochreSession);
split1.setPosition(15);
List<Split> splits1 = new ArrayList<>();
splits1.add(split1);
when(splitCandidateFinder.findSplitCandidates(shape1)).thenReturn(splits1);
Split split2 = new Split(shape2, jochreSession);
split2.setPosition(15);
List<Split> splits2 = new ArrayList<>();
splits2.add(split2);
when(splitCandidateFinder.findSplitCandidates(shape2)).thenReturn(splits2);
Set<SplitFeature<?>> splitFeatures = new TreeSet<>();
RecursiveShapeSplitter splitter = new RecursiveShapeSplitter(splitCandidateFinder, splitFeatures, decisionMaker, jochreSession);
splitter.setBeamWidth(10);
splitter.setMaxDepth(2);
splitter.setMinWidthRatio(1.0);
List<ShapeSequence> shapeSequences = splitter.split(shape);
assertEquals(5, shapeSequences.size());
int i = 0;
for (ShapeSequence shapeSequence : shapeSequences) {
LOG.debug("sequence " + i + " shapes:");
for (ShapeInSequence shapeInSequence : shapeSequence) {
Shape oneShape = shapeInSequence.getShape();
LOG.debug("Shape: " + oneShape.getLeft() + "," + oneShape.getRight());
}
LOG.debug("" + shapeSequence.getScore());
i++;
}
i = 0;
double prob = 1.0;
double twoThirds = 0.4 / 0.6;
LOG.debug("twoThirds: " + twoThirds);
for (ShapeSequence shapeSequence : shapeSequences) {
LOG.debug("sequence " + i + " decisions:");
for (Decision decision : shapeSequence.getDecisions()) LOG.debug("" + decision.getProbability());
if (i == 0) {
prob = 1.0;
assertEquals(prob, shapeSequence.getScore(), 0.0001);
assertEquals(4, shapeSequence.size());
} else if (i == 1) {
prob = 1.0 * twoThirds;
assertEquals(prob, shapeSequence.getScore(), 0.0001);
assertEquals(3, shapeSequence.size());
} else if (i == 2) {
prob = 1.0 * twoThirds;
assertEquals(prob, shapeSequence.getScore(), 0.0001);
assertEquals(3, shapeSequence.size());
} else if (i == 3) {
prob = 1.0 * twoThirds * twoThirds;
assertEquals(prob, shapeSequence.getScore(), 0.0001);
assertEquals(2, shapeSequence.size());
} else if (i == 4) {
prob = 1.0 * twoThirds * twoThirds * twoThirds;
assertEquals(prob, shapeSequence.getScore(), 0.0001);
assertEquals(1, shapeSequence.size());
}
i++;
}
}
use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.
the class SplitCandidateFinderImplTest method testFindSplitCanidates.
@Test
public void testFindSplitCanidates() throws Exception {
System.setProperty("config.file", "src/test/resources/test.conf");
ConfigFactory.invalidateCaches();
Config config = ConfigFactory.load();
JochreSession jochreSession = new JochreSession(config);
InputStream imageFileStream = getClass().getResourceAsStream("shape_370454.png");
assertNotNull(imageFileStream);
BufferedImage image = ImageIO.read(imageFileStream);
final JochrePage page = mock(JochrePage.class);
JochreImage jochreImage = new SourceImage(page, "name", image, jochreSession);
Shape shape = jochreImage.getShape(0, 0, jochreImage.getWidth() - 1, jochreImage.getHeight() - 1);
SplitCandidateFinder splitCandidateFinder = new SplitCandidateFinder(jochreSession);
List<Split> splits = splitCandidateFinder.findSplitCandidates(shape);
int[] trueSplitPositions = new int[] { 38, 59, 82 };
boolean[] foundSplit = new boolean[] { false, false, false };
for (Split splitCandidate : splits) {
LOG.debug("Split candidate at " + splitCandidate.getPosition());
for (int i = 0; i < trueSplitPositions.length; i++) {
int truePos = trueSplitPositions[i];
int distance = splitCandidate.getPosition() - truePos;
if (distance < 0)
distance = 0 - distance;
if (distance < splitCandidateFinder.getMinDistanceBetweenSplits()) {
foundSplit[i] = true;
LOG.debug("Found split: " + truePos + ", distance " + distance);
}
}
}
for (int i = 0; i < trueSplitPositions.length; i++) {
assertTrue("didn't find split " + trueSplitPositions[i], foundSplit[i]);
}
}
use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.
the class JochreLetterEventStream method hasNext.
@Override
public boolean hasNext() {
this.initialiseStream();
while (shapeInSequence == null && shapeSequence != null) {
while (shapeInSequence == null && shapeIndex < shapeSequence.size()) {
shapeInSequence = shapeSequence.get(shapeIndex);
shapeIndex++;
Shape shape = shapeInSequence.getShape();
String letter = shape.getLetter();
if (!letterValidator.validate(letter)) {
// if there's an invalid letter, skip the rest of this
// group
// note we allow empty letters (which is how we indicate
// ink smudges
// in the text)
LOG.debug("Invalid letter for shape " + shapeInSequence.getOriginalShapes().get(0).getId() + ": " + letter);
invalidLetterCount++;
shapeInSequence = null;
break;
}
}
if (shapeInSequence == null) {
this.getNextGroup();
}
}
if (shapeInSequence == null) {
LOG.debug("invalidLetterCount: " + invalidLetterCount);
}
return shapeInSequence != null;
}
use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.
the class JochreLetterEventStream method next.
@Override
public ClassificationEvent next() {
ClassificationEvent event = null;
if (this.hasNext()) {
Shape shape = shapeInSequence.getShape();
LOG.debug("next event, shape: " + shape);
LetterGuesserContext context = new LetterGuesserContext(shapeInSequence, history);
List<FeatureResult<?>> featureResults = new ArrayList<>();
// analyse features
for (LetterFeature<?> feature : features) {
RuntimeEnvironment env = new RuntimeEnvironment();
FeatureResult<?> featureResult = feature.check(context, env);
if (featureResult != null) {
featureResults.add(featureResult);
if (LOG.isTraceEnabled()) {
LOG.trace(featureResult.toString());
}
}
}
String outcome = shape.getLetter();
event = new ClassificationEvent(featureResults, outcome);
history.getLetters().add(outcome);
// set shape to null so that hasNext can retrieve the next one.
this.shapeInSequence = null;
}
return event;
}
use of com.joliciel.jochre.graphics.Shape in project jochre by urieli.
the class LetterGuesser method guessLetter.
/**
* Analyses this shape, using the context provided for features that are not
* intrinsic. Updates shape.getWeightedOutcomes to include all outcomes
* above a certain threshold of probability.
*
* @return the best outcome for this shape.
*/
public String guessLetter(ShapeInSequence shapeInSequence, LetterSequence history) {
Shape shape = shapeInSequence.getShape();
if (LOG.isTraceEnabled())
LOG.trace("guessLetter, shape: " + shape);
List<FeatureResult<?>> featureResults = new ArrayList<FeatureResult<?>>();
// analyse features
for (LetterFeature<?> feature : features) {
LetterGuesserContext context = new LetterGuesserContext(shapeInSequence, history);
RuntimeEnvironment env = new RuntimeEnvironment();
FeatureResult<?> featureResult = feature.check(context, env);
if (featureResult != null) {
featureResults.add(featureResult);
if (LOG.isTraceEnabled()) {
LOG.trace(featureResult.toString());
}
}
}
List<Decision> letterGuesses = decisionMaker.decide(featureResults);
// store outcomes
String bestOutcome = null;
shape.getLetterGuesses().clear();
for (Decision letterGuess : letterGuesses) {
if (letterGuess.getProbability() >= MIN_PROB_TO_STORE) {
shape.getLetterGuesses().add(letterGuess);
}
}
bestOutcome = shape.getLetterGuesses().iterator().next().getOutcome();
if (LOG.isTraceEnabled()) {
LOG.trace("Shape: " + shape);
LOG.trace("Letter: " + shape.getLetter());
LOG.trace("Best outcome: " + bestOutcome);
}
return bestOutcome;
}
Aggregations