tesseract  5.0.0
tesseract::FPRow Class Reference

Public Member Functions

 FPRow ()
 
 ~FPRow ()=default
 
void Init (TO_ROW *row)
 
void EstimatePitch (bool pass1)
 
void Pass1Analyze ()
 
bool Pass2Analyze ()
 
void MergeFragments ()
 
void FinalizeLargeChars ()
 
void OutputEstimations ()
 
void DebugOutputResult (int row_index)
 
int good_pitches ()
 
float pitch ()
 
float estimated_pitch ()
 
void set_estimated_pitch (float v)
 
float height ()
 
float height_pitch_ratio ()
 
float gap ()
 
size_t num_chars ()
 
FPCharcharacter (int i)
 
const TBOXbox (int i)
 
const TBOXreal_body (int i)
 
bool is_box_modified (int i)
 
float center_x (int i)
 
bool is_final (int i)
 
void finalize (int i)
 
bool is_good (int i)
 
void mark_good (int i)
 
void mark_bad (int i)
 
void clear_alignment (int i)
 

Detailed Description

Definition at line 288 of file cjkpitch.cpp.

Constructor & Destructor Documentation

◆ FPRow()

tesseract::FPRow::FPRow ( )
inline

Definition at line 290 of file cjkpitch.cpp.

290 : all_pitches_(), all_gaps_(), good_pitches_(), good_gaps_(), heights_(), characters_() {}

◆ ~FPRow()

tesseract::FPRow::~FPRow ( )
default

Member Function Documentation

◆ box()

const TBOX& tesseract::FPRow::box ( int  i)
inline

Definition at line 366 of file cjkpitch.cpp.

366  {
367  return characters_[i].box();
368  }

◆ center_x()

float tesseract::FPRow::center_x ( int  i)
inline

Definition at line 378 of file cjkpitch.cpp.

378  {
379  return (characters_[i].box().left() + characters_[i].box().right()) / 2.0;
380  }
const TBOX & box(int i)
Definition: cjkpitch.cpp:366

◆ character()

FPChar* tesseract::FPRow::character ( int  i)
inline

Definition at line 362 of file cjkpitch.cpp.

362  {
363  return &characters_[i];
364  }

◆ clear_alignment()

void tesseract::FPRow::clear_alignment ( int  i)
inline

Definition at line 402 of file cjkpitch.cpp.

402  {
403  characters_[i].set_alignment(FPChar::ALIGN_UNKNOWN);
404  }

◆ DebugOutputResult()

void tesseract::FPRow::DebugOutputResult ( int  row_index)

Definition at line 686 of file cjkpitch.cpp.

686  {
687  if (num_chars() > 0) {
688  tprintf(
689  "Row %d: pitch_decision=%d, fixed_pitch=%f, max_nonspace=%d, "
690  "space_size=%f, space_threshold=%d, xheight=%f\n",
691  row_index, static_cast<int>(real_row_->pitch_decision), real_row_->fixed_pitch,
692  real_row_->max_nonspace, real_row_->space_size, real_row_->space_threshold,
693  real_row_->xheight);
694 
695  for (unsigned i = 0; i < num_chars(); i++) {
696  tprintf("Char %u: is_final=%d is_good=%d num_blobs=%d: ", i, is_final(i), is_good(i),
697  character(i)->num_blobs());
698  box(i).print();
699  }
700  }
701 }
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
int32_t max_nonspace
Definition: blobbox.h:670
float space_size
Definition: blobbox.h:673
float fixed_pitch
Definition: blobbox.h:657
int32_t space_threshold
Definition: blobbox.h:671
PITCH_TYPE pitch_decision
Definition: blobbox.h:656
void print() const
Definition: rect.h:289
bool is_good(int i)
Definition: cjkpitch.cpp:390
bool is_final(int i)
Definition: cjkpitch.cpp:382
FPChar * character(int i)
Definition: cjkpitch.cpp:362
size_t num_chars()
Definition: cjkpitch.cpp:359

◆ estimated_pitch()

float tesseract::FPRow::estimated_pitch ( )
inline

Definition at line 336 of file cjkpitch.cpp.

336  {
337  return estimated_pitch_;
338  }

◆ EstimatePitch()

void tesseract::FPRow::EstimatePitch ( bool  pass1)

Definition at line 615 of file cjkpitch.cpp.

