com.joliciel.jochre.graphics.WhiteAreaFinder.java Source code

Java tutorial

Introduction

Here is the source code for com.joliciel.jochre.graphics.WhiteAreaFinder.java

Source

///////////////////////////////////////////////////////////////////////////////
//Copyright (C) 2012 Assaf Urieli
//
//This file is part of Jochre.
//
//Jochre is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//Jochre is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU Affero General Public License for more details.
//
//You should have received a copy of the GNU Affero General Public License
//along with Jochre.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////////////
package com.joliciel.jochre.graphics;

import java.util.List;
import java.util.TreeSet;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Finds white areas of a certain minimum vertical and horizontal dimension
 * given a set of black areas already known in the area.
 * @author Assaf Urieli
 *
 */
class WhiteAreaFinder {
    private static final Log LOG = LogFactory.getLog(WhiteAreaFinder.class);

    public List<Rectangle> getWhiteAreas(ImageGrid imageGrid, int blackThreshold, int left, int top, int right,
            int bottom, double minWhiteAreaWidth, double minWhiteAreaHeight) {
        return this.getWhiteAreas(imageGrid, blackThreshold, null, left, top, right, bottom, minWhiteAreaWidth,
                minWhiteAreaHeight);
    }

    public List<Rectangle> getWhiteAreas(List<? extends Rectangle> shapes, int left, int top, int right, int bottom,
            double minWhiteAreaWidth, double minWhiteAreaHeight) {
        return this.getWhiteAreas(null, 0, shapes, left, top, right, bottom, minWhiteAreaWidth, minWhiteAreaHeight);
    }

