Fix old TODO (STATS::rangemax_)

Signed-off-by: Stefan Weil <sw@weilnetz.de>
This commit is contained in:
Stefan Weil 2021-12-29 20:18:36 +01:00
parent 31a968432d
commit 76faf16006
31 changed files with 124 additions and 130 deletions

View File

@ -159,7 +159,7 @@ PAGE_RES *Tesseract::ApplyBoxes(const char *filename, bool find_segmentation,
// Helper computes median xheight in the image.
static double MedianXHeight(BLOCK_LIST *block_list) {
BLOCK_IT block_it(block_list);
STATS xheights(0, block_it.data()->pdblk.bounding_box().height());
STATS xheights(0, block_it.data()->pdblk.bounding_box().height() - 1);
for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
ROW_IT row_it(block_it.data()->row_list());
for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {

View File

@ -2015,7 +2015,7 @@ void Tesseract::set_word_fonts(WERD_RES *word) {
void Tesseract::font_recognition_pass(PAGE_RES *page_res) {
PAGE_RES_IT page_res_it(page_res);
WERD_RES *word; // current word
STATS doc_fonts(0, font_table_size_); // font counters
STATS doc_fonts(0, font_table_size_ - 1); // font counters
// Gather font id statistics.
for (page_res_it.restart_page(); page_res_it.word() != nullptr; page_res_it.forward()) {

View File

@ -103,8 +103,8 @@ int Tesseract::CountMisfitTops(WERD_RES *word_res) {
// Returns a new x-height maximally compatible with the result in word_res.
// See comment above for overall algorithm.
float Tesseract::ComputeCompatibleXheight(WERD_RES *word_res, float *baseline_shift) {
STATS top_stats(0, UINT8_MAX);
STATS shift_stats(-UINT8_MAX, UINT8_MAX);
STATS top_stats(0, UINT8_MAX - 1);
STATS shift_stats(-UINT8_MAX, UINT8_MAX - 1);
int bottom_shift = 0;
int num_blobs = word_res->rebuild_word->NumBlobs();
do {

View File

@ -1623,8 +1623,8 @@ void RecomputeMarginsAndClearHypotheses(std::vector<RowScratchRegisters> *rows,
UpdateRange(sr.lmargin_ + sr.lindent_, &lmin, &lmax);
UpdateRange(sr.rmargin_ + sr.rindent_, &rmin, &rmax);
}
STATS lefts(lmin, lmax + 1);
STATS rights(rmin, rmax + 1);
STATS lefts(lmin, lmax);
STATS rights(rmin, rmax);
for (int i = start; i < end; i++) {
RowScratchRegisters &sr = (*rows)[i];
if (sr.ri_->num_words == 0) {
@ -1655,7 +1655,7 @@ int InterwordSpace(const std::vector<RowScratchRegisters> &rows, int row_start,
(rows[row_start].ri_->lword_box.height() + rows[row_end - 1].ri_->lword_box.height()) / 2;
int word_width =
(rows[row_start].ri_->lword_box.width() + rows[row_end - 1].ri_->lword_box.width()) / 2;
STATS spacing_widths(0, 5 + word_width);
STATS spacing_widths(0, 4 + word_width);
for (int i = row_start; i < row_end; i++) {
if (rows[i].ri_->num_words > 1) {
spacing_widths.add(rows[i].ri_->average_interword_space, 1);

View File

@ -810,7 +810,7 @@ void TO_ROW::compute_vertical_projection() { // project whole row
row_box += blob_it.data()->bounding_box();
}
projection.set_range(row_box.left() - PROJECTION_MARGIN, row_box.right() + PROJECTION_MARGIN);
projection.set_range(row_box.left() - PROJECTION_MARGIN, row_box.right() + PROJECTION_MARGIN - 1);
projection_left = row_box.left() - PROJECTION_MARGIN;
projection_right = row_box.right() + PROJECTION_MARGIN;
for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {

View File

@ -725,8 +725,8 @@ public:
ASSERT_HOST(block->pdblk.poly_block() != nullptr);
block->rotate(rotation);
// Update the median size statistic from the blobs list.
STATS widths(0, block->pdblk.bounding_box().width());
STATS heights(0, block->pdblk.bounding_box().height());
STATS widths(0, block->pdblk.bounding_box().width() - 1);
STATS heights(0, block->pdblk.bounding_box().height() - 1);
BLOBNBOX_IT blob_it(&blobs);
for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
widths.add(blob_it.data()->bounding_box().width(), 1);

View File

@ -40,14 +40,14 @@ namespace tesseract {
*
* Construct a new stats element by allocating and zeroing the memory.
**********************************************************************/
STATS::STATS(int32_t min_bucket_value, int32_t max_bucket_value_plus_1) {
if (max_bucket_value_plus_1 <= min_bucket_value) {
STATS::STATS(int32_t min_bucket_value, int32_t max_bucket_value) {
if (max_bucket_value < min_bucket_value) {
min_bucket_value = 0;
max_bucket_value_plus_1 = 1;
max_bucket_value = 1;
}
rangemin_ = min_bucket_value; // setup
rangemax_ = max_bucket_value_plus_1;
buckets_ = new int32_t[rangemax_ - rangemin_];
rangemax_ = max_bucket_value;
buckets_ = new int32_t[1 + rangemax_ - rangemin_];
clear();
}
@ -56,16 +56,16 @@ STATS::STATS(int32_t min_bucket_value, int32_t max_bucket_value_plus_1) {
*
* Alter the range on an existing stats element.
**********************************************************************/
bool STATS::set_range(int32_t min_bucket_value, int32_t max_bucket_value_plus_1) {
if (max_bucket_value_plus_1 <= min_bucket_value) {
bool STATS::set_range(int32_t min_bucket_value, int32_t max_bucket_value) {
if (max_bucket_value < min_bucket_value) {
return false;
}
if (rangemax_ - rangemin_ != max_bucket_value_plus_1 - min_bucket_value) {
if (rangemax_ - rangemin_ != max_bucket_value - min_bucket_value) {
delete[] buckets_;
buckets_ = new int32_t[max_bucket_value_plus_1 - min_bucket_value];
buckets_ = new int32_t[1 + max_bucket_value - min_bucket_value];
}
rangemin_ = min_bucket_value; // setup
rangemax_ = max_bucket_value_plus_1;
rangemax_ = max_bucket_value;
clear(); // zero it
return true;
}
@ -78,7 +78,7 @@ bool STATS::set_range(int32_t min_bucket_value, int32_t max_bucket_value_plus_1)
void STATS::clear() { // clear out buckets
total_count_ = 0;
if (buckets_ != nullptr) {
memset(buckets_, 0, (rangemax_ - rangemin_) * sizeof(buckets_[0]));
memset(buckets_, 0, (1 + rangemax_ - rangemin_) * sizeof(buckets_[0]));
}
}
@ -97,12 +97,11 @@ STATS::~STATS() {
* Add a set of samples to (or delete from) a pile.
**********************************************************************/
void STATS::add(int32_t value, int32_t count) {
if (buckets_ == nullptr) {
return;
}
value = ClipToRange(value, rangemin_, rangemax_ - 1);
if (buckets_ != nullptr) {
value = ClipToRange(value, rangemin_, rangemax_);
buckets_[value - rangemin_] += count;
total_count_ += count; // keep count of total
}
}
/**********************************************************************
@ -116,7 +115,7 @@ int32_t STATS::mode() const { // get mode of samples
}
int32_t max = buckets_[0]; // max cell count
int32_t maxindex = 0; // index of max
for (int index = rangemax_ - rangemin_ - 1; index > 0; --index) {
for (int index = rangemax_ - rangemin_; index > 0; --index) {
if (buckets_[index] > max) {
max = buckets_[index]; // find biggest
maxindex = index;
@ -135,7 +134,7 @@ double STATS::mean() const { // get mean of samples
return static_cast<double>(rangemin_);
}
int64_t sum = 0;
for (int index = rangemax_ - rangemin_ - 1; index >= 0; --index) {
for (int index = rangemax_ - rangemin_; index >= 0; --index) {
sum += static_cast<int64_t>(index) * buckets_[index];
}
return static_cast<double>(sum) / total_count_ + rangemin_;
@ -152,7 +151,7 @@ double STATS::sd() const { // standard deviation
}
int64_t sum = 0;
double sqsum = 0.0;
for (int index = rangemax_ - rangemin_ - 1; index >= 0; --index) {
for (int index = rangemax_ - rangemin_; index >= 0; --index) {
sum += static_cast<int64_t>(index) * buckets_[index];
sqsum += static_cast<double>(index) * index * buckets_[index];
}
@ -186,7 +185,7 @@ double STATS::ile(double frac) const {
#endif
int sum = 0;
int index = 0;
for (index = 0; index < rangemax_ - rangemin_ && sum < target; sum += buckets_[index++]) {
for (index = 0; index <= rangemax_ - rangemin_ && sum < target; sum += buckets_[index++]) {
;
}
if (index > 0) {
@ -207,7 +206,7 @@ int32_t STATS::min_bucket() const { // Find min
return rangemin_;
}
int32_t min = 0;
for (min = 0; (min < rangemax_ - rangemin_) && (buckets_[min] == 0); min++) {
for (min = 0; (min <= rangemax_ - rangemin_) && (buckets_[min] == 0); min++) {
;
}
return rangemin_ + min;
@ -224,7 +223,7 @@ int32_t STATS::max_bucket() const { // Find max
return rangemin_;
}
int32_t max;
for (max = rangemax_ - rangemin_ - 1; max > 0 && buckets_[max] == 0; max--) {
for (max = rangemax_ - rangemin_; max > 0 && buckets_[max] == 0; max--) {
;
}
return rangemin_ + max;
@ -270,7 +269,7 @@ bool STATS::local_min(int32_t x) const {
if (buckets_ == nullptr) {
return false;
}
x = ClipToRange(x, rangemin_, rangemax_ - 1) - rangemin_;
x = ClipToRange(x, rangemin_, rangemax_) - rangemin_;
if (buckets_[x] == 0) {
return true;
}
@ -281,10 +280,10 @@ bool STATS::local_min(int32_t x) const {
if (index >= 0 && buckets_[index] < buckets_[x]) {
return false;
}
for (index = x + 1; index < rangemax_ - rangemin_ && buckets_[index] == buckets_[x]; ++index) {
for (index = x + 1; index <= rangemax_ - rangemin_ && buckets_[index] == buckets_[x]; ++index) {
;
}
if (index < rangemax_ - rangemin_ && buckets_[index] < buckets_[x]) {
if (index <= rangemax_ - rangemin_ && buckets_[index] < buckets_[x]) {
return false;
} else {
return true;
@ -304,7 +303,7 @@ void STATS::smooth(int32_t factor) {
return;
}
STATS result(rangemin_, rangemax_);
int entrycount = rangemax_ - rangemin_;
int entrycount = 1 + rangemax_ - rangemin_;
for (int entry = 0; entry < entrycount; entry++) {
// centre weight
int count = buckets_[entry] * factor;
@ -368,7 +367,7 @@ int32_t STATS::cluster(float lower, // thresholds
clusters[0].add(entry, count);
}
}
for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry < rangemax_ &&
for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry <= rangemax_ &&
pile_count(entry) <= pile_count(entry - 1);
entry++) {
count = pile_count(entry) - clusters[0].pile_count(entry);
@ -386,7 +385,7 @@ int32_t STATS::cluster(float lower, // thresholds
do {
new_cluster = false;
new_mode = 0;
for (entry = 0; entry < rangemax_ - rangemin_; entry++) {
for (entry = 0; entry <= rangemax_ - rangemin_; entry++) {
count = buckets_[entry] - clusters[0].buckets_[entry];
// remaining pile
if (count > 0) { // any to handle
@ -433,7 +432,7 @@ int32_t STATS::cluster(float lower, // thresholds
clusters[0].add(entry, count);
}
}
for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry < rangemax_ &&
for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry <= rangemax_ &&
pile_count(entry) <= pile_count(entry - 1);
entry++) {
count = pile_count(entry) - clusters[0].pile_count(entry);
@ -482,7 +481,7 @@ int STATS::top_n_modes(int max_modes, std::vector<KDPairInc<float, int>> &modes)
if (max_modes <= 0) {
return 0;
}
int src_count = rangemax_ - rangemin_;
int src_count = 1 + rangemax_ - rangemin_;
// Used copies the counts in buckets_ as they get used.
STATS used(rangemin_, rangemax_);
modes.clear();
@ -605,7 +604,7 @@ void STATS::plot(ScrollView *window, // to draw in
}
window->Pen(colour);
for (int index = 0; index < rangemax_ - rangemin_; index++) {
for (int index = 0; index <= rangemax_ - rangemin_; index++) {
window->Rectangle(xorigin + xscale * index, yorigin, xorigin + xscale * (index + 1),
yorigin + yscale * buckets_[index]);
}
@ -630,7 +629,7 @@ void STATS::plotline(ScrollView *window, // to draw in
}
window->Pen(colour);
window->SetCursor(xorigin, yorigin + yscale * buckets_[0]);
for (int index = 0; index < rangemax_ - rangemin_; index++) {
for (int index = 0; index <= rangemax_ - rangemin_; index++) {
window->DrawTo(xorigin + xscale * index, yorigin + yscale * buckets_[index]);
}
}

View File

@ -30,23 +30,20 @@ namespace tesseract {
class TESS_API STATS {
public:
// The histogram buckets are in the range
// [min_bucket_value, max_bucket_value_plus_1 - 1] i.e.
// [min_bucket_value, max_bucket_value].
// Any data under min_bucket value is silently mapped to min_bucket_value,
// and likewise, any data over max_bucket_value is silently mapped to
// max_bucket_value.
// In the internal array, min_bucket_value maps to 0 and
// max_bucket_value_plus_1 - min_bucket_value to the array size.
// TODO(rays) This is ugly. Convert the second argument to
// max_bucket_value and all the code that uses it.
STATS(int32_t min_bucket_value, int32_t max_bucket_value_plus_1);
// 1 + max_bucket_value - min_bucket_value to the array size.
STATS(int32_t min_bucket_value, int32_t max_bucket_value);
STATS() = default; // empty for arrays
~STATS();
// (Re)Sets the range and clears the counts.
// See the constructor for info on max and min values.
bool set_range(int32_t min_bucket_value, int32_t max_bucket_value_plus_1);
bool set_range(int32_t min_bucket_value, int32_t max_bucket_value);
void clear(); // empty buckets
@ -79,8 +76,8 @@ public:
if (value <= rangemin_) {
return buckets_[0];
}
if (value >= rangemax_ - 1) {
return buckets_[rangemax_ - rangemin_ - 1];
if (value >= rangemax_) {
return buckets_[rangemax_ - rangemin_];
}
return buckets_[value - rangemin_];
}
@ -142,7 +139,6 @@ public:
private:
int32_t rangemin_ = 0; // min of range
// rangemax_ is not well named as it is really one past the max.
int32_t rangemax_ = 0; // max of range
int32_t total_count_ = 0; // no of samples
int32_t *buckets_ = nullptr; // array of cells

View File

@ -294,7 +294,7 @@ void LSTMRecognizer::RecognizeLine(const ImageData &image_data, bool invert, boo
void LSTMRecognizer::OutputStats(const NetworkIO &outputs, float *min_output, float *mean_output,
float *sd) {
const int kOutputScale = INT8_MAX;
STATS stats(0, kOutputScale + 1);
STATS stats(0, kOutputScale);
for (int t = 0; t < outputs.Width(); ++t) {
int best_label = outputs.BestLabel(t, nullptr);
if (best_label != null_char_) {

View File

@ -127,7 +127,7 @@ void NetworkIO::ZeroInvalidElements() {
static void ComputeBlackWhite(Image pix, float *black, float *white) {
int width = pixGetWidth(pix);
int height = pixGetHeight(pix);
STATS mins(0, 256), maxes(0, 256);
STATS mins(0, 255), maxes(0, 255);
if (width >= 3) {
int y = height / 2;
l_uint32 *line = pixGetData(pix) + pixGetWpl(pix) * y;

View File

@ -525,7 +525,7 @@ static void HistogramWeight(TFloat weight, STATS *histogram) {
}
void WeightMatrix::Debug2D(const char *msg) {
STATS histogram(0, kHistogramBuckets);
STATS histogram(0, kHistogramBuckets - 1);
if (int_mode_) {
for (int i = 0; i < wi_.dim1(); ++i) {
for (int j = 0; j < wi_.dim2(); ++j) {

View File

@ -320,7 +320,7 @@ void BaselineRow::SetupBlobDisplacements(const FCOORD &direction) {
}
// Set up a histogram using disp_quant_factor_ as the bucket size.
STATS dist_stats(IntCastRounded(min_dist / disp_quant_factor_),
IntCastRounded(max_dist / disp_quant_factor_) + 1);
IntCastRounded(max_dist / disp_quant_factor_));
for (double perp_blob_dist : perp_blob_dists) {
dist_stats.add(IntCastRounded(perp_blob_dist / disp_quant_factor_), 1);
}

View File

@ -55,7 +55,7 @@ bool test_underline( // look for underlines
auto blob_box = blob->bounding_box();
auto blob_width = blob->bounding_box().width();
projection.set_range(blob_box.bottom(), blob_box.top() + 1);
projection.set_range(blob_box.bottom(), blob_box.top());
if (testing_on) {
// blob->plot(to_win,GOLDENROD,GOLDENROD);
// line_color_index(to_win,GOLDENROD);

View File

@ -808,7 +808,7 @@ bool ColumnFinder::BiggestUnassignedRange(int set_count, const bool *any_columns
int ColumnFinder::RangeModalColumnSet(int **column_set_costs, const int *assigned_costs, int start,
int end) {
int column_count = column_sets_.size();
STATS column_stats(0, column_count);
STATS column_stats(0, column_count - 1);
for (int part_i = start; part_i < end; ++part_i) {
for (int col_j = 0; col_j < column_count; ++col_j) {
if (column_set_costs[part_i][col_j] < assigned_costs[part_i]) {
@ -1577,8 +1577,8 @@ void ColumnFinder::RotateAndReskewBlocks(bool input_is_rtl, TO_BLOCK_LIST *block
FCOORD blob_rotation = ComputeBlockAndClassifyRotation(block);
// Rotate all the blobs if needed and recompute the bounding boxes.
// Compute the block median blob width and height as we go.
STATS widths(0, block->pdblk.bounding_box().width());
STATS heights(0, block->pdblk.bounding_box().height());
STATS widths(0, block->pdblk.bounding_box().width() - 1);
STATS heights(0, block->pdblk.bounding_box().height() - 1);
RotateAndExplodeBlobList(blob_rotation, &to_block->blobs, &widths, &heights);
TO_ROW_IT row_it(to_block->get_rows());
for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {

View File

@ -949,12 +949,12 @@ void ColPartition::ComputeLimits() {
median_right_ = bounding_box_.right();
median_width_ = bounding_box_.width();
} else {
STATS top_stats(bounding_box_.bottom(), bounding_box_.top() + 1);
STATS bottom_stats(bounding_box_.bottom(), bounding_box_.top() + 1);
STATS height_stats(0, bounding_box_.height() + 1);
STATS left_stats(bounding_box_.left(), bounding_box_.right() + 1);
STATS right_stats(bounding_box_.left(), bounding_box_.right() + 1);
STATS width_stats(0, bounding_box_.width() + 1);
STATS top_stats(bounding_box_.bottom(), bounding_box_.top());
STATS bottom_stats(bounding_box_.bottom(), bounding_box_.top());
STATS height_stats(0, bounding_box_.height());
STATS left_stats(bounding_box_.left(), bounding_box_.right());
STATS right_stats(bounding_box_.left(), bounding_box_.right());
STATS width_stats(0, bounding_box_.width());
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
bbox = it.data();
if (non_leader_count == 0 || bbox->flow() != BTFT_LEADER) {
@ -1132,8 +1132,8 @@ bool ColPartition::MarkAsLeaderIfMonospaced() {
bool result = false;
// Gather statistics on the gaps between blobs and the widths of the blobs.
int part_width = bounding_box_.width();
STATS gap_stats(0, part_width);
STATS width_stats(0, part_width);
STATS gap_stats(0, part_width - 1);
STATS width_stats(0, part_width - 1);
BLOBNBOX_C_IT it(&boxes_);
BLOBNBOX *prev_blob = it.data();
prev_blob->set_flow(BTFT_NEIGHBOURS);
@ -1489,7 +1489,7 @@ void ColPartition::LineSpacingBlocks(const ICOORD &bleft, const ICOORD &tright,
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
ColPartition *part = it.data();
ASSERT_HOST(!part->boxes()->empty());
STATS side_steps(0, part->bounding_box().height());
STATS side_steps(0, part->bounding_box().height() - 1);
if (part->bounding_box().height() > max_line_height) {
max_line_height = part->bounding_box().height();
}
@ -1626,7 +1626,7 @@ static TO_BLOCK *MoveBlobsToBlock(bool vertical_text, int line_spacing,
// that have have to continue to exist until the part grid is deleted.
// Compute the median blob size as we go, as the block needs to know.
TBOX block_box(block->pdblk.bounding_box());
STATS sizes(0, std::max(block_box.width(), block_box.height()));
STATS sizes(0, std::max(block_box.width(), block_box.height()) - 1);
bool text_type = block->pdblk.poly_block()->IsText();
ColPartition_IT it(block_parts);
auto *to_block = new TO_BLOCK(block);
@ -1884,8 +1884,8 @@ void ColPartition::PrintColors() {
// Sets the types of all partitions in the run to be the max of the types.
void ColPartition::SmoothPartnerRun(int working_set_count) {
STATS left_stats(0, working_set_count);
STATS right_stats(0, working_set_count);
STATS left_stats(0, working_set_count - 1);
STATS right_stats(0, working_set_count - 1);
PolyBlockType max_type = type_;
ColPartition *partner;
for (partner = SingletonPartner(false); partner != nullptr;
@ -2250,7 +2250,7 @@ bool ColPartition::ThisPartitionBetter(BLOBNBOX *bbox,
// The iterator is passed by value so the iteration does not modify the
// caller's iterator.
static int MedianSpacing(int page_height, ColPartition_IT it) {
STATS stats(0, page_height);
STATS stats(0, page_height - 1);
while (!it.cycled_list()) {
ColPartition *part = it.data();
it.forward();

View File

@ -3,7 +3,6 @@
* Description: Methods to process images containing devanagari symbols,
* prior to classification.
* Author: Shobhit Saxena
* Created: Mon Nov 17 20:26:01 IST 2008
*
* (C) Copyright 2008, Google Inc.
** Licensed under the Apache License, Version 2.0 (the "License");
@ -387,7 +386,7 @@ Box *ShiroRekhaSplitter::GetBoxForTBOX(const TBOX &tbox) const {
// It also prunes very small blobs from calculation.
int ShiroRekhaSplitter::GetModeHeight(Image pix) {
Boxa *boxa = pixConnComp(pix, nullptr, 8);
STATS heights(0, pixGetHeight(pix));
STATS heights(0, pixGetHeight(pix) - 1);
heights.clear();
for (int i = 0; i < boxaGetCount(boxa); ++i) {
Box *box = boxaGetBox(boxa, i, L_CLONE);

View File

@ -43,7 +43,7 @@ GAPMAP::GAPMAP( // Constructor
int16_t gap_width;
int16_t start_of_row;
int16_t end_of_row;
STATS xht_stats(0, 128);
STATS xht_stats(0, 127);
int16_t min_quantum;
int16_t max_quantum;
int16_t i;

View File

@ -451,9 +451,9 @@ void ImageFind::ComputeRectangleColors(const TBOX &rect, Image pix, int factor,
Image scaled = pixClipRectangle(pix, scaled_box, nullptr);
// Compute stats over the whole image.
STATS red_stats(0, 256);
STATS green_stats(0, 256);
STATS blue_stats(0, 256);
STATS red_stats(0, 255);
STATS green_stats(0, 255);
STATS blue_stats(0, 255);
uint32_t *data = pixGetData(scaled);
ASSERT_HOST(pixGetWpl(scaled) == width_pad);
for (int y = 0; y < height_pad; ++y) {

View File

@ -518,7 +518,7 @@ void vigorous_noise_removal(TO_BLOCK *block) {
max_height = blob->bounding_box().height();
}
}
STATS hstats(0, max_height + 1);
STATS hstats(0, max_height);
for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
BLOBNBOX *blob = b_it.data();
int height = blob->bounding_box().height();
@ -1288,16 +1288,16 @@ void Textord::compute_block_xheight(TO_BLOCK *block, float gradient) {
// Compute the best guess of xheight of each row individually.
// Use xheight and ascrise values of the rows where ascenders were found.
get_min_max_xheight(block->line_size, &min_height, &max_height);
STATS row_asc_xheights(min_height, max_height + 1);
STATS row_asc_xheights(min_height, max_height);
STATS row_asc_ascrise(static_cast<int>(min_height * asc_frac_xheight),
static_cast<int>(max_height * asc_frac_xheight) + 1);
static_cast<int>(max_height * asc_frac_xheight));
int min_desc_height = static_cast<int>(min_height * desc_frac_xheight);
int max_desc_height = static_cast<int>(max_height * desc_frac_xheight);
STATS row_asc_descdrop(min_desc_height, max_desc_height + 1);
STATS row_desc_xheights(min_height, max_height + 1);
STATS row_desc_descdrop(min_desc_height, max_desc_height + 1);
STATS row_cap_xheights(min_height, max_height + 1);
STATS row_cap_floating_xheights(min_height, max_height + 1);
STATS row_asc_descdrop(min_desc_height, max_desc_height);
STATS row_desc_xheights(min_height, max_height);
STATS row_desc_descdrop(min_desc_height, max_desc_height);
STATS row_cap_xheights(min_height, max_height);
STATS row_cap_floating_xheights(min_height, max_height);
for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
row = row_it.data();
// Compute the xheight of this row if it has not been computed before.
@ -1394,8 +1394,8 @@ void Textord::compute_row_xheight(TO_ROW *row, // row to do
int min_height, max_height;
get_min_max_xheight(block_line_size, &min_height, &max_height);
STATS heights(min_height, max_height + 1);
STATS floating_heights(min_height, max_height + 1);
STATS heights(min_height, max_height);
STATS floating_heights(min_height, max_height);
fill_heights(row, gradient, min_height, max_height, &heights, &floating_heights);
row->ascrise = 0.0f;
row->xheight = 0.0f;
@ -1594,7 +1594,7 @@ int32_t compute_row_descdrop(TO_ROW *row, float gradient, int xheight_blob_count
float height; // height of blob
BLOBNBOX_IT blob_it = row->blob_list();
BLOBNBOX *blob; // current blob
STATS heights(min_height, max_height + 1);
STATS heights(min_height, max_height);
for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
blob = blob_it.data();
if (!blob->joined_to_prev()) {

View File

@ -426,7 +426,7 @@ int get_blob_coords( // get boxes
int losscount; // lost blobs
int maxlosscount; // greatest lost blobs
/*height stat collection */
STATS heightstat(0, MAXHEIGHT);
STATS heightstat(0, MAXHEIGHT - 1);
if (blob_it.empty()) {
return 0; // none
@ -1347,7 +1347,7 @@ void old_first_xheight( // the wiseowl way
) {
int blobindex; /*current blob */
/*height statistics */
STATS heightstat(0, MAXHEIGHT);
STATS heightstat(0, MAXHEIGHT - 1);
int height; /*height of blob */
int xcentre; /*centre of blob */
int lineheight; /*approx xheight */
@ -1427,7 +1427,7 @@ void make_first_xheight( // find xheight
QSPLINE *baseline, /*established */
float jumplimit /*min ascender height */
) {
STATS heightstat(0, HEIGHTBUCKETS);
STATS heightstat(0, HEIGHTBUCKETS - 1);
int lefts[HEIGHTBUCKETS];
int rights[HEIGHTBUCKETS];
int modelist[MODENUM];

View File

@ -567,7 +567,7 @@ void StrokeWidth::MarkLeaderNeighbours(const ColPartition *part, LeftOrRight sid
// Helper to compute the UQ of the square-ish CJK characters.
static int UpperQuartileCJKSize(int gridsize, BLOBNBOX_LIST *blobs) {
STATS sizes(0, gridsize * kMaxCJKSizeRatio);
STATS sizes(0, gridsize * kMaxCJKSizeRatio - 1);
BLOBNBOX_IT it(blobs);
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
BLOBNBOX *blob = it.data();

View File

@ -971,7 +971,7 @@ void TabFind::ComputeColumnWidths(ScrollView *tab_win, ColPartitionGrid *part_gr
#endif // !GRAPHICS_DISABLED
// Accumulate column sections into a STATS
int col_widths_size = (tright_.x() - bleft_.x()) / kColumnWidthFactor;
STATS col_widths(0, col_widths_size + 1);
STATS col_widths(0, col_widths_size);
ApplyPartitionsToColumnWidths(part_grid, &col_widths);
#ifndef GRAPHICS_DISABLED
if (tab_win != nullptr) {
@ -1099,8 +1099,8 @@ int TabFind::FindMedianGutterWidth(TabVector_LIST *lines) {
TabVector_IT it(lines);
int prev_right = -1;
int max_gap = static_cast<int>(kMaxGutterWidthAbsolute * resolution_);
STATS gaps(0, max_gap);
STATS heights(0, max_gap);
STATS gaps(0, max_gap - 1);
STATS heights(0, max_gap - 1);
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
TabVector *v = it.data();
TabVector *partner = v->GetSinglePartner();

View File

@ -714,9 +714,9 @@ void TableFinder::SetVerticalSpacing(ColPartition *part) {
// Set global spacing and x-height estimates
void TableFinder::SetGlobalSpacings(ColPartitionGrid *grid) {
STATS xheight_stats(0, kMaxVerticalSpacing + 1);
STATS width_stats(0, kMaxBlobWidth + 1);
STATS ledding_stats(0, kMaxVerticalSpacing + 1);
STATS xheight_stats(0, kMaxVerticalSpacing);
STATS width_stats(0, kMaxBlobWidth);
STATS ledding_stats(0, kMaxVerticalSpacing);
// Iterate the ColPartitions in the grid.
ColPartitionGridSearch gsearch(grid);
gsearch.SetUniqueMode(true);

View File

@ -529,8 +529,8 @@ int StructuredTable::FindHorizontalMargin(ColPartitionGrid *grid, int border, bo
void StructuredTable::CalculateStats() {
const int kMaxCellHeight = 1000;
const int kMaxCellWidth = 1000;
STATS height_stats(0, kMaxCellHeight + 1);
STATS width_stats(0, kMaxCellWidth + 1);
STATS height_stats(0, kMaxCellHeight);
STATS width_stats(0, kMaxCellWidth);
for (unsigned i = 0; i < row_count(); ++i) {
height_stats.add(row_height(i), column_count());

View File

@ -608,7 +608,7 @@ void TabVector::Evaluate(const ICOORD &vertical, TabFind *finder) {
max_gutter = kGutterToNeighbourRatio * mean_height;
}
STATS gutters(0, max_gutter + 1);
STATS gutters(0, max_gutter);
// Evaluate the boxes for their goodness, calculating the coverage as we go.
// Remove boxes that are not good and shorten the list to the first and
// last good boxes.
@ -901,7 +901,7 @@ TabVector *TabVector::VerticalTextlinePartner() {
if (width < 0) {
width = -width;
}
STATS gaps(0, width * 2);
STATS gaps(0, width * 2 - 1);
BLOBNBOX *prev_bbox = nullptr;
box_it2.mark_cycle_pt();
for (box_it1.mark_cycle_pt(); !box_it1.cycled_list(); box_it1.forward()) {

View File

@ -163,8 +163,8 @@ void fix_row_pitch(TO_ROW *bad_row, // row to fix
block_votes = like_votes = other_votes = 0;
maxwidth = static_cast<int32_t>(ceil(bad_row->xheight * textord_words_maxspace));
if (bad_row->pitch_decision != PITCH_DEF_FIXED && bad_row->pitch_decision != PITCH_DEF_PROP) {
block_stats.set_range(0, maxwidth);
like_stats.set_range(0, maxwidth);
block_stats.set_range(0, maxwidth - 1);
like_stats.set_range(0, maxwidth - 1);
block_index = 1;
for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
block = block_it.data();
@ -392,7 +392,7 @@ bool try_doc_fixed( // determine pitch
float final_pitch; // output pitch
float row_y; // baseline
STATS projection; // entire page
STATS pitches(0, MAX_ALLOWED_PITCH);
STATS pitches(0, MAX_ALLOWED_PITCH - 1);
// for median
float sp_sd; // space sd
int16_t mid_cuts; // no of cheap cuts
@ -438,7 +438,7 @@ bool try_doc_fixed( // determine pitch
if (pitches.get_total() == 0) {
return false;
}
projection.set_range(projection_left, projection_right);
projection.set_range(projection_left, projection_right - 1);
for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
block = block_it.data();
@ -663,7 +663,7 @@ bool row_pitch_stats( // find line stats
float gaps[BLOCK_STATS_CLUSTERS];
// blobs
BLOBNBOX_IT blob_it = row->blob_list();
STATS gap_stats(0, maxwidth);
STATS gap_stats(0, maxwidth - 1);
STATS cluster_stats[BLOCK_STATS_CLUSTERS + 1];
// clusters
@ -801,9 +801,9 @@ bool find_row_pitch( // find lines
float dm_pitch; // pitch with dm on
float pitch; // revised estimate
float initial_pitch; // guess at pitch
STATS gap_stats(0, maxwidth);
STATS gap_stats(0, maxwidth - 1);
// centre-centre
STATS pitch_stats(0, maxwidth);
STATS pitch_stats(0, maxwidth - 1);
row->fixed_pitch = 0.0f;
initial_pitch = row->fp_space;
@ -1225,7 +1225,7 @@ float tune_row_pitch2( // find fp cells
std::unique_ptr<STATS[]> sum_proj(new STATS[textord_pitch_range * 2 + 1]); // summed projection
for (pitch_delta = -textord_pitch_range; pitch_delta <= textord_pitch_range; pitch_delta++) {
sum_proj[textord_pitch_range + pitch_delta].set_range(0, best_pitch + pitch_delta + 1);
sum_proj[textord_pitch_range + pitch_delta].set_range(0, best_pitch + pitch_delta);
}
for (pixel = projection_left; pixel <= projection_right; pixel++) {
for (pitch_delta = -textord_pitch_range; pitch_delta <= textord_pitch_range; pitch_delta++) {

View File

@ -80,7 +80,7 @@ void SetBlobStrokeWidth(Image pix, BLOBNBOX *blob) {
uint32_t *data = pixGetData(dist_pix);
int wpl = pixGetWpl(dist_pix);
// Horizontal width of stroke.
STATS h_stats(0, width + 1);
STATS h_stats(0, width);
for (int y = 0; y < height; ++y) {
uint32_t *pixels = data + y * wpl;
int prev_pixel = 0;
@ -104,7 +104,7 @@ void SetBlobStrokeWidth(Image pix, BLOBNBOX *blob) {
}
}
// Vertical width of stroke.
STATS v_stats(0, height + 1);
STATS v_stats(0, height);
for (int x = 0; x < width; ++x) {
int prev_pixel = 0;
int pixel = GET_DATA_BYTE(data, x);
@ -300,7 +300,7 @@ float Textord::filter_noise_blobs(BLOBNBOX_LIST *src_list, // original list
BLOBNBOX_IT noise_it = noise_list;
BLOBNBOX_IT small_it = small_list;
BLOBNBOX_IT large_it = large_list;
STATS size_stats(0, MAX_NEAREST_DIST);
STATS size_stats(0, MAX_NEAREST_DIST - 1);
// blob heights
float min_y; // size limits
float max_y;

View File

@ -112,10 +112,10 @@ void Textord::block_spacing_stats(TO_BLOCK *block, GAPMAP *gapmap, bool &old_tex
TO_ROW *row; // current row
BLOBNBOX_IT blob_it; // iterator
STATS centre_to_centre_stats(0, MAXSPACING);
STATS centre_to_centre_stats(0, MAXSPACING - 1);
// DEBUG USE ONLY
STATS all_gap_stats(0, MAXSPACING);
STATS space_gap_stats(0, MAXSPACING);
STATS all_gap_stats(0, MAXSPACING - 1);
STATS space_gap_stats(0, MAXSPACING - 1);
int16_t minwidth = MAXSPACING; // narrowest blob
TBOX blob_box;
TBOX prev_blob_box;
@ -274,10 +274,10 @@ void Textord::row_spacing_stats(TO_ROW *row, GAPMAP *gapmap, int16_t block_idx,
) {
// iterator
BLOBNBOX_IT blob_it = row->blob_list();
STATS all_gap_stats(0, MAXSPACING);
STATS cert_space_gap_stats(0, MAXSPACING);
STATS all_space_gap_stats(0, MAXSPACING);
STATS small_gap_stats(0, MAXSPACING);
STATS all_gap_stats(0, MAXSPACING - 1);
STATS cert_space_gap_stats(0, MAXSPACING - 1);
STATS all_space_gap_stats(0, MAXSPACING - 1);
STATS small_gap_stats(0, MAXSPACING - 1);
TBOX blob_box;
TBOX prev_blob_box;
int16_t gap_width;
@ -636,9 +636,9 @@ bool Textord::isolated_row_stats(TO_ROW *row, GAPMAP *gapmap, STATS *all_gap_sta
int16_t total;
// iterator
BLOBNBOX_IT blob_it = row->blob_list();
STATS cert_space_gap_stats(0, MAXSPACING);
STATS all_space_gap_stats(0, MAXSPACING);
STATS small_gap_stats(0, MAXSPACING);
STATS cert_space_gap_stats(0, MAXSPACING - 1);
STATS all_space_gap_stats(0, MAXSPACING - 1);
STATS small_gap_stats(0, MAXSPACING - 1);
TBOX blob_box;
TBOX prev_blob_box;
int16_t gap_width;

View File

@ -166,9 +166,9 @@ void find_underlined_blobs( // get chop points
TBOX blob_box = u_line->bounding_box();
// cell iterator
ICOORDELT_IT cell_it = chop_cells;
STATS upper_proj(blob_box.left(), blob_box.right() + 1);
STATS middle_proj(blob_box.left(), blob_box.right() + 1);
STATS lower_proj(blob_box.left(), blob_box.right() + 1);
STATS upper_proj(blob_box.left(), blob_box.right());
STATS middle_proj(blob_box.left(), blob_box.right());
STATS lower_proj(blob_box.left(), blob_box.right());
C_OUTLINE_IT out_it; // outlines of blob
ASSERT_HOST(u_line->cblob() != nullptr);

View File

@ -185,7 +185,7 @@ int32_t row_words( // compute space size
TBOX blob_box; // bounding box
// iterator
BLOBNBOX_IT blob_it = row->blob_list();
STATS gap_stats(0, maxwidth);
STATS gap_stats(0, maxwidth - 1);
STATS cluster_stats[4]; // clusters
testpt = ICOORD(textord_test_x, textord_test_y);
@ -341,7 +341,7 @@ int32_t row_words2( // compute space size
TBOX blob_box; // bounding box
// iterator
BLOBNBOX_IT blob_it = row->blob_list();
STATS gap_stats(0, maxwidth);
STATS gap_stats(0, maxwidth - 1);
// gap sizes
float gaps[BLOCK_STATS_CLUSTERS];
STATS cluster_stats[BLOCK_STATS_CLUSTERS + 1];

View File

@ -22,7 +22,7 @@ class STATSTest : public testing::Test {
public:
void SetUp() override {
std::locale::global(std::locale(""));
stats_.set_range(0, 16);
stats_.set_range(0, 15);
for (size_t i = 0; i < countof(kTestData); ++i) {
stats_.add(i, kTestData[i]);
}