615  {
616  good_pitches_.Clear();
617  all_pitches_.Clear();
618  good_gaps_.Clear();
619  all_gaps_.Clear();
620  heights_.Clear();
621  if (num_chars() == 0) {
622  return;
623  }
624 
625  int32_t cx0, cx1;
626  bool prev_was_good = is_good(0);
627  cx0 = center_x(0);
628 
629  heights_.Add(box(0).height());
630  for (size_t i = 1; i < num_chars(); i++) {
631  cx1 = center_x(i);
632  int32_t pitch = cx1 - cx0;
633  int32_t gap = std::max(0, real_body(i - 1).x_gap(real_body(i)));
634 
635  heights_.Add(box(i).height());
636  // Ignore if the pitch is too close. But don't ignore wide pitch
637  // may be the result of large tracking.
638  if (pitch > height_ * 0.5) {
639  all_pitches_.Add(pitch);
640  all_gaps_.Add(gap);
641  if (is_good(i)) {
642  // In pass1 (after Pass1Analyze()), all characters marked as
643  // "good" have a good consistent pitch with their previous
644  // characters. However, it's not true in pass2 and a good
645  // character may have a good pitch only between its successor.
646  // So we collect only pitch values between two good
647  // characters. and within tolerance in pass2.
648  if (pass1 ||
649  (prev_was_good && std::fabs(estimated_pitch_ - pitch) < kFPTolerance * estimated_pitch_)) {
650  good_pitches_.Add(pitch);
651  if (!is_box_modified(i - 1) && !is_box_modified(i)) {
652  good_gaps_.Add(gap);
653  }
654  }
655  prev_was_good = true;
656  } else {
657  prev_was_good = false;
658  }
659  }
660  cx0 = cx1;
661  }
662 
663  good_pitches_.Finish();
664  all_pitches_.Finish();
665  good_gaps_.Finish();
666  all_gaps_.Finish();
667  heights_.Finish();
668 
669  height_ = heights_.ile(0.875);
670  if (all_pitches_.empty()) {
671  pitch_ = 0.0f;
672  gap_ = 0.0f;
673  } else if (good_pitches_.size() < 2) {
674  // We don't have enough data to estimate the pitch of this row yet.
675  // Use median of all pitches as the initial guess.
676  pitch_ = all_pitches_.median();
677  ASSERT_HOST(pitch_ > 0.0f);
678  gap_ = all_gaps_.ile(0.125);
679  } else {
680  pitch_ = good_pitches_.median();
681  ASSERT_HOST(pitch_ > 0.0f);
682  gap_ = good_gaps_.ile(0.125);
683  }
684 }
#define ASSERT_HOST(x)
Definition: errcode.h:59
float ile(double frac)
Definition: cjkpitch.cpp:62
bool empty() const
Definition: cjkpitch.cpp:95
void Add(float value)
Definition: cjkpitch.cpp:52
bool is_box_modified(int i)
Definition: cjkpitch.cpp:374
const TBOX & real_body(int i)
Definition: cjkpitch.cpp:370
float center_x(int i)
Definition: cjkpitch.cpp:378

◆ finalize()

void tesseract::FPRow::finalize ( int  i)
inline

Definition at line 386 of file cjkpitch.cpp.

386  {
387  characters_[i].set_final(true);
388  }

◆ FinalizeLargeChars()

void tesseract::FPRow::FinalizeLargeChars ( )

Definition at line 870 of file cjkpitch.cpp.

