tesseract  5.0.0
pgedit.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: pgedit.cpp (Formerly pgeditor.c)
3  * Description: Page structure file editor
4  * Author: Phil Cheatle
5  *
6  *(C) Copyright 1991, Hewlett-Packard Ltd.
7  ** Licensed under the Apache License, Version 2.0(the "License");
8  ** you may not use this file except in compliance with the License.
9  ** You may obtain a copy of the License at
10  ** http:// www.apache.org/licenses/LICENSE-2.0
11  ** Unless required by applicable law or agreed to in writing, software
12  ** distributed under the License is distributed on an "AS IS" BASIS,
13  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  ** See the License for the specific language governing permissions and
15  ** limitations under the License.
16  *
17  **********************************************************************/
18 
19 // Include automatically generated configuration file if running autoconf.
20 #ifdef HAVE_CONFIG_H
21 # include "config_auto.h"
22 #endif
23 
24 #include "pgedit.h"
25 
26 #include "blread.h"
27 #include "control.h"
28 #include "pageres.h"
29 #include "paramsd.h"
30 #include "scrollview.h"
31 #include "statistc.h"
32 #include "svmnode.h"
33 #include "tesseractclass.h"
34 #include "tordmain.h"
35 #include "werdit.h"
36 
37 #include <cctype>
38 #include <cmath>
39 
40 #ifndef GRAPHICS_DISABLED
41 namespace tesseract {
42 # define ASC_HEIGHT (2 * kBlnBaselineOffset + kBlnXHeight)
43 # define X_HEIGHT (kBlnBaselineOffset + kBlnXHeight)
44 # define BL_HEIGHT kBlnBaselineOffset
45 # define DESC_HEIGHT 0
46 
47 enum CMD_EVENTS {
78 };
79 
91 };
92 
93 /*
94  *
95  * Some global data
96  *
97  */
98 
99 static ScrollView *image_win;
100 static ParamsEditor *pe;
101 static bool stillRunning = false;
102 
103 static ScrollView *bln_word_window = nullptr; // baseline norm words
104 
105 static CMD_EVENTS mode = CHANGE_DISP_CMD_EVENT; // selected words op
106 
107 static bool recog_done = false; // recog_all_words was called
108 
109 // These variables should remain global, since they are only used for the
110 // debug mode (in which only a single Tesseract thread/instance will exist).
111 static std::bitset<16> word_display_mode;
112 static ColorationMode color_mode = CM_RAINBOW;
113 static bool display_image = false;
114 static bool display_blocks = false;
115 static bool display_baselines = false;
116 
117 static PAGE_RES *current_page_res = nullptr;
118 
119 STRING_VAR(editor_image_win_name, "EditorImage", "Editor image window name");
120 INT_VAR(editor_image_xpos, 590, "Editor image X Pos");
121 INT_VAR(editor_image_ypos, 10, "Editor image Y Pos");
122 static INT_VAR(editor_image_menuheight, 50, "Add to image height for menu bar");
125 
126 STRING_VAR(editor_word_name, "BlnWords", "BL normalized word window");
127 INT_VAR(editor_word_xpos, 60, "Word window X Pos");
128 INT_VAR(editor_word_ypos, 510, "Word window Y Pos");
129 INT_VAR(editor_word_height, 240, "Word window height");
130 INT_VAR(editor_word_width, 655, "Word window width");
131 
139 static void show_point(PAGE_RES *page_res, float x, float y) {
140  FCOORD pt(x, y);
141  PAGE_RES_IT pr_it(page_res);
142 
143  const int kBufsize = 512;
144  char msg[kBufsize];
145  char *msg_ptr = msg;
146 
147  msg_ptr += sprintf(msg_ptr, "Pt:(%0.3f, %0.3f) ", x, y);
148 
149  for (WERD_RES *word = pr_it.word(); word != nullptr; word = pr_it.forward()) {
150  if (pr_it.row() != pr_it.prev_row() && pr_it.row()->row->bounding_box().contains(pt)) {
151  msg_ptr += sprintf(msg_ptr, "BL(x)=%0.3f ", pr_it.row()->row->base_line(x));
152  }
153  if (word->word->bounding_box().contains(pt)) {
154  TBOX box = word->word->bounding_box();
155  msg_ptr += sprintf(msg_ptr, "Wd(%d, %d)/(%d, %d) ", box.left(), box.bottom(), box.right(),
156  box.top());
157  C_BLOB_IT cblob_it(word->word->cblob_list());
158  for (cblob_it.mark_cycle_pt(); !cblob_it.cycled_list(); cblob_it.forward()) {
159  C_BLOB *cblob = cblob_it.data();
160  box = cblob->bounding_box();
161  if (box.contains(pt)) {
162  msg_ptr += sprintf(msg_ptr, "CBlb(%d, %d)/(%d, %d) ", box.left(), box.bottom(),
163  box.right(), box.top());
164  }
165  }
166  }
167  }
168  image_win->AddMessage(msg);
169 }
170 
177 static void pgeditor_msg( // message display
178  const char *msg) {
179  image_win->AddMessage(msg);
180 }
181 
183 public:
184  void Notify(const SVEvent *sv_event) override {
185  if (sv_event->type == SVET_DESTROY) {
186  bln_word_window = nullptr;
187  } else if (sv_event->type == SVET_CLICK) {
188  show_point(current_page_res, sv_event->x, sv_event->y);
189  }
190  }
191 };
192 
198 static ScrollView *bln_word_window_handle() { // return handle
199  // not opened yet
200  if (bln_word_window == nullptr) {
201  pgeditor_msg("Creating BLN word window...");
202  bln_word_window = new ScrollView(editor_word_name.c_str(), editor_word_xpos, editor_word_ypos,
203  editor_word_width, editor_word_height, 4000, 4000, true);
204  auto *a = new BlnEventHandler();
205  bln_word_window->AddEventHandler(a);
206  pgeditor_msg("Creating BLN word window...Done");
207  }
208  return bln_word_window;
209 }
210 
218 static void build_image_window(int width, int height) {
219  delete image_win;
220  image_win = new ScrollView(editor_image_win_name.c_str(), editor_image_xpos, editor_image_ypos,
221  width + 1, height + editor_image_menuheight + 1, width, height, true);
222 }
223 
230 static void display_bln_lines(ScrollView *window, ScrollView::Color colour, float scale_factor,
231  float y_offset, float minx, float maxx) {
232  window->Pen(colour);
233  window->Line(minx, y_offset + scale_factor * DESC_HEIGHT, maxx,
234  y_offset + scale_factor * DESC_HEIGHT);
235  window->Line(minx, y_offset + scale_factor * BL_HEIGHT, maxx,
236  y_offset + scale_factor * BL_HEIGHT);
237  window->Line(minx, y_offset + scale_factor * X_HEIGHT, maxx, y_offset + scale_factor * X_HEIGHT);
238  window->Line(minx, y_offset + scale_factor * ASC_HEIGHT, maxx,
239  y_offset + scale_factor * ASC_HEIGHT);
240 }
241 
250 void PGEventHandler::Notify(const SVEvent *event) {
251  char myval = '0';
252  if (event->type == SVET_POPUP) {
253  pe->Notify(event);
254  } // These are handled by ParamsEditor
255  else if (event->type == SVET_EXIT) {
256  stillRunning = false;
257  } else if (event->type == SVET_MENU) {
258  if (strcmp(event->parameter, "true") == 0) {
259  myval = 'T';
260  } else if (strcmp(event->parameter, "false") == 0) {
261  myval = 'F';
262  }
263  tess_->process_cmd_win_event(event->command_id, &myval);
264  } else {
265  tess_->process_image_event(*event);
266  }
267 }
268 
275  SVMenuNode *parent_menu;
276  auto *root_menu_item = new SVMenuNode();
277 
278  SVMenuNode *modes_menu_item = root_menu_item->AddChild("MODES");
279 
280  modes_menu_item->AddChild("Change Display", CHANGE_DISP_CMD_EVENT);
281  modes_menu_item->AddChild("Dump Word", DUMP_WERD_CMD_EVENT);
282  modes_menu_item->AddChild("Show Point", SHOW_POINT_CMD_EVENT);
283  modes_menu_item->AddChild("Show BL Norm Word", SHOW_BLN_WERD_CMD_EVENT);
284  modes_menu_item->AddChild("Config Words", DEBUG_WERD_CMD_EVENT);
285  modes_menu_item->AddChild("Recog Words", RECOG_WERDS);
286  modes_menu_item->AddChild("Recog Blobs", RECOG_PSEUDO);
287  modes_menu_item->AddChild("Show Blob Features", SHOW_BLOB_FEATURES);
288 
289  parent_menu = root_menu_item->AddChild("DISPLAY");
290 
291  parent_menu->AddChild("Blamer", BLAMER_CMD_EVENT, false);
292  parent_menu->AddChild("Bounding Boxes", BOUNDING_BOX_CMD_EVENT, false);
293  parent_menu->AddChild("Correct Text", CORRECT_TEXT_CMD_EVENT, false);
294  parent_menu->AddChild("Polygonal Approx", POLYGONAL_CMD_EVENT, false);
295  parent_menu->AddChild("Baseline Normalized", BL_NORM_CMD_EVENT, false);
296  parent_menu->AddChild("Edge Steps", BITMAP_CMD_EVENT, true);
297  parent_menu->AddChild("Subscripts", SHOW_SUBSCRIPT_CMD_EVENT);
298  parent_menu->AddChild("Superscripts", SHOW_SUPERSCRIPT_CMD_EVENT);
299  parent_menu->AddChild("Italics", SHOW_ITALIC_CMD_EVENT);
300  parent_menu->AddChild("Bold", SHOW_BOLD_CMD_EVENT);
301  parent_menu->AddChild("Underline", SHOW_UNDERLINE_CMD_EVENT);
302  parent_menu->AddChild("FixedPitch", SHOW_FIXEDPITCH_CMD_EVENT);
303  parent_menu->AddChild("Serifs", SHOW_SERIF_CMD_EVENT);
304  parent_menu->AddChild("SmallCaps", SHOW_SMALLCAPS_CMD_EVENT);
305  parent_menu->AddChild("DropCaps", SHOW_DROPCAPS_CMD_EVENT);
306 
307  parent_menu = root_menu_item->AddChild("OTHER");
308 
309  parent_menu->AddChild("Quit", QUIT_CMD_EVENT);
310  parent_menu->AddChild("Show Image", IMAGE_CMD_EVENT, false);
311  parent_menu->AddChild("ShowBlock Outlines", BLOCKS_CMD_EVENT, false);
312  parent_menu->AddChild("Show Baselines", BASELINES_CMD_EVENT, false);
313  parent_menu->AddChild("Uniform Display", UNIFORM_DISP_CMD_EVENT);
314  parent_menu->AddChild("Refresh Display", REFRESH_CMD_EVENT);
315 
316  return root_menu_item;
317 }
318 
324 void Tesseract::do_re_display(bool (tesseract::Tesseract::*word_painter)(PAGE_RES_IT *pr_it)) {
325  int block_count = 1;
326 
327  image_win->Clear();
328  if (display_image) {
329  image_win->Draw(pix_binary_, 0, 0);
330  }
331 
332  image_win->Brush(ScrollView::NONE);
333  PAGE_RES_IT pr_it(current_page_res);
334  for (WERD_RES *word = pr_it.word(); word != nullptr; word = pr_it.forward()) {
335  (this->*word_painter)(&pr_it);
336  if (display_baselines && pr_it.row() != pr_it.prev_row()) {
337  pr_it.row()->row->plot_baseline(image_win, ScrollView::GREEN);
338  }
339  if (display_blocks && pr_it.block() != pr_it.prev_block()) {
340  pr_it.block()->block->pdblk.plot(image_win, block_count++, ScrollView::RED);
341  }
342  }
343  image_win->Update();
344 }
345 
354 void Tesseract::pgeditor_main(int width, int height, PAGE_RES *page_res) {
355  current_page_res = page_res;
356  if (current_page_res->block_res_list.empty()) {
357  return;
358  }
359 
360  recog_done = false;
361  stillRunning = true;
362 
363  build_image_window(width, height);
364  word_display_mode.set(DF_EDGE_STEP);
366 # ifndef GRAPHICS_DISABLED
367  pe = new ParamsEditor(this, image_win);
368 # endif
369  PGEventHandler pgEventHandler(this);
370 
371  image_win->AddEventHandler(&pgEventHandler);
372  image_win->AddMessageBox();
373 
374  SVMenuNode *svMenuRoot = build_menu_new();
375 
376  svMenuRoot->BuildMenu(image_win);
377  image_win->SetVisible(true);
378 
379  image_win->AwaitEvent(SVET_DESTROY);
380  image_win->AddEventHandler(nullptr);
381 }
382 
390 bool Tesseract::process_cmd_win_event( // UI command semantics
391  int32_t cmd_event, // which menu item?
392  char *new_value // any prompt data
393 ) {
394  char msg[160];
395  bool exit = false;
396 
397  color_mode = CM_RAINBOW;
398 
399  // Run recognition on the full page if needed.
400  switch (cmd_event) {
401  case BLAMER_CMD_EVENT:
405  case SHOW_BOLD_CMD_EVENT:
411  if (!recog_done) {
412  recog_all_words(current_page_res, nullptr, nullptr, nullptr, 0);
413  recog_done = true;
414  }
415  break;
416  default:
417  break;
418  }
419 
420  char *parameter;
421 
422  switch (cmd_event) {
423  case NULL_CMD_EVENT:
424  break;
425 
427  case DUMP_WERD_CMD_EVENT:
430  case RECOG_WERDS:
431  case RECOG_PSEUDO:
432  case SHOW_BLOB_FEATURES:
433  mode = static_cast<CMD_EVENTS>(cmd_event);
434  break;
436  mode = DEBUG_WERD_CMD_EVENT;
437  parameter = image_win->ShowInputDialog("Config File Name");
438  word_config_ = parameter;
439  delete[] parameter;
440  break;
442  if (new_value[0] == 'T') {
443  word_display_mode.set(DF_BOX);
444  } else {
445  word_display_mode.reset(DF_BOX);
446  }
447  mode = CHANGE_DISP_CMD_EVENT;
448  break;
449  case BLAMER_CMD_EVENT:
450  if (new_value[0] == 'T') {
451  word_display_mode.set(DF_BLAMER);
452  } else {
453  word_display_mode.reset(DF_BLAMER);
454  }
456  mode = CHANGE_DISP_CMD_EVENT;
457  break;
459  if (new_value[0] == 'T') {
460  word_display_mode.set(DF_TEXT);
461  } else {
462  word_display_mode.reset(DF_TEXT);
463  }
464  mode = CHANGE_DISP_CMD_EVENT;
465  break;
466  case POLYGONAL_CMD_EVENT:
467  if (new_value[0] == 'T') {
468  word_display_mode.set(DF_POLYGONAL);
469  } else {
470  word_display_mode.reset(DF_POLYGONAL);
471  }
472  mode = CHANGE_DISP_CMD_EVENT;
473  break;
474  case BL_NORM_CMD_EVENT:
475  if (new_value[0] == 'T') {
476  word_display_mode.set(DF_BN_POLYGONAL);
477  } else {
478  word_display_mode.reset(DF_BN_POLYGONAL);
479  }
480  mode = CHANGE_DISP_CMD_EVENT;
481  break;
482  case BITMAP_CMD_EVENT:
483  if (new_value[0] == 'T') {
484  word_display_mode.set(DF_EDGE_STEP);
485  } else {
486  word_display_mode.reset(DF_EDGE_STEP);
487  }
488  mode = CHANGE_DISP_CMD_EVENT;
489  break;
492  break;
493  case IMAGE_CMD_EVENT:
494  display_image = (new_value[0] == 'T');
496  break;
497  case BLOCKS_CMD_EVENT:
498  display_blocks = (new_value[0] == 'T');
500  break;
501  case BASELINES_CMD_EVENT:
502  display_baselines = (new_value[0] == 'T');
504  break;
506  color_mode = CM_SUBSCRIPT;
508  break;
510  color_mode = CM_SUPERSCRIPT;
512  break;
514  color_mode = CM_ITALIC;
516  break;
517  case SHOW_BOLD_CMD_EVENT:
518  color_mode = CM_BOLD;
520  break;
522  color_mode = CM_UNDERLINE;
524  break;
526  color_mode = CM_FIXEDPITCH;
528  break;
530  color_mode = CM_SERIF;
532  break;
534  color_mode = CM_SMALLCAPS;
536  break;
538  color_mode = CM_DROPCAPS;
540  break;
541  case REFRESH_CMD_EVENT:
543  break;
544  case QUIT_CMD_EVENT:
545  exit = true;
547  break;
548 
549  default:
550  snprintf(msg, sizeof(msg), "Unrecognised event %" PRId32 "(%s)", cmd_event, new_value);
551  image_win->AddMessage(msg);
552  break;
553  }
554  return exit;
555 }
556 
566 void Tesseract::process_image_event( // action in image win
567  const SVEvent &event) {
568  // The following variable should remain static, since it is used by
569  // debug editor, which uses a single Tesseract instance.
570  static ICOORD down;
571  ICOORD up;
572  TBOX selection_box;
573  char msg[80];
574 
575  switch (event.type) {
576  case SVET_SELECTION:
577  if (event.type == SVET_SELECTION) {
578  down.set_x(event.x + event.x_size);
579  down.set_y(event.y + event.y_size);
580  if (mode == SHOW_POINT_CMD_EVENT) {
581  show_point(current_page_res, event.x, event.y);
582  }
583  }
584 
585  up.set_x(event.x);
586  up.set_y(event.y);
587 
588  selection_box = TBOX(down, up);
589 
590  switch (mode) {
592  process_selected_words(current_page_res, selection_box,
594  break;
595  case DUMP_WERD_CMD_EVENT:
596  process_selected_words(current_page_res, selection_box,
598  break;
600  process_selected_words(current_page_res, selection_box,
602  break;
604  debug_word(current_page_res, selection_box);
605  break;
607  break; // ignore up event
608 
609  case RECOG_WERDS:
610 # ifndef DISABLED_LEGACY_ENGINE
611  image_win->AddMessage("Recogging selected words");
612  this->process_selected_words(current_page_res, selection_box,
614 # endif // ndef DISABLED_LEGACY_ENGINE
615  break;
616  case RECOG_PSEUDO:
617  image_win->AddMessage("Recogging selected blobs");
618  recog_pseudo_word(current_page_res, selection_box);
619  break;
620  case SHOW_BLOB_FEATURES:
621  blob_feature_display(current_page_res, selection_box);
622  break;
623 
624  default:
625  sprintf(msg, "Mode %d not yet implemented", mode);
626  image_win->AddMessage(msg);
627  break;
628  }
629  default:
630  break;
631  }
632 }
633 
639 void Tesseract::debug_word(PAGE_RES *page_res, const TBOX &selection_box) {
640 # ifndef DISABLED_LEGACY_ENGINE
642 # endif
643  recog_all_words(page_res, nullptr, &selection_box, word_config_.c_str(), 0);
644 }
645 
646 /**********************************************************************
647  * WERD PROCESSOR FUNCTIONS
648  * ========================
649  *
650  * These routines are invoked by one or more of:
651  * process_all_words()
652  * process_selected_words()
653  * or
654  * process_all_words_it()
655  * process_selected_words_it()
656  * for each word to be processed
657  **********************************************************************/
658 
667  pr_it->word()->word->bounding_box().plot(image_win, ScrollView::BLACK, ScrollView::BLACK);
668  return word_set_display(pr_it);
669 }
670 
677  WERD_RES *word_res = pr_it->word();
678  if (word_res->chopped_word == nullptr) {
679  // Setup word normalization parameters.
680  word_res->SetupForRecognition(unicharset, this, BestPix(), tessedit_ocr_engine_mode, nullptr,
681  classify_bln_numeric_mode, textord_use_cjk_fp_model,
682  poly_allow_detailed_fx, pr_it->row()->row, pr_it->block()->block);
683  }
684  bln_word_window_handle()->Clear();
685  display_bln_lines(bln_word_window_handle(), ScrollView::CYAN, 1.0, 0.0f, -1000.0f, 1000.0f);
686  C_BLOB_IT it(word_res->word->cblob_list());
688  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
689  it.data()->plot_normed(word_res->denorm, color, ScrollView::BROWN, bln_word_window_handle());
690  color = WERD::NextColor(color);
691  }
692  bln_word_window_handle()->Update();
693  return true;
694 }
695 
702  WERD_RES *word_res = pr_it->word();
703  WERD *word = word_res->word;
704  TBOX word_bb; // word bounding box
705  int word_height; // ht of word BB
706  bool displayed_something = false;
707  float shift; // from bot left
708 
709  if (color_mode != CM_RAINBOW && word_res->box_word != nullptr) {
710 # ifndef DISABLED_LEGACY_ENGINE
711  BoxWord *box_word = word_res->box_word;
712  WERD_CHOICE *best_choice = word_res->best_choice;
713  int length = box_word->length();
714  if (word_res->fontinfo == nullptr) {
715  return false;
716  }
717  const FontInfo &font_info = *word_res->fontinfo;
718  for (int i = 0; i < length; ++i) {
720  switch (color_mode) {
721  case CM_SUBSCRIPT:
722  if (best_choice->BlobPosition(i) == SP_SUBSCRIPT) {
723  color = ScrollView::RED;
724  }
725  break;
726  case CM_SUPERSCRIPT:
727  if (best_choice->BlobPosition(i) == SP_SUPERSCRIPT) {
728  color = ScrollView::RED;
729  }
730  break;
731  case CM_ITALIC:
732  if (font_info.is_italic()) {
733  color = ScrollView::RED;
734  }
735  break;
736  case CM_BOLD:
737  if (font_info.is_bold()) {
738  color = ScrollView::RED;
739  }
740  break;
741  case CM_FIXEDPITCH:
742  if (font_info.is_fixed_pitch()) {
743  color = ScrollView::RED;
744  }
745  break;
746  case CM_SERIF:
747  if (font_info.is_serif()) {
748  color = ScrollView::RED;
749  }
750  break;
751  case CM_SMALLCAPS:
752  if (word_res->small_caps) {
753  color = ScrollView::RED;
754  }
755  break;
756  case CM_DROPCAPS:
757  if (best_choice->BlobPosition(i) == SP_DROPCAP) {
758  color = ScrollView::RED;
759  }
760  break;
761  // TODO(rays) underline is currently completely unsupported.
762  case CM_UNDERLINE:
763  default:
764  break;
765  }
766  image_win->Pen(color);
767  TBOX box = box_word->BlobBox(i);
768  image_win->Rectangle(box.left(), box.bottom(), box.right(), box.top());
769  }
770  return true;
771 # else
772  return false;
773 # endif // ndef DISABLED_LEGACY_ENGINE
774  }
775  /*
776  Note the double coercions of(COLOUR)((int32_t)editor_image_word_bb_color)
777  etc. are to keep the compiler happy.
778 */
779  // display bounding box
780  if (word->display_flag(DF_BOX)) {
781  word->bounding_box().plot(image_win,
782  static_cast<ScrollView::Color>((int32_t)editor_image_word_bb_color),
783  static_cast<ScrollView::Color>((int32_t)editor_image_word_bb_color));
784 
785  auto c = static_cast<ScrollView::Color>((int32_t)editor_image_blob_bb_color);
786  image_win->Pen(c);
787  // cblob iterator
788  C_BLOB_IT c_it(word->cblob_list());
789  for (c_it.mark_cycle_pt(); !c_it.cycled_list(); c_it.forward()) {
790  c_it.data()->bounding_box().plot(image_win);
791  }
792  displayed_something = true;
793  }
794 
795  // display edge steps
796  if (word->display_flag(DF_EDGE_STEP)) { // edgesteps available
797  word->plot(image_win); // rainbow colors
798  displayed_something = true;
799  }
800 
801  // display poly approx
802  if (word->display_flag(DF_POLYGONAL)) {
803  // need to convert
804  TWERD *tword = TWERD::PolygonalCopy(poly_allow_detailed_fx, word);
805  tword->plot(image_win);
806  delete tword;
807  displayed_something = true;
808  }
809 
810  // Display correct text and blamer information.
811  std::string text;
812  std::string blame;
813  if (word->display_flag(DF_TEXT) && word->text() != nullptr) {
814  text = word->text();
815  }
816  if (word->display_flag(DF_BLAMER) &&
817  !(word_res->blamer_bundle != nullptr &&
819  text = "";
820  const BlamerBundle *blamer_bundle = word_res->blamer_bundle;
821  if (blamer_bundle == nullptr) {
822  text += "NULL";
823  } else {
824  text = blamer_bundle->TruthString();
825  }
826  text += " -> ";
827  std::string best_choice_str;
828  if (word_res->best_choice == nullptr) {
829  best_choice_str = "NULL";
830  } else {
831  word_res->best_choice->string_and_lengths(&best_choice_str, nullptr);
832  }
833  text += best_choice_str;
834  IncorrectResultReason reason =
835  (blamer_bundle == nullptr) ? IRR_PAGE_LAYOUT : blamer_bundle->incorrect_result_reason();
836  ASSERT_HOST(reason < IRR_NUM_REASONS);
837  blame += " [";
838  blame += BlamerBundle::IncorrectReasonName(reason);
839  blame += "]";
840  }
841  if (text.length() > 0) {
842  word_bb = word->bounding_box();
843  image_win->Pen(ScrollView::RED);
844  word_height = word_bb.height();
845  int text_height = 0.50 * word_height;
846  if (text_height > 20) {
847  text_height = 20;
848  }
849  image_win->TextAttributes("Arial", text_height, false, false, false);
850  shift = (word_height < word_bb.width()) ? 0.25 * word_height : 0.0f;
851  image_win->Text(word_bb.left() + shift, word_bb.bottom() + 0.25 * word_height, text.c_str());
852  if (blame.length() > 0) {
853  image_win->Text(word_bb.left() + shift, word_bb.bottom() + 0.25 * word_height - text_height,
854  blame.c_str());
855  }
856 
857  displayed_something = true;
858  }
859 
860  if (!displayed_something) { // display BBox anyway
861  word->bounding_box().plot(image_win,
862  static_cast<ScrollView::Color>((int32_t)editor_image_word_bb_color),
863  static_cast<ScrollView::Color>((int32_t)editor_image_word_bb_color));
864  }
865  return true;
866 }
867 } // namespace tesseract
868 #endif // !GRAPHICS_DISABLED
869 
870 namespace tesseract {
877  if (pr_it->block()->block != nullptr) {
878  tprintf("\nBlock data...\n");
879  pr_it->block()->block->print(nullptr, false);
880  }
881  tprintf("\nRow data...\n");
882  pr_it->row()->row->print(nullptr);
883  tprintf("\nWord data...\n");
884  WERD_RES *word_res = pr_it->word();
885  word_res->word->print();
886  if (word_res->blamer_bundle != nullptr && wordrec_debug_blamer &&
888  tprintf("Current blamer debug: %s\n", word_res->blamer_bundle->debug().c_str());
889  }
890  return true;
891 }
892 
893 #ifndef GRAPHICS_DISABLED
900  WERD *word = pr_it->word()->word;
901  word->set_display_flag(DF_BOX, word_display_mode[DF_BOX]);
902  word->set_display_flag(DF_TEXT, word_display_mode[DF_TEXT]);
903  word->set_display_flag(DF_POLYGONAL, word_display_mode[DF_POLYGONAL]);
904  word->set_display_flag(DF_EDGE_STEP, word_display_mode[DF_EDGE_STEP]);
905  word->set_display_flag(DF_BN_POLYGONAL, word_display_mode[DF_BN_POLYGONAL]);
906  word->set_display_flag(DF_BLAMER, word_display_mode[DF_BLAMER]);
907  return word_display(pr_it);
908 }
909 
910 // page_res is non-const because the iterator doesn't know if you are going
911 // to change the items it points to! Really a const here though.
912 void Tesseract::blob_feature_display(PAGE_RES *page_res, const TBOX &selection_box) {
913 # ifndef DISABLED_LEGACY_ENGINE
914  PAGE_RES_IT *it = make_pseudo_word(page_res, selection_box);
915  if (it != nullptr) {
916  WERD_RES *word_res = it->word();
917  word_res->x_height = it->row()->row->x_height();
918  word_res->SetupForRecognition(unicharset, this, BestPix(), tessedit_ocr_engine_mode, nullptr,
919  classify_bln_numeric_mode, textord_use_cjk_fp_model,
920  poly_allow_detailed_fx, it->row()->row, it->block()->block);
921  TWERD *bln_word = word_res->chopped_word;
922  TBLOB *bln_blob = bln_word->blobs[0];
923  INT_FX_RESULT_STRUCT fx_info;
924  std::vector<INT_FEATURE_STRUCT> bl_features;
925  std::vector<INT_FEATURE_STRUCT> cn_features;
926  Classify::ExtractFeatures(*bln_blob, classify_nonlinear_norm, &bl_features, &cn_features,
927  &fx_info, nullptr);
928  // Display baseline features.
929  ScrollView *bl_win = CreateFeatureSpaceWindow("BL Features", 512, 0);
931  for (auto &bl_feature : bl_features) {
932  RenderIntFeature(bl_win, &bl_feature, ScrollView::GREEN);
933  }
934  bl_win->Update();
935  // Display cn features.
936  ScrollView *cn_win = CreateFeatureSpaceWindow("CN Features", 512, 0);
938  for (auto &cn_feature : cn_features) {
939  RenderIntFeature(cn_win, &cn_feature, ScrollView::GREEN);
940  }
941  cn_win->Update();
942 
943  it->DeleteCurrentWord();
944  delete it;
945  }
946 # endif // ndef DISABLED_LEGACY_ENGINE
947 }
948 
949 #endif // !GRAPHICS_DISABLED
950 
951 } // namespace tesseract
#define DESC_HEIGHT
Definition: pgedit.cpp:45
#define ASC_HEIGHT
Definition: pgedit.cpp:42
#define BL_HEIGHT
Definition: pgedit.cpp:44
#define X_HEIGHT
Definition: pgedit.cpp:43
#define ASSERT_HOST(x)
Definition: errcode.h:59
#define INT_VAR(name, val, comment)
Definition: params.h:356
#define STRING_VAR(name, val, comment)
Definition: params.h:362
@ TBOX
@ SHOW_SUBSCRIPT_CMD_EVENT
Definition: pgedit.cpp:69
@ DEBUG_WERD_CMD_EVENT
Definition: pgedit.cpp:53
@ SHOW_UNDERLINE_CMD_EVENT
Definition: pgedit.cpp:73
@ SHOW_SERIF_CMD_EVENT
Definition: pgedit.cpp:75
@ BASELINES_CMD_EVENT
Definition: pgedit.cpp:62
@ SHOW_BOLD_CMD_EVENT
Definition: pgedit.cpp:72
@ BLAMER_CMD_EVENT
Definition: pgedit.cpp:54
@ SHOW_BLN_WERD_CMD_EVENT
Definition: pgedit.cpp:52
@ RECOG_PSEUDO
Definition: pgedit.cpp:67
@ SHOW_SUPERSCRIPT_CMD_EVENT
Definition: pgedit.cpp:70
@ BL_NORM_CMD_EVENT
Definition: pgedit.cpp:58
@ REFRESH_CMD_EVENT
Definition: pgedit.cpp:64
@ BITMAP_CMD_EVENT
Definition: pgedit.cpp:59
@ DUMP_WERD_CMD_EVENT
Definition: pgedit.cpp:50
@ SHOW_BLOB_FEATURES
Definition: pgedit.cpp:68
@ SHOW_POINT_CMD_EVENT
Definition: pgedit.cpp:51
@ IMAGE_CMD_EVENT
Definition: pgedit.cpp:60
@ RECOG_WERDS
Definition: pgedit.cpp:66
@ NULL_CMD_EVENT
Definition: pgedit.cpp:48
@ SHOW_DROPCAPS_CMD_EVENT
Definition: pgedit.cpp:77
@ SHOW_FIXEDPITCH_CMD_EVENT
Definition: pgedit.cpp:74
@ CHANGE_DISP_CMD_EVENT
Definition: pgedit.cpp:49
@ CORRECT_TEXT_CMD_EVENT
Definition: pgedit.cpp:56
@ BOUNDING_BOX_CMD_EVENT
Definition: pgedit.cpp:55
@ BLOCKS_CMD_EVENT
Definition: pgedit.cpp:61
@ POLYGONAL_CMD_EVENT
Definition: pgedit.cpp:57
@ UNIFORM_DISP_CMD_EVENT
Definition: pgedit.cpp:63
@ QUIT_CMD_EVENT
Definition: pgedit.cpp:65
@ SHOW_SMALLCAPS_CMD_EVENT
Definition: pgedit.cpp:76
@ SHOW_ITALIC_CMD_EVENT
Definition: pgedit.cpp:71
ColorationMode
Definition: pgedit.cpp:80
@ CM_ITALIC
Definition: pgedit.cpp:84
@ CM_SUBSCRIPT
Definition: pgedit.cpp:82
@ CM_RAINBOW
Definition: pgedit.cpp:81
@ CM_FIXEDPITCH
Definition: pgedit.cpp:87
@ CM_BOLD
Definition: pgedit.cpp:85
@ CM_SMALLCAPS
Definition: pgedit.cpp:89
@ CM_SUPERSCRIPT
Definition: pgedit.cpp:83
@ CM_SERIF
Definition: pgedit.cpp:88
@ CM_DROPCAPS
Definition: pgedit.cpp:90
@ CM_UNDERLINE
Definition: pgedit.cpp:86
PAGE_RES_IT * make_pseudo_word(PAGE_RES *page_res, const TBOX &selection_box)
Definition: werdit.cpp:38
int editor_image_ypos
Definition: pgedit.cpp:121
int editor_word_height
Definition: pgedit.cpp:129
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
@ SP_SUBSCRIPT
Definition: ratngs.h:250
@ SP_DROPCAP
Definition: ratngs.h:250
@ SP_SUPERSCRIPT
Definition: ratngs.h:250
int editor_image_xpos
Definition: pgedit.cpp:120
@ SVET_SELECTION
Definition: scrollview.h:56
@ SVET_DESTROY
Definition: scrollview.h:53
@ SVET_POPUP
Definition: scrollview.h:61
@ SVET_CLICK
Definition: scrollview.h:55
@ character
Definition: mfoutline.h:53
@ baseline
Definition: mfoutline.h:53
ScrollView * CreateFeatureSpaceWindow(const char *name, int xpos, int ypos)
Definition: intproto.cpp:1622
void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT *Feature, ScrollView::Color color)
Definition: intproto.cpp:1500
int editor_word_ypos
Definition: pgedit.cpp:128
int editor_word_width
Definition: pgedit.cpp:130
@ DF_POLYGONAL
Polyg approx.
Definition: werd.h:50
@ DF_BLAMER
Blamer information.
Definition: werd.h:53
@ DF_BOX
Bounding box.
Definition: werd.h:48
@ DF_BN_POLYGONAL
BL normalisd polyapx.
Definition: werd.h:52
@ DF_EDGE_STEP
Edge steps.
Definition: werd.h:51
@ DF_TEXT
Correct ascii.
Definition: werd.h:49
IncorrectResultReason
Definition: blamer.h:56
@ IRR_CORRECT
Definition: blamer.h:58
@ IRR_PAGE_LAYOUT
Definition: blamer.h:77
@ IRR_NUM_REASONS
Definition: blamer.h:103
int editor_image_word_bb_color
Definition: pgedit.cpp:123
int editor_image_blob_bb_color
Definition: pgedit.cpp:124
void ClearFeatureSpaceWindow(NORM_METHOD norm_method, ScrollView *window)
Definition: intproto.cpp:887
int editor_word_xpos
Definition: pgedit.cpp:127
char * editor_image_win_name
Definition: pgedit.cpp:119
char * editor_word_name
Definition: pgedit.cpp:126
void Notify(const SVEvent *sve) override
Definition: paramsd.cpp:271
void Notify(const SVEvent *sv_event) override
Definition: pgedit.cpp:184
void Notify(const SVEvent *sve) override
Definition: pgedit.cpp:250
bool recog_interactive(PAGE_RES_IT *pr_it)
Definition: control.cpp:76
void process_image_event(const SVEvent &event)
Definition: pgedit.cpp:566
bool process_cmd_win_event(int32_t cmd_event, char *new_value)
Definition: pgedit.cpp:390
SVMenuNode * build_menu_new()
Definition: pgedit.cpp:274
void recog_pseudo_word(PAGE_RES *page_res, TBOX &selection_box)
Definition: control.cpp:62
bool word_display(PAGE_RES_IT *pr_it)
Definition: pgedit.cpp:701
bool word_bln_display(PAGE_RES_IT *pr_it)
Definition: pgedit.cpp:676
Image BestPix() const
void process_selected_words(PAGE_RES *page_res, TBOX &selection_box, bool(tesseract::Tesseract::*word_processor)(PAGE_RES_IT *pr_it))
Definition: pagewalk.cpp:30
bool word_set_display(PAGE_RES_IT *pr_it)
Definition: pgedit.cpp:899
bool word_dumper(PAGE_RES_IT *pr_it)
Definition: pgedit.cpp:876
bool word_blank_and_set_display(PAGE_RES_IT *pr_its)
Definition: pgedit.cpp:666
void debug_word(PAGE_RES *page_res, const TBOX &selection_box)
Definition: pgedit.cpp:639
void pgeditor_main(int width, int height, PAGE_RES *page_res)
Definition: pgedit.cpp:354
void blob_feature_display(PAGE_RES *page_res, const TBOX &selection_box)
Definition: pgedit.cpp:912
void do_re_display(bool(tesseract::Tesseract::*word_painter)(PAGE_RES_IT *pr_it))
Definition: pgedit.cpp:324
bool recog_all_words(PAGE_RES *page_res, ETEXT_DESC *monitor, const TBOX *target_word_box, const char *word_config, int dopasses)
Definition: control.cpp:287
const std::string & debug() const
Definition: blamer.h:140
static const char * IncorrectReasonName(IncorrectResultReason irr)
Definition: blamer.cpp:56
std::string TruthString() const
Definition: blamer.h:124
IncorrectResultReason incorrect_result_reason() const
Definition: blamer.h:131
static TWERD * PolygonalCopy(bool allow_detailed_fx, WERD *src)
Definition: blobs.cpp:778
std::vector< TBLOB * > blobs
Definition: blobs.h:462
void plot(ScrollView *window)
Definition: blobs.cpp:907
const TBOX & BlobBox(unsigned index) const
Definition: boxword.h:84
unsigned length() const
Definition: boxword.h:81
bool is_italic() const
Definition: fontinfo.h:118
bool is_fixed_pitch() const
Definition: fontinfo.h:124
bool is_bold() const
Definition: fontinfo.h:121
bool is_serif() const
Definition: fontinfo.h:127
void print(FILE *fp, bool dump)
dump whole table
Definition: ocrblock.cpp:188
PDBLK pdblk
Page Description Block.
Definition: ocrblock.h:185
void plot_baseline(ScrollView *window, ScrollView::Color colour)
Definition: ocrrow.h:139
void print(FILE *fp) const
Definition: ocrrow.cpp:167
float x_height() const
Definition: ocrrow.h:66
BLOCK_RES_LIST block_res_list
Definition: pageres.h:81
WERD_CHOICE * best_choice
Definition: pageres.h:239
TWERD * chopped_word
Definition: pageres.h:210
bool SetupForRecognition(const UNICHARSET &unicharset_in, tesseract::Tesseract *tesseract, Image pix, int norm_mode, const TBOX *norm_box, bool numeric_mode, bool use_body_size, bool allow_detailed_fx, ROW *row, const BLOCK *block)
Definition: pageres.cpp:304
BlamerBundle * blamer_bundle
Definition: pageres.h:250
const FontInfo * fontinfo
Definition: pageres.h:307
tesseract::BoxWord * box_word
Definition: pageres.h:270
BLOCK_RES * prev_block() const
Definition: pageres.h:760
ROW_RES * prev_row() const
Definition: pageres.h:757
WERD_RES * forward()
Definition: pageres.h:743
ROW_RES * row() const
Definition: pageres.h:766
WERD_RES * word() const
Definition: pageres.h:763
BLOCK_RES * block() const
Definition: pageres.h:769
void plot(ScrollView *window, int32_t serial, ScrollView::Color colour)
Definition: pdblock.cpp:185
integer coordinate
Definition: points.h:36
void set_x(TDimension xin)
rewrite function
Definition: points.h:67
void set_y(TDimension yin)
rewrite function
Definition: points.h:71
void string_and_lengths(std::string *word_str, std::string *word_lengths_str) const
Definition: ratngs.cpp:427
ScriptPos BlobPosition(unsigned index) const
Definition: ratngs.h:302
TDimension left() const
Definition: rect.h:82
TDimension height() const
Definition: rect.h:118
TDimension width() const
Definition: rect.h:126
TDimension top() const
Definition: rect.h:68
TDimension right() const
Definition: rect.h:89
TDimension bottom() const
Definition: rect.h:75
void plot(ScrollView *fd) const
Definition: rect.h:296
C_BLOB_LIST * cblob_list()
Definition: werd.h:96
void set_display_flag(uint8_t flag, bool value)
Definition: werd.h:138
bool display_flag(uint8_t flag) const
Definition: werd.h:135
static ScrollView::Color NextColor(ScrollView::Color colour)
Definition: werd.cpp:298
TBOX bounding_box() const
Definition: werd.cpp:155
const char * text() const
Definition: werd.h:121
void print() const
Definition: werd.cpp:262
void plot(ScrollView *window, ScrollView::Color colour)
Definition: werd.cpp:289
UNICHARSET unicharset
Definition: ccutil.h:61
static void ExtractFeatures(const TBLOB &blob, bool nonlinear_norm, std::vector< INT_FEATURE_STRUCT > *bl_features, std::vector< INT_FEATURE_STRUCT > *cn_features, INT_FX_RESULT_STRUCT *results, std::vector< int > *outline_cn_counts)
Definition: intfx.cpp:436
SVEventType type
Definition: scrollview.h:73
char * ShowInputDialog(const char *msg)
Definition: scrollview.cpp:735
void AddMessage(const char *message)
Definition: scrollview.cpp:546
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:623
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:648
void Draw(Image image, int x_pos, int y_pos)
Definition: scrollview.cpp:767
void SetVisible(bool visible)
Definition: scrollview.cpp:528
void Pen(Color color)
Definition: scrollview.cpp:723
static void Update()
Definition: scrollview.cpp:713
void AddEventHandler(SVEventHandler *listener)
Add an Event Listener to this ScrollView Window.
Definition: scrollview.cpp:418
void Brush(Color color)
Definition: scrollview.cpp:729
static void Exit()
Definition: scrollview.cpp:572
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:589
SVEvent * AwaitEvent(SVEventType type)
Definition: scrollview.cpp:445
SVMenuNode * AddChild(const char *txt)
Definition: svmnode.cpp:59
void BuildMenu(ScrollView *sv, bool menu_bar=true)
Definition: svmnode.cpp:120