Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 75 additions & 70 deletions src/api/hocrrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ char* TessBaseAPI::GetHOCRText(ETEXT_DESC* monitor, int page_number) {
if (tesseract_ == nullptr || (page_res_ == nullptr && Recognize(monitor) < 0))
return nullptr;

int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1, scnt = 1, tcnt = 1, gcnt = 1;
int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1, scnt = 1, tcnt = 1, ccnt = 1;
int page_id = page_number + 1; // hOCR uses 1-based page numbers.
bool para_is_ltr = true; // Default direction is LTR
const char* paragraph_lang = nullptr;
Expand Down Expand Up @@ -230,20 +230,14 @@ char* TessBaseAPI::GetHOCRText(ETEXT_DESC* monitor, int page_number) {

// Now, process the word...
int32_t lstm_choice_mode = tesseract_->lstm_choice_mode;
std::vector<std::vector<std::pair<const char*, float>>>* rawTimestepMap =
nullptr;
std::vector<std::vector<std::pair<const char*, float>>>* choiceMap =
std::vector<std::vector<std::vector<std::pair<const char*, float>>>>* rawTimestepMap =
nullptr;
std::vector<std::vector<std::pair<const char*, float>>>* CTCMap =
nullptr;
std::vector<std::vector<std::vector<std::pair<const char*, float>>>>*
symbolMap = nullptr;
if (lstm_choice_mode) {

choiceMap = res_it->GetBestLSTMSymbolChoices();
symbolMap = res_it->GetSegmentedLSTMTimesteps();
CTCMap = res_it->GetBestLSTMSymbolChoices();
rawTimestepMap = res_it->GetRawLSTMTimesteps();
CTCMap = res_it->GetBestCTCSymbolChoices();
}
hocr_str << "\n <span class='ocrx_word'"
<< " id='"
Expand Down Expand Up @@ -302,51 +296,89 @@ char* TessBaseAPI::GetHOCRText(ETEXT_DESC* monitor, int page_number) {
hocr_str << HOcrEscape(grapheme.get()).c_str();
if (hocr_boxes) {
hocr_str << "</span>";
tesseract::ChoiceIterator ci(*res_it);
if (lstm_choice_mode == 1 && ci.Timesteps() != nullptr) {
std::vector<std::vector<std::pair<const char*, float>>>* symbol =
ci.Timesteps();
hocr_str << "\n <span class='ocr_symbol'"
<< " id='"
<< "symbol_" << page_id << "_" << wcnt << "_" << scnt
<< "'>";
for (auto timestep : *symbol) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "timestep" << page_id << "_" << wcnt << "_" << tcnt
<< "'>";
for (auto conf : timestep) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << ccnt
<< "'"
<< " title='x_confs " << int(conf.second * 100)
<< "'>" << HOcrEscape(conf.first).c_str()
<< "</span>";
++ccnt;
}
hocr_str << "</span>";
++tcnt;
}
hocr_str << "\n </span>";
++scnt;
} else if (lstm_choice_mode == 2) {
tesseract::ChoiceIterator ci(*res_it);
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "lstm_choices_" << page_id << "_" << wcnt << "_" << tcnt
<< "'>";
do {
const char* choice = ci.GetUTF8Text();
float choiceconf = ci.Confidence();
if (choice != nullptr) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << ccnt
<< "'"
<< " title='x_confs " << choiceconf << "'>"
<< HOcrEscape(choice).c_str() << "</span>";
ccnt++;
}
} while (ci.Next());
hocr_str << "\n </span>";
tcnt++;
}
}
}
res_it->Next(RIL_SYMBOL);
} while (!res_it->Empty(RIL_BLOCK) && !res_it->IsAtBeginningOf(RIL_WORD));
if (italic) hocr_str << "</em>";
if (bold) hocr_str << "</strong>";
// If the lstm choice mode is required it is added here
if (lstm_choice_mode == 1 && rawTimestepMap != nullptr) {
for (auto timestep : *rawTimestepMap) {
hocr_str << "\n <span class='ocrx_cinfo'"
if (lstm_choice_mode == 1 && !hocr_boxes && rawTimestepMap != nullptr) {
for (auto symbol : *rawTimestepMap) {
hocr_str << "\n <span class='ocr_symbol'"
<< " id='"
<< "timestep_" << page_id << "_" << wcnt << "_" << tcnt << "'"
<< ">";
for (std::pair<const char*, float> conf : timestep) {
hocr_str << "<span class='ocr_glyph'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << gcnt << "'"
<< " title='x_confs " << int(conf.second * 100) << "'>"
<< HOcrEscape(conf.first).c_str() << "</span>";
gcnt++;
}
hocr_str << "</span>";
tcnt++;
}
} else if (lstm_choice_mode == 2 && choiceMap != nullptr) {
for (auto timestep : *choiceMap) {
if (timestep.size() > 0) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< "symbol_" << page_id << "_" << wcnt << "_" << scnt << "'>";
for (auto timestep : symbol) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "lstm_choices_" << page_id << "_" << wcnt << "_" << tcnt
<< "timestep" << page_id << "_" << wcnt << "_" << tcnt
<< "'>";
for (auto & j : timestep) {
hocr_str << "<span class='ocr_glyph'"
for (auto conf : timestep) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << gcnt
<< "choice_" << page_id << "_" << wcnt << "_" << ccnt
<< "'"
<< " title='x_confs " << int(j.second * 100)
<< "'>" << HOcrEscape(j.first).c_str() << "</span>";
gcnt++;
<< " title='x_confs " << int(conf.second * 100) << "'>"
<< HOcrEscape(conf.first).c_str() << "</span>";
++ccnt;
}
hocr_str << "</span>";
tcnt++;
++tcnt;
}
hocr_str << "</span>";
++scnt;
}
} else if (lstm_choice_mode == 4) {
} else if (lstm_choice_mode == 2 && !hocr_boxes && CTCMap != nullptr) {
for (auto timestep : *CTCMap) {
if (timestep.size() > 0) {
hocr_str << "\n <span class='ocrx_cinfo'"
Expand All @@ -359,53 +391,26 @@ char* TessBaseAPI::GetHOCRText(ETEXT_DESC* monitor, int page_number) {
conf = 0.0f;
if (conf > 100.0f)
conf = 100.0f;
hocr_str << "<span class='ocr_glyph'"
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << gcnt
<< "choice_" << page_id << "_" << wcnt << "_" << ccnt
<< "'"
<< " title='x_confs " << conf << "'>"
<< HOcrEscape(j.first).c_str() << "</span>";
gcnt++;
ccnt++;
}
hocr_str << "</span>";
tcnt++;
}
}
} else if (lstm_choice_mode == 3 && symbolMap != nullptr) {
for (auto timesteps : *symbolMap) {
hocr_str << "\n <span class='ocr_symbol'"
<< " id='"
<< "symbol_" << page_id << "_" << wcnt << "_" << scnt
<< "'>";
for (auto timestep : timesteps) {
hocr_str << "\n <span class='ocrx_cinfo'"
<< " id='"
<< "timestep_" << page_id << "_" << wcnt << "_" << tcnt
<< "'"
<< ">";
for (std::pair<const char*, float> conf : timestep) {
hocr_str << "<span class='ocr_glyph'"
<< " id='"
<< "choice_" << page_id << "_" << wcnt << "_" << gcnt
<< "'"
<< " title='x_confs " << int(conf.second * 100) << "'>"
<< HOcrEscape(conf.first).c_str() << "</span>";
gcnt++;
}
hocr_str << "</span>";
tcnt++;
}
hocr_str << "</span>";
scnt++;
}
}
}
// Close ocrx_word.
if (hocr_boxes || lstm_choice_mode > 0) {
hocr_str << "\n ";
}
hocr_str << "</span>";
tcnt = 1;
gcnt = 1;
ccnt = 1;
wcnt++;
// Close any ending block/paragraph/textline.
if (last_word_in_line) {
Expand Down
2 changes: 1 addition & 1 deletion src/ccmain/linerec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ void Tesseract::LSTMRecognizeWord(const BLOCK& block, ROW *row, WERD_RES *word,
lstm_recognizer_->RecognizeLine(*im_data, true, classify_debug_level > 0,
kWorstDictCertainty / kCertaintyScale,
word_box, words, lstm_choice_mode,
lstm_choice_amount);
lstm_choice_iterations);
delete im_data;
SearchWords(words);
}
Expand Down
Loading