blob: 52edd776a83336d34fca24a889f0453738174623 [file] [log] [blame]
// Copyright 2006 Google Inc.
// All Rights Reserved.
// Author: <renn@google.com> (Marius Renn)
//
// This file contains the HeliumBinarizer class, used to binarize given
// Clusters in a given Image. Its main strengths are the use of color
// information, which allows the binarizer to search for components, that the
// text detector might have missed.
//
#ifndef HELIUM_MOBILEBINARIZER_H__
#define HELIUM_MOBILEBINARIZER_H__
#include "array.h"
#include "binarizer.h"
#include "box.h"
#include "color.h"
#include "clusterer.h"
#include "mask.h"
#include "unionfind.h"
namespace helium {
class Shape;
// The HeliumBinarizer class contains a complex set of data structures and
// methods to perform binarization and box extension on a given image with
// a given set of Clusters.
// Most of the work is actually done before binarization, when Clusters are
// added to the HeliumBinarizer. Apart from putting the Cluster information
// in a binarization queue (areas_), the Area surrounding the left-most and
// right-most shape is searched for possible overlooked components. This
// is done by a series of scanning and extension methods, that look for pixels
// colored similarly to the outermost Shape, and extend the area, in case
// such pixels are found.
// A number of cases have to be handled: If the extension area is much larger
// than the original Cluster itself, the area is discarded, as we probably ran
// into another part of the Image, that is colored similarly by coincidence
// (such as the frame around a text area).
// We also might run into another Cluster that has been, or will be added to
// the queue for binarization. In such a case, these Areas are merged into
// a single large area.
class HeliumBinarizer : public Binarizer {
public:
// Create a new HeliumBinarizer that will operate on the given Image.
HeliumBinarizer(const Image& image);
// Add a Cluster to the Binarizer. It will be added to an internal list
// of Areas, along with a search area around the Cluster, to search for
// similarly colored components.
void AddCluster(const Cluster& cluster);
// Convenience method to add multiple Clusters. This simply makes multiple
// calls to AddCluster(const Cluster&).
void AddClusters(const ClusterArray& clusters);
// Extracts the next Mask from the Image, along with its bounding box
// within the image. Note, that these bounds may differ from the original
// Cluster bounds, as the HeliumBinarizer attempts to extend Cluster
// bounds, if it finds adjacent components of a similar color.
// Returns false, if no further Mask could be extracted.
bool GetNextMask(Mask& out_mask, Box& out_bounds);
private:
// The Area structure is used internally to mark the areas that require
// binarization. They not only hold the bounding box information, but also
// the expected color and color variance, and an ID that specifies which
// Areas belong to the same Cluster.
struct Area {
Box bounds;
uint8 id;
Color expected;
Color variance;
bool binarized;
// Constructs an Area with all members set to 0.
Area() : bounds(), id(0), expected(0), variance(0), binarized(0) {
}
// Constructs an Area with the given bounds, id, expected color and color
// variance.
Area(Box area_bounds, uint8 area_id, Color area_exp, Color area_var)
: bounds(area_bounds),
id(area_id),
expected(area_exp),
variance(area_var),
binarized(false) {
}
};
// The AreaCluster structure is used to hold multiple Boxes, that belong
// to the same Cluster. This structure is required when scanning for
// potential areas around the Cluster, as these are not necessarily
// rectangular, but do consist of multiple rectangular squares.
struct AreaCluster : ReferenceCounted {
Box bounds;
Array<Box>* boxes;
uint8 id;
Color expected;
Color variance;
// Contructs an empty AreaCluster.
AreaCluster() :
ReferenceCounted(),
bounds(),
boxes(NULL),
id(0),
expected(0),
variance(0) {
}
// Contructs an AreaCluster with the given boxes, the total bounds of
// these boxes, an ID, and the expected color and color variance.
AreaCluster(Array<Box>* box_array, Box total_bounds, uint8 cluster_id,
Color cluster_exp, Color cluster_var)
: ReferenceCounted(),
bounds(total_bounds), boxes(box_array), id(cluster_id),
expected(cluster_exp), variance(cluster_var) {
}
// Deallocates the AreaCluster, if it is not referenced anymore.
~AreaCluster() {
if (ShouldDelete()) DeleteData();
}
// Deletes the Box Array.
void DeleteData() {
delete boxes;
ReferenceCounted::DeleteData(); // Call super
}
};
Array<Area> areas_;
Array<AreaCluster> extension_clusters_;
unsigned current_index_;
uint8 number_of_clusters_;
Unions cluster_classes_;
// Adds an Area for the specified Shape to the areas_ Array for
// binarization.
void AddShapeArea(const Shape& shape, uint8 id);
// Adds an Area, that lies in between two Shapes, to the areas_ Array for
// binarization.
void AddInBetweenArea(const Shape& left, const Shape& right, uint8 id);
// Helper method to check if the specified bounds lie within the source
// Image.
inline bool CheckBounds(const Box& bounds) const;
// This method uses the other Extend... methods to search for new
// components, that the text detector might have missed. It does this by
// scanning the surrounding area of the Shape for pixels that are of a
// similar color as the Shape color. If the detected area is of an
// acceptable size, it is added to the binarization queue.
void ExtendEnd(const Shape& shape, uint8 id, bool right_end);
// Recursively scans for similarly colored pixels to the top of the
// specified Area.
void ExtendTopEndRec(const Area& area, Array<Box>* extensions);
// Recursively scans for similarly colored pixels to the bottom of the
// specified Area.
void ExtendBottomEndRec(const Area& area, Array<Box>* extensions);
// Recursively scans for similarly colored pixels to the left and right of
//the specified Area.
void ExtendEndRec(const Area& area,
Array<Box>* extensions,
bool to_right);
// Finds and outputs the Areas that belong to the same class ID in the
// given list of Areas.
void FindAreasOfClass(int class_id,
Array<Area>& areas,
Array<Area>& found);
// Finds and outputs the Areas that belong to the same class ID in the
// given list of AreaClusters.
void FindAreasOfClassInClusters(int class_id,
Array<AreaCluster>& clusters,
Array<Area>& found);
// If, due to Area extension, an Area overlaps with another, this method is
// called to merge the overlapping areas to one.
void MergeOverlaps(const AreaCluster& cluster);
// This method binarizes the given Area in the input Image into the given
// allocated Mask. The mask_origin parameter must contain the origin of the
// given mask in the input image.
void BinarizeAreaToMask(const Area& area,
Mask& mask,
const Point& mask_origin);
// Returns the bounding box of the areas specified.
Box BoundsOfAreas(const Array<Area>& areas);
// Returns true if pixels similarly colored to the specified area were
// found to the left of the area.
bool ScanLeft(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found to the top of the area.
bool ScanTop(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found to the right of the area.
bool ScanRight(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found to the bottom of the area.
bool ScanBottom(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found in the middle horizontal line of the area.
bool ScanHMiddle(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found in the middle vertical line of the area.
bool ScanVMiddle(const Area& area) const;
// Returns true if pixels similarly colored to the specified area were
// found on the horizontal line, starting from the given point and
// with the same width as the area. This method is used by the above
// Scan... methods.
bool ScanHorizontal(const Area& area, const Point& p) const;
// Returns true if pixels similarly colored to the specified area were
// found on the vertical line, starting from the given point and
// with the same height as the area. This method is used by the above
// Scan... methods.
bool ScanVertical(const Area& area, const Point& p) const;
};
} // namespace
#endif // HELIUM_MOBILEBINARIZER_H__