870  {
871  float row_pitch = estimated_pitch();
872  for (size_t i = 0; i < num_chars(); i++) {
873  if (is_final(i)) {
874  continue;
875  }
876 
877  // Finalize if both neighbors are finalized. We have no other choice.
878  if (i > 0 && is_final(i - 1) && i < num_chars() - 1 && is_final(i + 1)) {
879  finalize(i);
880  continue;
881  }
882 
883  float cx = center_x(i);
884  TBOX ibody(cx - 0.5 * row_pitch, 0, cx + 0.5 * row_pitch, 1);
885  if (i > 0) {
886  // The preceding character significantly intersects with the
887  // imaginary body of this character. Let Pass2Analyze() handle
888  // this case.
889  if (x_overlap_fraction(ibody, box(i - 1)) > 0.1) {
890  continue;
891  }
892  if (!is_final(i - 1)) {
893  TBOX merged = box(i);
894  merged += box(i - 1);
895  if (merged.width() < row_pitch) {
896  continue;
897  }
898  // This character cannot be finalized yet because it can be
899  // merged with the previous one. Again, let Pass2Analyze()
900  // handle this case.
901  }
902  }
903  if (i < num_chars() - 1) {
904  if (x_overlap_fraction(ibody, box(i + 1)) > 0.1) {
905  continue;
906  }
907  if (!is_final(i + 1)) {
908  TBOX merged = box(i);
909  merged += box(i + 1);
910  if (merged.width() < row_pitch) {
911  continue;
912  }
913  }
914  }
915  finalize(i);
916  }
917 
918  // Update alignment decision. We only consider finalized characters
919  // in pass2. E.g. if a finalized character C has another finalized
920  // character L on its left and a not-finalized character R on its
921  // right, we mark C as good if the pitch between C and L is good,
922  // regardless of the pitch between C and R.
923  for (size_t i = 0; i < num_chars(); i++) {
924  if (!is_final(i)) {
925  continue;
926  }
927  bool good_pitch = false;
928  bool bad_pitch = false;
929  if (i > 0 && is_final(i - 1)) {
930  if (is_good_pitch(row_pitch, box(i - 1), box(i))) {
931  good_pitch = true;
932  } else {
933  bad_pitch = true;
934  }
935  }
936  if (i < num_chars() - 1 && is_final(i + 1)) {
937  if (is_good_pitch(row_pitch, box(i), box(i + 1))) {
938  good_pitch = true;
939  } else {
940  bad_pitch = true;
941  }
942  }
943  if (good_pitch && !bad_pitch) {
944  mark_good(i);
945  } else if (!good_pitch && bad_pitch) {
946  mark_bad(i);
947  }
948  }
949 }
@ TBOX
void mark_bad(int i)
Definition: cjkpitch.cpp:398
void mark_good(int i)
Definition: cjkpitch.cpp:394
void finalize(int i)
Definition: cjkpitch.cpp:386
float estimated_pitch()
Definition: cjkpitch.cpp:336

◆ gap()

float tesseract::FPRow::gap ( )
inline

Definition at line 355 of file cjkpitch.cpp.

355  {
356  return gap_;
357  }

◆ good_pitches()

int tesseract::FPRow::good_pitches ( )
inline

Definition at line 328 of file cjkpitch.cpp.

328  {
329  return good_pitches_.size();
330  }

◆ height()

float tesseract::FPRow::height ( )
inline

Definition at line 344 of file cjkpitch.cpp.

344  {
345  return height_;
346  }

◆ height_pitch_ratio()

float tesseract::FPRow::height_pitch_ratio ( )
inline

Definition at line 348 of file cjkpitch.cpp.

348  {
349  if (good_pitches_.size() < 2) {
350  return -1.0;
351  }
352  return height_ / good_pitches_.median();
353  }

◆ Init()

void tesseract::FPRow::Init ( TO_ROW row)

Definition at line 496 of file cjkpitch.cpp.

496  {
497  ASSERT_HOST(row != nullptr);
498  ASSERT_HOST(row->xheight > 0);
499  real_row_ = row;
500  real_row_->pitch_decision = PITCH_CORR_PROP; // Default decision.
501 
502  BLOBNBOX_IT blob_it = row->blob_list();
503  // Initialize characters_ and compute the initial estimation of
504  // character height.
505  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
506  if (is_interesting_blob(blob_it.data())) {
507  FPChar fp_char;
508  fp_char.Init(blob_it.data());
509  // Merge unconditionally if two blobs overlap.
510  if (!characters_.empty() && significant_overlap(fp_char.box(), characters_.back().box())) {
511  characters_.back().Merge(fp_char);
512  } else {
513  characters_.push_back(fp_char);
514  }
515  TBOX bound = blob_it.data()->bounding_box();
516  if (bound.height() * 3.0 > bound.width()) {
517  heights_.Add(bound.height());
518  }
519  }
520  }
521  heights_.Finish();
522  height_ = heights_.ile(0.875);
523 }
@ PITCH_CORR_PROP
Definition: blobbox.h:54

◆ is_box_modified()

bool tesseract::FPRow::is_box_modified ( int  i)
inline

Definition at line 374 of file cjkpitch.cpp.

374  {
375  return !(characters_[i].box() == characters_[i].real_body());
376  }

◆ is_final()

bool tesseract::FPRow::is_final ( int  i)
inline

Definition at line 382 of file cjkpitch.cpp.

