use of com.joliciel.jochre.graphics.WritableImageGrid in project jochre by urieli.
the class InnerEmptyChupchikLowerLeftFeature method checkInternal.
@Override
public FeatureResult<Boolean> checkInternal(ShapeWrapper shapeWrapper, RuntimeEnvironment env) {
Shape shape = shapeWrapper.getShape();
BitSet bitset = shape.getBlackAndWhiteBitSet(shape.getJochreImage().getBlackThreshold());
boolean[][] grid = new boolean[shape.getWidth()][shape.getHeight()];
for (int i = 0; i < shape.getWidth(); i++) {
for (int j = 0; j < shape.getHeight(); j++) {
if (bitset.get(j * shape.getWidth() + i))
grid[i][j] = true;
}
}
int startX = shape.getWidth() / 2;
int startY = shape.getHeight() / 2;
while (startY < shape.getHeight() && grid[startX][startY]) {
startY += 1;
}
WritableImageGrid mirror = new ImageMirror(shape);
boolean foundChupchikOrOpening = false;
if (startY < shape.getHeight()) {
Stack<HorizontalLineSegment> whiteLineStack = new Stack<HorizontalLineSegment>();
Set<HorizontalLineSegment> whiteLineSet = new TreeSet<HorizontalLineSegment>();
HorizontalLineSegment startLine = new HorizontalLineSegment(startX, startY);
whiteLineStack.push(startLine);
while (!whiteLineStack.empty()) {
HorizontalLineSegment line = whiteLineStack.pop();
if (line.y == shape.getHeight() - 1) {
// found opening to the outside world
if (LOG.isTraceEnabled())
LOG.trace("Reached edge: found opening");
foundChupchikOrOpening = true;
break;
}
if (mirror.getPixel(line.xLeft, line.y) == 1)
continue;
// extend this line to the right and left
for (int i = line.xLeft; i >= 0; i--) {
if (!grid[i][line.y])
line.xLeft = i;
else
break;
}
for (int i = line.xRight; i <= startX; i++) {
if (!grid[i][line.y])
line.xRight = i;
else
break;
}
if (LOG.isTraceEnabled())
LOG.trace(line.toString());
whiteLineSet.add(line);
for (int i = line.xLeft; i <= line.xRight; i++) {
mirror.setPixel(i, line.y, 1);
}
// find lines below and to the left
if (line.y < shape.getHeight() - 1) {
boolean inLine = false;
int row = line.y + 1;
int xLeft = 0;
for (int i = line.xLeft; i <= line.xRight; i++) {
if (!inLine && !grid[i][row]) {
inLine = true;
xLeft = i;
} else if (inLine && grid[i][row]) {
HorizontalLineSegment newLine = new HorizontalLineSegment(xLeft, row);
newLine.xRight = i - 1;
whiteLineStack.push(newLine);
inLine = false;
}
}
if (inLine) {
HorizontalLineSegment newLine = new HorizontalLineSegment(xLeft, row);
newLine.xRight = line.xRight;
whiteLineStack.push(newLine);
}
}
}
if (!foundChupchikOrOpening) {
// if (LOG.isDebugEnabled()) {
// LOG.trace("List of lines");
// for (HorizontalLineSegment line : whiteLineSet) {
// LOG.trace(line.toString());
// }
// }
Iterator<HorizontalLineSegment> iLines = whiteLineSet.iterator();
HorizontalLineSegment bottomLeftLine = iLines.next();
double threshold = shape.getWidth() / 8;
if (LOG.isTraceEnabled())
LOG.trace("Length threshold: " + threshold);
HorizontalLineSegment nextLine = null;
List<HorizontalLineSegment> firstFewLines = new ArrayList<HorizontalLineSegment>();
firstFewLines.add(bottomLeftLine);
HorizontalLineSegment currentLine = bottomLeftLine;
while (iLines.hasNext() && firstFewLines.size() < 3) {
nextLine = iLines.next();
if (nextLine.y != currentLine.y) {
firstFewLines.add(nextLine);
currentLine = nextLine;
}
}
boolean mightHaveChupchik = true;
HorizontalLineSegment prevLine = null;
for (HorizontalLineSegment line : firstFewLines) {
if (LOG.isTraceEnabled())
LOG.trace("Next line left, " + bottomLeftLine.xLeft + ", length: " + bottomLeftLine.length() + ", threshold: " + threshold);
if (line.length() > threshold) {
mightHaveChupchik = false;
break;
}
if (prevLine != null) {
if (line.xLeft + 2 < prevLine.xLeft) {
mightHaveChupchik = false;
break;
}
if (line.length() + 1 < prevLine.length()) {
mightHaveChupchik = false;
break;
}
}
prevLine = line;
threshold = threshold * 1.2;
}
if (mightHaveChupchik)
foundChupchikOrOpening = true;
}
}
FeatureResult<Boolean> outcome = this.generateResult(foundChupchikOrOpening);
return outcome;
}
Aggregations