    List<Rectangle> getWhiteAreas(ImageGrid imageGrid, int blackThreshold, List<? extends Rectangle> blackAreas,
            int left, int top, int right, int bottom, double minWhiteAreaWidth, double minWhiteAreaHeight) {
        // figure out white areas based on shapes, not isPixelBlack
        List<Rectangle> whiteAreas = new ArrayList<Rectangle>();
        List<WhiteArea> openWhiteAreas = new ArrayList<WhiteArea>();
        TreeSet<Rectangle> blackAreasToConsider = new TreeSet<Rectangle>(new RectangleTopToBottomComparator());
        if (blackAreas != null)
            blackAreasToConsider.addAll(blackAreas);

        // stop "false" column separators from appearing at the top row, below a series of titles
        // these can be recognise because they radically narrow what is already a long strip
        // Now - doing this by getting horizontal boxes first
        //      double minRatioForExtension = 0.5;

        for (int y = top; y <= bottom; y++) {
            // get all white horizontal lines on current row
            List<WhiteLine> whiteLines = new ArrayList<WhiteLine>();
            boolean[] pixels = new boolean[right + 1];
            List<Rectangle> blackAreasToRemove = new ArrayList<Rectangle>();
            for (Rectangle blackArea : blackAreasToConsider) {
                if (blackArea.getBottom() < y)
                    blackAreasToRemove.add(blackArea);
                if (blackArea.getTop() > y)
                    break;
                if (blackArea.getBottom() >= y) {
                    int maxLeft = blackArea.getLeft() > left ? blackArea.getLeft() : left;
                    int minRight = blackArea.getRight() < right ? blackArea.getRight() : right;
                    for (int i = maxLeft; i <= minRight; i++) {
                        pixels[i] = true;
                    }
                }
            }
            blackAreasToConsider.removeAll(blackAreasToRemove);
            boolean inWhite = false;
            int startWhite = 0;
            for (int x = left; x <= right; x++) {
                boolean isBlack = pixels[x];
                // alternate method to a list of rectangles: get black pixel directly
                if (imageGrid != null) {
                    isBlack = imageGrid.isPixelBlack(x, y, blackThreshold);
                }
                if (!inWhite && !isBlack) {
                    startWhite = x;
                    inWhite = true;
                } else if (inWhite && isBlack) {
                    WhiteLine whiteLine = new WhiteLine(startWhite, x - 1);
                    whiteLines.add(whiteLine);
                    inWhite = false;
                }
            }
            if (inWhite) {
                WhiteLine whiteLine = new WhiteLine(startWhite, right);
                whiteLines.add(whiteLine);
            }

            // check if the white horizontal lines extend existing rectangles
            List<WhiteArea> currentWhiteAreas = new ArrayList<WhiteArea>();
            for (WhiteLine whiteLine : whiteLines) {
                for (WhiteArea whiteArea : openWhiteAreas) {
                    int maxLeft = whiteLine.start >= whiteArea.getLeft() ? whiteLine.start : whiteArea.getLeft();
                    int minRight = whiteLine.end <= whiteArea.getRight() ? whiteLine.end : whiteArea.getRight();
                    if (minRight - maxLeft >= minWhiteAreaWidth) {
                        // there is an overlap that's wide enough, add it
                        // but first check the ratio is above the minimum
                        //                  if ((double)(minRight - maxLeft) / (double) (whiteArea.getRight() - whiteArea.getLeft()) > minRatioForExtension) {
                        WhiteArea newWhiteArea = new WhiteArea(maxLeft, whiteArea.getTop(), minRight, y);
                        currentWhiteAreas.add(newWhiteArea);
                        //                  }
                    }
                }
                WhiteArea whiteLineArea = new WhiteArea(whiteLine.start, y, whiteLine.end, y);
                currentWhiteAreas.add(whiteLineArea);
            }
            currentWhiteAreas.addAll(openWhiteAreas);

            // get rid of white areas with full overlap
            List<WhiteArea> whiteAreasToDelete = new ArrayList<WhiteArea>();
            for (int i = 0; i < currentWhiteAreas.size() - 1; i++) {
                WhiteArea whiteArea1 = currentWhiteAreas.get(i);
                for (int j = i + 1; j < currentWhiteAreas.size(); j++) {
                    WhiteArea whiteArea2 = currentWhiteAreas.get(j);
                    if (whiteArea1.getLeft() >= whiteArea2.getLeft() && whiteArea1.getTop() >= whiteArea2.getTop()
                            && whiteArea1.getRight() <= whiteArea2.getRight()
                            && whiteArea1.getBottom() <= whiteArea2.getBottom()) {
                        whiteAreasToDelete.add(whiteArea1);
                    } else if (whiteArea2.getLeft() >= whiteArea1.getLeft()
                            && whiteArea2.getTop() >= whiteArea1.getTop()
                            && whiteArea2.getRight() <= whiteArea1.getRight()
                            && whiteArea2.getBottom() <= whiteArea1.getBottom()) {
                        whiteAreasToDelete.add(whiteArea2);
                    }
                }
            }
            currentWhiteAreas.removeAll(whiteAreasToDelete);

            openWhiteAreas = new ArrayList<WhiteArea>();
            for (WhiteArea whiteArea : currentWhiteAreas) {
                if (whiteArea.getBottom() < y
                        && (whiteArea.getBottom() - whiteArea.getTop() >= minWhiteAreaHeight)) {
                    LOG.debug("Adding " + whiteArea.toString());
                    whiteAreas.add(whiteArea);
                } else if (whiteArea.getBottom() == y) {
                    openWhiteAreas.add(whiteArea);
                }
            }
        }
        for (WhiteArea whiteArea : openWhiteAreas) {
            if (whiteArea.getBottom() - whiteArea.getTop() >= minWhiteAreaHeight) {
                LOG.debug("Adding " + whiteArea.toString());
                whiteAreas.add(whiteArea);
            }
        }
        return whiteAreas;
    }

    private static class WhiteLine {
        public WhiteLine(int start, int end) {
            this.start = start;
            this.end = end;
        }

        public int start;
        public int end;
    }
}