382  {
383  return characters_[i].is_final();
384  }

◆ is_good()

bool tesseract::FPRow::is_good ( int  i)
inline

Definition at line 390 of file cjkpitch.cpp.

390  {
391  return characters_[i].alignment() == FPChar::ALIGN_GOOD;
392  }

◆ mark_bad()

void tesseract::FPRow::mark_bad ( int  i)
inline

Definition at line 398 of file cjkpitch.cpp.

398  {
399  characters_[i].set_alignment(FPChar::ALIGN_BAD);
400  }

◆ mark_good()

void tesseract::FPRow::mark_good ( int  i)
inline

Definition at line 394 of file cjkpitch.cpp.

394  {
395  characters_[i].set_alignment(FPChar::ALIGN_GOOD);
396  }

◆ MergeFragments()

void tesseract::FPRow::MergeFragments ( )

Definition at line 854 of file cjkpitch.cpp.

854  {
855  int last_char = 0;
856 
857  for (size_t j = 0; j < num_chars(); ++j) {
858  if (character(j)->merge_to_prev()) {
859  character(last_char)->Merge(*character(j));
860  character(j)->set_delete_flag(true);
861  clear_alignment(last_char);
862  character(j - 1)->set_merge_to_prev(false);
863  } else {
864  last_char = j;
865  }
866  }
867  DeleteChars();
868 }
bool merge_to_prev() const
Definition: cjkpitch.cpp:243
void Merge(const FPChar &next)
Definition: cjkpitch.cpp:206
void set_delete_flag(bool flag)
Definition: cjkpitch.cpp:253
void set_merge_to_prev(bool flag)
Definition: cjkpitch.cpp:246
void clear_alignment(int i)
Definition: cjkpitch.cpp:402

◆ num_chars()

size_t tesseract::FPRow::num_chars ( )
inline

Definition at line 359 of file cjkpitch.cpp.

359  {
360  return characters_.size();
361  }

◆ OutputEstimations()

void tesseract::FPRow::OutputEstimations ( )

Definition at line 525 of file cjkpitch.cpp.

