@@ -358,7 +358,17 @@ bool LTRResultIterator::SymbolIsDropcap() const {
358
358
ChoiceIterator::ChoiceIterator (const LTRResultIterator& result_it) {
359
359
ASSERT_HOST (result_it.it_ ->word () != nullptr );
360
360
word_res_ = result_it.it_ ->word ();
361
+ oemLSTM_ = word_res_->tesseract ->AnyLSTMLang ();
362
+ oemLegacy_ = word_res_->tesseract ->AnyTessLang ();
361
363
BLOB_CHOICE_LIST* choices = nullptr ;
364
+ tstep_index_ = &result_it.blob_index_ ;
365
+ if (oemLSTM_ && !oemLegacy_ && &word_res_->accumulated_timesteps != nullptr ) {
366
+ if (word_res_->leadingSpace )
367
+ LSTM_choices_ = &word_res_->accumulated_timesteps [(*tstep_index_) + 1 ];
368
+ else
369
+ LSTM_choices_ = &word_res_->accumulated_timesteps [*tstep_index_];
370
+ filterSpaces ();
371
+ }
362
372
if (word_res_->ratings != nullptr )
363
373
choices = word_res_->GetBlobChoices (result_it.blob_index_ );
364
374
if (choices != nullptr && !choices->empty ()) {
@@ -367,49 +377,93 @@ ChoiceIterator::ChoiceIterator(const LTRResultIterator& result_it) {
367
377
} else {
368
378
choice_it_ = nullptr ;
369
379
}
370
- if (&word_res_->symbol_steps != nullptr && !word_res_->symbol_steps .empty ()) {
371
- symbol_step_it_ = word_res_->symbol_steps .begin ();
380
+ if (LSTM_choices_ != nullptr && !LSTM_choices_->empty ()) {
381
+ LSTM_mode_ = true ;
382
+ LSTM_choice_it_ = LSTM_choices_->begin ();
372
383
}
373
384
}
374
-
375
385
ChoiceIterator::~ChoiceIterator () { delete choice_it_; }
376
386
377
387
// Moves to the next choice for the symbol and returns false if there
378
388
// are none left.
379
389
bool ChoiceIterator::Next () {
380
- if (choice_it_ == nullptr ) return false ;
381
- if (&word_res_-> symbol_steps != nullptr ) {
382
- if (symbol_step_it_ == word_res_-> symbol_steps . end ()) {
383
- symbol_step_it_ = word_res_-> symbol_steps . begin () ;
390
+ if (LSTM_mode_) {
391
+ if (LSTM_choice_it_ != LSTM_choices_-> end () &&
392
+ next (LSTM_choice_it_) == LSTM_choices_-> end ()) {
393
+ return false ;
384
394
} else {
385
- symbol_step_it_++;
386
- }
395
+ ++LSTM_choice_it_;
396
+ return true ;
397
+ }
398
+ } else {
399
+ if (choice_it_ == nullptr ) return false ;
400
+ choice_it_->forward ();
401
+ return !choice_it_->cycled_list ();
387
402
}
388
- choice_it_->forward ();
389
- return !choice_it_->cycled_list ();
390
403
}
391
404
392
405
// Returns the null terminated UTF-8 encoded text string for the current
393
406
// choice. Do NOT use delete [] to free after use.
394
407
const char * ChoiceIterator::GetUTF8Text () const {
395
- if (choice_it_ == nullptr ) return nullptr ;
396
- UNICHAR_ID id = choice_it_->data ()->unichar_id ();
397
- return word_res_->uch_set ->id_to_unichar_ext (id);
408
+ if (LSTM_mode_) {
409
+ std::pair<const char *, float > choice = *LSTM_choice_it_;
410
+ return choice.first ;
411
+ } else {
412
+ if (choice_it_ == nullptr ) return nullptr ;
413
+ UNICHAR_ID id = choice_it_->data ()->unichar_id ();
414
+ return word_res_->uch_set ->id_to_unichar_ext (id);
415
+ }
398
416
}
399
417
400
- // Returns the confidence of the current choice.
401
- // The number should be interpreted as a percent probability. (0.0f-100.0f)
418
+ // Returns the confidence of the current choice depending on the used language
419
+ // data. If only LSTM traineddata is used the value range is 0.0f - 1.0f. All
420
+ // choices for one symbol should roughly add up to 1.0f.
421
+ // If only traineddata of the legacy engine is used, the number should be
422
+ // interpreted as a percent probability. (0.0f-100.0f) In this case probabilities
423
+ // won't add up to 100. Each one stands on its own.
402
424
float ChoiceIterator::Confidence () const {
403
- if (choice_it_ == nullptr ) return 0 .0f ;
404
- float confidence = 100 + 5 * choice_it_->data ()->certainty ();
405
- if (confidence < 0 .0f ) confidence = 0 .0f ;
406
- if (confidence > 100 .0f ) confidence = 100 .0f ;
407
- return confidence;
425
+ if (LSTM_mode_) {
426
+ std::pair<const char *, float > choice = *LSTM_choice_it_;
427
+ return choice.second ;
428
+ } else {
429
+ if (choice_it_ == nullptr ) return 0 .0f ;
430
+ float confidence = 100 + 5 * choice_it_->data ()->certainty ();
431
+ if (confidence < 0 .0f ) confidence = 0 .0f ;
432
+ if (confidence > 100 .0f ) confidence = 100 .0f ;
433
+ return confidence;
434
+ }
408
435
}
409
436
437
+ // Returns the set of timesteps which belong to the current symbol
410
438
std::vector<std::vector<std::pair<const char *, float >>>*
411
439
ChoiceIterator::Timesteps () const {
412
- if (&word_res_->symbol_steps == nullptr ) return nullptr ;
413
- return &*symbol_step_it_;
440
+ if (&word_res_->symbol_steps == nullptr || !LSTM_mode_) return nullptr ;
441
+ if (word_res_->leadingSpace ) {
442
+ return &word_res_->symbol_steps [*(tstep_index_) + 1 ];
443
+ } else {
444
+ return &word_res_->symbol_steps [*tstep_index_];
445
+ }
446
+ }
447
+
448
+ void ChoiceIterator::filterSpaces () {
449
+ if (LSTM_choices_->empty ()) return ;
450
+ std::vector<std::pair<const char *, float >>::iterator it =
451
+ LSTM_choices_->begin ();
452
+ bool found_space = false ;
453
+ float sum = 0 ;
454
+ for (it; it != LSTM_choices_->end ();) {
455
+ if (!strcmp (it->first , " " )) {
456
+ it = LSTM_choices_->erase (it);
457
+ found_space = true ;
458
+ } else {
459
+ sum += it->second ;
460
+ ++it;
461
+ }
462
+ }
463
+ if (found_space) {
464
+ for (it = LSTM_choices_->begin (); it != LSTM_choices_->end (); ++it) {
465
+ it->second /= sum;
466
+ }
467
+ }
414
468
}
415
469
} // namespace tesseract.
0 commit comments