mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2025-01-18 22:43:45 +08:00
c81483f714
git-svn-id: https://tesseract-ocr.googlecode.com/svn/trunk@566 d0cd1f9f-072b-0410-8dd7-cf729c803f20
279 lines
10 KiB
C++
279 lines
10 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// File: resultiterator.cpp
|
|
// Description: Iterator for tesseract results that avoids using tesseract
|
|
// internal data structures
|
|
// Author: Ray Smith
|
|
// Created: Fri Feb 26 14:32:09 PST 2010
|
|
//
|
|
// (C) Copyright 2010, Google Inc.
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
#include "resultiterator.h"
|
|
#include "allheaders.h"
|
|
#include "pageres.h"
|
|
#include "tesseractclass.h"
|
|
|
|
namespace tesseract {
|
|
|
|
ResultIterator::ResultIterator(PAGE_RES* page_res, Tesseract* tesseract,
|
|
int scale, int scaled_yres,
|
|
int rect_left, int rect_top,
|
|
int rect_width, int rect_height)
|
|
: PageIterator(page_res, tesseract, scale, scaled_yres,
|
|
rect_left, rect_top, rect_width, rect_height) {
|
|
}
|
|
|
|
ResultIterator::~ResultIterator() {
|
|
}
|
|
|
|
// Returns the null terminated UTF-8 encoded text string for the current
|
|
// object at the given level. Use delete [] to free after use.
|
|
char* ResultIterator::GetUTF8Text(PageIteratorLevel level) const {
|
|
if (it_->word() == NULL) return NULL; // Already at the end!
|
|
STRING text;
|
|
PAGE_RES_IT res_it(*it_);
|
|
WERD_CHOICE* best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
switch (level) {
|
|
case RIL_BLOCK:
|
|
case RIL_PARA:
|
|
do {
|
|
best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
text += best_choice->unichar_string();
|
|
text += res_it.word()->word->flag(W_EOL) ? "\n" : " ";
|
|
res_it.forward();
|
|
} while (res_it.block() == res_it.prev_block());
|
|
break;
|
|
case RIL_TEXTLINE:
|
|
do {
|
|
best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
text += best_choice->unichar_string();
|
|
text += res_it.word()->word->flag(W_EOL) ? "\n" : " ";
|
|
res_it.forward();
|
|
} while (res_it.row() == res_it.prev_row());
|
|
break;
|
|
case RIL_WORD:
|
|
text = best_choice->unichar_string();
|
|
break;
|
|
case RIL_SYMBOL:
|
|
text = tesseract_->unicharset.id_to_unichar(
|
|
best_choice->unichar_id(blob_index_));
|
|
}
|
|
int length = text.length() + 1;
|
|
char* result = new char[length];
|
|
strncpy(result, text.string(), length);
|
|
return result;
|
|
}
|
|
|
|
// Returns the mean confidence of the current object at the given level.
|
|
// The number should be interpreted as a percent probability. (0.0f-100.0f)
|
|
float ResultIterator::Confidence(PageIteratorLevel level) const {
|
|
if (it_->word() == NULL) return 0.0f; // Already at the end!
|
|
float mean_certainty = 0.0f;
|
|
int certainty_count = 0;
|
|
PAGE_RES_IT res_it(*it_);
|
|
WERD_CHOICE* best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
switch (level) {
|
|
case RIL_BLOCK:
|
|
case RIL_PARA:
|
|
do {
|
|
best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
mean_certainty += best_choice->certainty();
|
|
++certainty_count;
|
|
res_it.forward();
|
|
} while (res_it.block() == res_it.prev_block());
|
|
break;
|
|
case RIL_TEXTLINE:
|
|
do {
|
|
best_choice = res_it.word()->best_choice;
|
|
ASSERT_HOST(best_choice != NULL);
|
|
mean_certainty += best_choice->certainty();
|
|
++certainty_count;
|
|
res_it.forward();
|
|
} while (res_it.row() == res_it.prev_row());
|
|
break;
|
|
case RIL_WORD:
|
|
mean_certainty += best_choice->certainty();
|
|
++certainty_count;
|
|
break;
|
|
case RIL_SYMBOL:
|
|
BLOB_CHOICE_LIST_CLIST* choices = best_choice->blob_choices();
|
|
if (choices != NULL) {
|
|
BLOB_CHOICE_LIST_C_IT blob_choices_it(choices);
|
|
for (int blob = 0; blob < blob_index_; ++blob)
|
|
blob_choices_it.forward();
|
|
BLOB_CHOICE_IT choice_it(blob_choices_it.data());
|
|
for (choice_it.mark_cycle_pt();
|
|
!choice_it.cycled_list();
|
|
choice_it.forward()) {
|
|
if (choice_it.data()->unichar_id() ==
|
|
best_choice->unichar_id(blob_index_))
|
|
break;
|
|
}
|
|
mean_certainty += choice_it.data()->certainty();
|
|
} else {
|
|
mean_certainty += best_choice->certainty();
|
|
}
|
|
++certainty_count;
|
|
}
|
|
if (certainty_count > 0) {
|
|
mean_certainty /= certainty_count;
|
|
float confidence = 100 + 5 * mean_certainty;
|
|
if (confidence < 0.0f) confidence = 0.0f;
|
|
if (confidence > 100.0f) confidence = 100.0f;
|
|
return confidence;
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
// Returns the font attributes of the current word. If iterating at a higher
|
|
// level object than words, eg textlines, then this will return the
|
|
// attributes of the first word in that textline.
|
|
// The actual return value is a string representing a font name. It points
|
|
// to an internal table and SHOULD NOT BE DELETED. Lifespan is the same as
|
|
// the iterator itself, ie rendered invalid by various members of
|
|
// TessBaseAPI, including Init, SetImage, End or deleting the TessBaseAPI.
|
|
// Pointsize is returned in printers points (1/72 inch.)
|
|
const char* ResultIterator::WordFontAttributes(bool* is_bold,
|
|
bool* is_italic,
|
|
bool* is_underlined,
|
|
bool* is_monospace,
|
|
bool* is_serif,
|
|
bool* is_smallcaps,
|
|
int* pointsize,
|
|
int* font_id) const {
|
|
if (it_->word() == NULL) return NULL; // Already at the end!
|
|
*font_id = it_->word()->fontinfo_id;
|
|
if (*font_id < 0) return NULL; // No font available.
|
|
const UnicityTable<FontInfo> &font_table = tesseract_->get_fontinfo_table();
|
|
FontInfo font_info = font_table.get(*font_id);
|
|
*is_bold = font_info.is_bold();
|
|
*is_italic = font_info.is_italic();
|
|
*is_underlined = false; // TODO(rays) fix this!
|
|
*is_monospace = font_info.is_fixed_pitch();
|
|
*is_serif = font_info.is_serif();
|
|
*is_smallcaps = it_->word()->small_caps;
|
|
// The font size is calculated from a multiple of the x-height
|
|
// that came from the block.
|
|
float row_height = it_->row()->row->x_height() *
|
|
it_->block()->block->cell_over_xheight();
|
|
// Convert from pixels to printers points.
|
|
*pointsize = scaled_yres_ > 0
|
|
? static_cast<int>(row_height * kPointsPerInch / scaled_yres_ + 0.5)
|
|
: 0;
|
|
|
|
return font_info.name;
|
|
}
|
|
|
|
// Returns true if the current word was found in a dictionary.
|
|
bool ResultIterator::WordIsFromDictionary() const {
|
|
if (it_->word() == NULL) return false; // Already at the end!
|
|
int permuter = it_->word()->best_choice->permuter();
|
|
return permuter == SYSTEM_DAWG_PERM || permuter == FREQ_DAWG_PERM ||
|
|
permuter == USER_DAWG_PERM;
|
|
}
|
|
|
|
// Returns true if the current word is numeric.
|
|
bool ResultIterator::WordIsNumeric() const {
|
|
if (it_->word() == NULL) return false; // Already at the end!
|
|
int permuter = it_->word()->best_choice->permuter();
|
|
return permuter == NUMBER_PERM;
|
|
}
|
|
|
|
// Returns true if the current symbol is a superscript.
|
|
// If iterating at a higher level object than symbols, eg words, then
|
|
// this will return the attributes of the first symbol in that word.
|
|
bool ResultIterator::SymbolIsSuperscript() const {
|
|
if (cblob_it_ == NULL && it_->word() != NULL)
|
|
return it_->word()->box_word->BlobPosition(blob_index_) == SP_SUPERSCRIPT;
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the current symbol is a subscript.
|
|
// If iterating at a higher level object than symbols, eg words, then
|
|
// this will return the attributes of the first symbol in that word.
|
|
bool ResultIterator::SymbolIsSubscript() const {
|
|
if (cblob_it_ == NULL && it_->word() != NULL)
|
|
return it_->word()->box_word->BlobPosition(blob_index_) == SP_SUBSCRIPT;
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the current symbol is a dropcap.
|
|
// If iterating at a higher level object than symbols, eg words, then
|
|
// this will return the attributes of the first symbol in that word.
|
|
bool ResultIterator::SymbolIsDropcap() const {
|
|
if (cblob_it_ == NULL && it_->word() != NULL)
|
|
return it_->word()->box_word->BlobPosition(blob_index_) == SP_DROPCAP;
|
|
return false;
|
|
}
|
|
|
|
ChoiceIterator::ChoiceIterator(const ResultIterator& result_it) {
|
|
ASSERT_HOST(result_it.it_->word() != NULL);
|
|
tesseract_ = result_it.tesseract_;
|
|
PAGE_RES_IT res_it(*result_it.it_);
|
|
WERD_CHOICE* best_choice = res_it.word()->best_choice;
|
|
BLOB_CHOICE_LIST_CLIST* choices = best_choice->blob_choices();
|
|
if (choices != NULL) {
|
|
BLOB_CHOICE_LIST_C_IT blob_choices_it(choices);
|
|
for (int blob = 0; blob < result_it.blob_index_; ++blob)
|
|
blob_choices_it.forward();
|
|
choice_it_ = new BLOB_CHOICE_IT(blob_choices_it.data());
|
|
choice_it_->mark_cycle_pt();
|
|
} else {
|
|
choice_it_ = NULL;
|
|
}
|
|
}
|
|
|
|
ChoiceIterator::~ChoiceIterator() {
|
|
delete choice_it_;
|
|
}
|
|
|
|
// Moves to the next choice for the symbol and returns false if there
|
|
// are none left.
|
|
bool ChoiceIterator::Next() {
|
|
if (choice_it_ == NULL)
|
|
return false;
|
|
choice_it_->forward();
|
|
return !choice_it_->cycled_list();
|
|
}
|
|
|
|
// Returns the null terminated UTF-8 encoded text string for the current
|
|
// choice. Use delete [] to free after use.
|
|
const char* ChoiceIterator::GetUTF8Text() const {
|
|
if (choice_it_ == NULL)
|
|
return NULL;
|
|
UNICHAR_ID id = choice_it_->data()->unichar_id();
|
|
if (id < 0 || id >= tesseract_->unicharset.size() ||
|
|
id == INVALID_UNICHAR_ID)
|
|
return NULL;
|
|
return tesseract_->unicharset.id_to_unichar(id);
|
|
}
|
|
|
|
// Returns the confidence of the current choice.
|
|
// The number should be interpreted as a percent probability. (0.0f-100.0f)
|
|
float ChoiceIterator::Confidence() const {
|
|
if (choice_it_ == NULL)
|
|
return 0.0f;
|
|
float confidence = 100 + 5 * choice_it_->data()->certainty();
|
|
if (confidence < 0.0f) confidence = 0.0f;
|
|
if (confidence > 100.0f) confidence = 100.0f;
|
|
return confidence;
|
|
}
|
|
|
|
|
|
} // namespace tesseract.
|