525  {
526  if (good_pitches_.empty()) {
527  pitch_ = 0.0f;
528  real_row_->pitch_decision = PITCH_CORR_PROP;
529  return;
530  }
531 
532  pitch_ = good_pitches_.median();
533  real_row_->fixed_pitch = pitch_;
534  // good_gaps_.ile(0.125) can be large if most characters on the row
535  // are skinny. Use pitch_ - height_ instead if it's smaller, but
536  // positive.
537  real_row_->kern_size = real_row_->pr_nonsp =
538  std::min(good_gaps_.ile(0.125), std::max(pitch_ - height_, 0.0f));
539  real_row_->body_size = pitch_ - real_row_->kern_size;
540 
541  if (good_pitches_.size() < all_pitches_.size() * kFixedPitchThreshold) {
542  // If more than half of the characters of a line don't fit to the
543  // fixed pitch model, consider the line to be proportional. 50%
544  // seems to be a good threshold in practice as well.
545  // Anyway we store estimated values (fixed_pitch, kern_size, etc.) in
546  // real_row_ as a partial estimation result and try to use them in the
547  // normalization process.
548  real_row_->pitch_decision = PITCH_CORR_PROP;
549  return;
550  } else if (good_pitches_.size() > all_pitches_.size() * 0.75) {
551  real_row_->pitch_decision = PITCH_DEF_FIXED;
552  } else {
553  real_row_->pitch_decision = PITCH_CORR_FIXED;
554  }
555 
556  real_row_->space_size = real_row_->pr_space = pitch_;
557  // Set min_space to 50% of character pitch so that we can break CJK
558  // text at a half-width space after punctuation.
559  real_row_->min_space = (pitch_ + good_gaps_.minimum()) * 0.5;
560 
561  // Don't consider a quarter space as a real space, because it's used
562  // for line justification in traditional Japanese books.
563  real_row_->max_nonspace =
564  std::max(pitch_ * 0.25 + good_gaps_.minimum(), static_cast<double>(good_gaps_.ile(0.875)));
565 
566  int space_threshold = std::min((real_row_->max_nonspace + real_row_->min_space) / 2,
567  static_cast<int>(real_row_->xheight));
568 
569  // Make max_nonspace larger than any intra-character gap so that
570  // make_prop_words() won't break a row at the middle of a character.
571  for (size_t i = 0; i < num_chars(); ++i) {
572  if (characters_[i].max_gap() > real_row_->max_nonspace) {
573  real_row_->max_nonspace = characters_[i].max_gap();
574  }
575  }
576  real_row_->space_threshold = std::min((real_row_->max_nonspace + real_row_->min_space) / 2,
577  static_cast<int>(real_row_->xheight));
578  real_row_->used_dm_model = false;
579 
580  // Setup char_cells.
581  ICOORDELT_IT cell_it = &real_row_->char_cells;
582  auto *cell = new ICOORDELT(real_body(0).left(), 0);
583  cell_it.add_after_then_move(cell);
584 
585  int right = real_body(0).right();
586  for (size_t i = 1; i < num_chars(); ++i) {
587  // Put a word break if gap between two characters is bigger than
588  // space_threshold. Don't break if none of two characters
589  // couldn't be "finalized", because maybe they need to be merged
590  // to one character.
591  if ((is_final(i - 1) || is_final(i)) &&
592  real_body(i - 1).x_gap(real_body(i)) > space_threshold) {
593  cell = new ICOORDELT(right + 1, 0);
594  cell_it.add_after_then_move(cell);
595  while (right + pitch_ < box(i).left()) {
596  right += pitch_;
597  cell = new ICOORDELT(right + 1, 0);
598  cell_it.add_after_then_move(cell);
599  }
600  right = box(i).left();
601  }
602  cell = new ICOORDELT((right + real_body(i).left()) / 2, 0);
603  cell_it.add_after_then_move(cell);
604  right = real_body(i).right();
605  }
606 
607  cell = new ICOORDELT(right + 1, 0);
608  cell_it.add_after_then_move(cell);
609 
610  // TODO(takenaka): add code to store alignment/fragmentation
611  // information to blobs so that it can be reused later, e.g. in
612  // recognition phase.
613 }
@ PITCH_DEF_FIXED
Definition: blobbox.h:49
@ PITCH_CORR_FIXED
Definition: blobbox.h:53
int32_t min_space
Definition: blobbox.h:669
ICOORDELT_LIST char_cells
Definition: blobbox.h:675
bool used_dm_model
Definition: blobbox.h:653
TDimension left() const
Definition: rect.h:82
int x_gap(const TBOX &box) const
Definition: rect.h:238
TDimension right() const
Definition: rect.h:89

◆ Pass1Analyze()

void tesseract::FPRow::Pass1Analyze ( )

Definition at line 703 of file cjkpitch.cpp.

703  {
704  if (num_chars() < 2) {
705  return;
706  }
707 
708  if (estimated_pitch_ > 0.0f) {
709  for (size_t i = 2; i < num_chars(); i++) {
710  if (is_good_pitch(estimated_pitch_, box(i - 2), box(i - 1)) &&
711  is_good_pitch(estimated_pitch_, box(i - 1), box(i))) {
712  mark_good(i - 1);
713  }
714  }
715  } else {
716  for (size_t i = 2; i < num_chars(); i++) {
717  if (is_good_pitch(box_pitch(box(i - 2), box(i - 1)), box(i - 1), box(i))) {
718  mark_good(i - 1);
719  }
720  }
721  }
722  character(0)->set_alignment(character(1)->alignment());
723  character(num_chars() - 1)->set_alignment(character(num_chars() - 2)->alignment());
724 }
void set_alignment(Alignment alignment)
Definition: cjkpitch.cpp:239

◆ Pass2Analyze()

bool tesseract::FPRow::Pass2Analyze ( )

Definition at line 726 of file cjkpitch.cpp.

726  {
727  bool changed = false;
728  if (num_chars() <= 1 || estimated_pitch_ == 0.0f) {
729  return false;
730  }
731  for (size_t i = 0; i < num_chars(); i++) {
732  if (is_final(i)) {
733  continue;
734  }
735 
736  FPChar::Alignment alignment = character(i)->alignment();
737  bool intersecting = false;
738  bool not_intersecting = false;
739 
740  if (i < num_chars() - 1 && is_final(i + 1)) {
741  // Next character is already finalized. Estimate the imaginary
742  // body including this character based on the character. Skip
743  // whitespace if necessary.
744  bool skipped_whitespaces = false;
745  float c1 = center_x(i + 1) - 1.5 * estimated_pitch_;
746  while (c1 > box(i).right()) {
747  skipped_whitespaces = true;
748  c1 -= estimated_pitch_;
749  }
750  TBOX ibody(c1, box(i).bottom(), c1 + estimated_pitch_, box(i).top());
751 
752  // Collect all characters that mostly fit in the region.
753  // Also, their union height shouldn't be too big.
754  int j = i;
755  TBOX merged;
756  while (j >= 0 && !is_final(j) && mostly_overlap(ibody, box(j)) &&
757  merged.bounding_union(box(j)).height() < estimated_pitch_ * (1 + kFPTolerance)) {
758  merged += box(j);
759  j--;
760  }
761 
762  if (j >= 0 && significant_overlap(ibody, box(j))) {
763  // character(j) lies on the character boundary and doesn't fit
764  // well into the imaginary body.
765  if (!is_final(j)) {
766  intersecting = true;
767  }
768  } else {
769  not_intersecting = true;
770  if (i - j > 0) {
771  // Merge character(j+1) ... character(i) because they fit
772  // into the body nicely.
773  if (i - j == 1) {
774  // Only one char in the imaginary body.
775  if (!skipped_whitespaces) {
776  mark_good(i);
777  }
778  // set ibody as bounding box of this character to get
779  // better pitch analysis result for halfwidth glyphs
780  // followed by a halfwidth space.
781  if (box(i).width() <= estimated_pitch_ * 0.5) {
782  ibody += box(i);
783  character(i)->set_box(ibody);
784  }
785  character(i)->set_merge_to_prev(false);
786  finalize(i);
787  } else {
788  for (int k = i; k > j + 1; k--) {
789  character(k)->set_merge_to_prev(true);
790  }
791  }
792  }
793  }
794  }
795  if (i > 0 && is_final(i - 1)) {
796  // Now we repeat everything from the opposite side. Previous
797  // character is already finalized. Estimate the imaginary body
798  // including this character based on the character.
799  bool skipped_whitespaces = false;
800  float c1 = center_x(i - 1) + 1.5 * estimated_pitch_;
801  while (c1 < box(i).left()) {
802  skipped_whitespaces = true;
803  c1 += estimated_pitch_;
804  }
805  TBOX ibody(c1 - estimated_pitch_, box(i).bottom(), c1, box(i).top());
806 
807  size_t j = i;
808  TBOX merged;
809  while (j < num_chars() && !is_final(j) && mostly_overlap(ibody, box(j)) &&
810  merged.bounding_union(box(j)).height() < estimated_pitch_ * (1 + kFPTolerance)) {
811  merged += box(j);
812  j++;
813  }
814 
815  if (j < num_chars() && significant_overlap(ibody, box(j))) {
816  if (!is_final(j)) {
817  intersecting = true;
818  }
819  } else {
820  not_intersecting = true;
821  if (j - i > 0) {
822  if (j - i == 1) {
823  if (!skipped_whitespaces) {
824  mark_good(i);
825  }
826  if (box(i).width() <= estimated_pitch_ * 0.5) {
827  ibody += box(i);
828  character(i)->set_box(ibody);
829  }
830  character(i)->set_merge_to_prev(false);
831  finalize(i);
832  } else {
833  for (size_t k = i + 1; k < j; k++) {
834  character(k)->set_merge_to_prev(true);
835  }
836  }
837  }
838  }
839  }
840 
841  // This character doesn't fit well into the estimated imaginary
842  // bodies. Mark it as bad.
843  if (intersecting && !not_intersecting) {
844  mark_bad(i);
845  }
846  if (character(i)->alignment() != alignment || character(i)->merge_to_prev()) {
847  changed = true;
848  }
849  }
850 
851  return changed;
852 }
const Alignment & alignment() const
Definition: cjkpitch.cpp:236
void set_box(const TBOX &box)
Definition: cjkpitch.cpp:222

◆ pitch()

float tesseract::FPRow::pitch ( )
inline

Definition at line 332 of file cjkpitch.cpp.

332  {
333  return pitch_;
334  }

◆ real_body()

const TBOX& tesseract::FPRow::real_body ( int  i)
inline

Definition at line 370 of file cjkpitch.cpp.

370  {
371  return characters_[i].real_body();
372  }

◆ set_estimated_pitch()

void tesseract::FPRow::set_estimated_pitch ( float  v)
inline

Definition at line 340 of file cjkpitch.cpp.

340  {
341  estimated_pitch_ = v;
342  }

The documentation for this class was generated from the following file: