|
tesseract 3.04.01
|
00001 /********************************************************************** 00002 * File: pgedit.cpp (Formerly pgeditor.c) 00003 * Description: Page structure file editor 00004 * Author: Phil Cheatle 00005 * Created: Thu Oct 10 16:25:24 BST 1991 00006 * 00007 *(C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0(the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http:// www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #ifdef _MSC_VER 00021 #pragma warning(disable:4244) // Conversion warnings 00022 #endif 00023 00024 // Include automatically generated configuration file if running autoconf. 00025 #ifdef HAVE_CONFIG_H 00026 #include "config_auto.h" 00027 #endif 00028 00029 #include "pgedit.h" 00030 00031 #include <ctype.h> 00032 #include <math.h> 00033 00034 #include "blread.h" 00035 #include "control.h" 00036 #include "paramsd.h" 00037 #include "pageres.h" 00038 #include "tordmain.h" 00039 #include "scrollview.h" 00040 #include "svmnode.h" 00041 #include "statistc.h" 00042 #include "tesseractclass.h" 00043 #include "werdit.h" 00044 00045 #ifndef GRAPHICS_DISABLED 00046 #define ASC_HEIGHT (2 * kBlnBaselineOffset + kBlnXHeight) 00047 #define X_HEIGHT (kBlnBaselineOffset + kBlnXHeight) 00048 #define BL_HEIGHT kBlnBaselineOffset 00049 #define DESC_HEIGHT 0 00050 #define MAXSPACING 128 /*max expected spacing in pix */ 00051 00052 const ERRCODE EMPTYBLOCKLIST = "No blocks to edit"; 00053 00054 enum CMD_EVENTS 00055 { 00056 NULL_CMD_EVENT, 00057 CHANGE_DISP_CMD_EVENT, 00058 DUMP_WERD_CMD_EVENT, 00059 SHOW_POINT_CMD_EVENT, 00060 SHOW_BLN_WERD_CMD_EVENT, 00061 DEBUG_WERD_CMD_EVENT, 00062 BLAMER_CMD_EVENT, 00063 BOUNDING_BOX_CMD_EVENT, 00064 CORRECT_TEXT_CMD_EVENT, 00065 POLYGONAL_CMD_EVENT, 00066 BL_NORM_CMD_EVENT, 00067 BITMAP_CMD_EVENT, 00068 IMAGE_CMD_EVENT, 00069 BLOCKS_CMD_EVENT, 00070 BASELINES_CMD_EVENT, 00071 UNIFORM_DISP_CMD_EVENT, 00072 REFRESH_CMD_EVENT, 00073 QUIT_CMD_EVENT, 00074 RECOG_WERDS, 00075 RECOG_PSEUDO, 00076 SHOW_BLOB_FEATURES, 00077 SHOW_SUBSCRIPT_CMD_EVENT, 00078 SHOW_SUPERSCRIPT_CMD_EVENT, 00079 SHOW_ITALIC_CMD_EVENT, 00080 SHOW_BOLD_CMD_EVENT, 00081 SHOW_UNDERLINE_CMD_EVENT, 00082 SHOW_FIXEDPITCH_CMD_EVENT, 00083 SHOW_SERIF_CMD_EVENT, 00084 SHOW_SMALLCAPS_CMD_EVENT, 00085 SHOW_DROPCAPS_CMD_EVENT, 00086 }; 00087 00088 enum ColorationMode { 00089 CM_RAINBOW, 00090 CM_SUBSCRIPT, 00091 CM_SUPERSCRIPT, 00092 CM_ITALIC, 00093 CM_BOLD, 00094 CM_UNDERLINE, 00095 CM_FIXEDPITCH, 00096 CM_SERIF, 00097 CM_SMALLCAPS, 00098 CM_DROPCAPS 00099 }; 00100 00101 /* 00102 * 00103 * Some global data 00104 * 00105 */ 00106 00107 ScrollView* image_win; 00108 ParamsEditor* pe; 00109 bool stillRunning = false; 00110 00111 #ifdef __UNIX__ 00112 FILE *debug_window = NULL; // opened on demand 00113 #endif 00114 ScrollView* bln_word_window = NULL; // baseline norm words 00115 00116 CMD_EVENTS mode = CHANGE_DISP_CMD_EVENT; // selected words op 00117 00118 bool recog_done = false; // recog_all_words was called 00119 00120 // These variables should remain global, since they are only used for the 00121 // debug mode (in which only a single Tesseract thread/instance will be exist). 00122 BITS16 word_display_mode; 00123 static ColorationMode color_mode = CM_RAINBOW; 00124 BOOL8 display_image = FALSE; 00125 BOOL8 display_blocks = FALSE; 00126 BOOL8 display_baselines = FALSE; 00127 00128 PAGE_RES *current_page_res = NULL; 00129 00130 STRING_VAR(editor_image_win_name, "EditorImage", 00131 "Editor image window name"); 00132 INT_VAR(editor_image_xpos, 590, "Editor image X Pos"); 00133 INT_VAR(editor_image_ypos, 10, "Editor image Y Pos"); 00134 INT_VAR(editor_image_menuheight, 50, "Add to image height for menu bar"); 00135 INT_VAR(editor_image_word_bb_color, ScrollView::BLUE, 00136 "Word bounding box colour"); 00137 INT_VAR(editor_image_blob_bb_color, ScrollView::YELLOW, 00138 "Blob bounding box colour"); 00139 INT_VAR(editor_image_text_color, ScrollView::WHITE, 00140 "Correct text colour"); 00141 00142 STRING_VAR(editor_dbwin_name, "EditorDBWin", 00143 "Editor debug window name"); 00144 INT_VAR(editor_dbwin_xpos, 50, "Editor debug window X Pos"); 00145 INT_VAR(editor_dbwin_ypos, 500, "Editor debug window Y Pos"); 00146 INT_VAR(editor_dbwin_height, 24, "Editor debug window height"); 00147 INT_VAR(editor_dbwin_width, 80, "Editor debug window width"); 00148 00149 STRING_VAR(editor_word_name, "BlnWords", "BL normalized word window"); 00150 INT_VAR(editor_word_xpos, 60, "Word window X Pos"); 00151 INT_VAR(editor_word_ypos, 510, "Word window Y Pos"); 00152 INT_VAR(editor_word_height, 240, "Word window height"); 00153 INT_VAR(editor_word_width, 655, "Word window width"); 00154 00155 STRING_VAR(editor_debug_config_file, "", "Config file to apply to single words"); 00156 00157 class BlnEventHandler : public SVEventHandler { 00158 public: 00159 void Notify(const SVEvent* sv_event) { 00160 if (sv_event->type == SVET_DESTROY) 00161 bln_word_window = NULL; 00162 else if (sv_event->type == SVET_CLICK) 00163 show_point(current_page_res, sv_event->x, sv_event->y); 00164 } 00165 }; 00166 00172 ScrollView* bln_word_window_handle() { // return handle 00173 // not opened yet 00174 if (bln_word_window == NULL) { 00175 pgeditor_msg("Creating BLN word window..."); 00176 bln_word_window = new ScrollView(editor_word_name.string(), 00177 editor_word_xpos, editor_word_ypos, editor_word_width, 00178 editor_word_height, 4000, 4000, true); 00179 BlnEventHandler* a = new BlnEventHandler(); 00180 bln_word_window->AddEventHandler(a); 00181 pgeditor_msg("Creating BLN word window...Done"); 00182 } 00183 return bln_word_window; 00184 } 00185 00193 void build_image_window(int width, int height) { 00194 if (image_win != NULL) { delete image_win; } 00195 image_win = new ScrollView(editor_image_win_name.string(), 00196 editor_image_xpos, editor_image_ypos, 00197 width + 1, 00198 height + editor_image_menuheight + 1, 00199 width, 00200 height, 00201 true); 00202 } 00203 00210 void display_bln_lines(ScrollView* window, 00211 ScrollView::Color colour, 00212 float scale_factor, 00213 float y_offset, 00214 float minx, 00215 float maxx) { 00216 window->Pen(colour); 00217 window->Line(minx, y_offset + scale_factor * DESC_HEIGHT, 00218 maxx, y_offset + scale_factor * DESC_HEIGHT); 00219 window->Line(minx, y_offset + scale_factor * BL_HEIGHT, 00220 maxx, y_offset + scale_factor * BL_HEIGHT); 00221 window->Line(minx, y_offset + scale_factor * X_HEIGHT, 00222 maxx, y_offset + scale_factor * X_HEIGHT); 00223 window->Line(minx, y_offset + scale_factor * ASC_HEIGHT, 00224 maxx, y_offset + scale_factor * ASC_HEIGHT); 00225 } 00226 00235 void PGEventHandler::Notify(const SVEvent* event) { 00236 char myval = '0'; 00237 if (event->type == SVET_POPUP) { 00238 pe->Notify(event); 00239 } // These are handled by ParamsEditor 00240 else if (event->type == SVET_EXIT) { stillRunning = false; } 00241 else if (event->type == SVET_MENU) { 00242 if (strcmp(event->parameter, "true") == 0) { myval = 'T'; } 00243 else if (strcmp(event->parameter, "false") == 0) { myval = 'F'; } 00244 tess_->process_cmd_win_event(event->command_id, &myval); 00245 } 00246 else { 00247 tess_->process_image_event(*event); 00248 } 00249 } 00250 00256 namespace tesseract { 00257 SVMenuNode *Tesseract::build_menu_new() { 00258 SVMenuNode* parent_menu; 00259 SVMenuNode* root_menu_item = new SVMenuNode(); 00260 00261 SVMenuNode* modes_menu_item = root_menu_item->AddChild("MODES"); 00262 00263 modes_menu_item->AddChild("Change Display", CHANGE_DISP_CMD_EVENT); 00264 modes_menu_item->AddChild("Dump Word", DUMP_WERD_CMD_EVENT); 00265 modes_menu_item->AddChild("Show Point", SHOW_POINT_CMD_EVENT); 00266 modes_menu_item->AddChild("Show BL Norm Word", SHOW_BLN_WERD_CMD_EVENT); 00267 modes_menu_item->AddChild("Config Words", DEBUG_WERD_CMD_EVENT); 00268 modes_menu_item->AddChild("Recog Words", RECOG_WERDS); 00269 modes_menu_item->AddChild("Recog Blobs", RECOG_PSEUDO); 00270 modes_menu_item->AddChild("Show Blob Features", SHOW_BLOB_FEATURES); 00271 00272 parent_menu = root_menu_item->AddChild("DISPLAY"); 00273 00274 parent_menu->AddChild("Blamer", BLAMER_CMD_EVENT, FALSE); 00275 parent_menu->AddChild("Bounding Boxes", BOUNDING_BOX_CMD_EVENT, FALSE); 00276 parent_menu->AddChild("Correct Text", CORRECT_TEXT_CMD_EVENT, FALSE); 00277 parent_menu->AddChild("Polygonal Approx", POLYGONAL_CMD_EVENT, FALSE); 00278 parent_menu->AddChild("Baseline Normalized", BL_NORM_CMD_EVENT, FALSE); 00279 parent_menu->AddChild("Edge Steps", BITMAP_CMD_EVENT, TRUE); 00280 parent_menu->AddChild("Subscripts", SHOW_SUBSCRIPT_CMD_EVENT); 00281 parent_menu->AddChild("Superscripts", SHOW_SUPERSCRIPT_CMD_EVENT); 00282 parent_menu->AddChild("Italics", SHOW_ITALIC_CMD_EVENT); 00283 parent_menu->AddChild("Bold", SHOW_BOLD_CMD_EVENT); 00284 parent_menu->AddChild("Underline", SHOW_UNDERLINE_CMD_EVENT); 00285 parent_menu->AddChild("FixedPitch", SHOW_FIXEDPITCH_CMD_EVENT); 00286 parent_menu->AddChild("Serifs", SHOW_SERIF_CMD_EVENT); 00287 parent_menu->AddChild("SmallCaps", SHOW_SMALLCAPS_CMD_EVENT); 00288 parent_menu->AddChild("DropCaps", SHOW_DROPCAPS_CMD_EVENT); 00289 00290 00291 parent_menu = root_menu_item->AddChild("OTHER"); 00292 00293 parent_menu->AddChild("Quit", QUIT_CMD_EVENT); 00294 parent_menu->AddChild("Show Image", IMAGE_CMD_EVENT, FALSE); 00295 parent_menu->AddChild("ShowBlock Outlines", BLOCKS_CMD_EVENT, FALSE); 00296 parent_menu->AddChild("Show Baselines", BASELINES_CMD_EVENT, FALSE); 00297 parent_menu->AddChild("Uniform Display", UNIFORM_DISP_CMD_EVENT); 00298 parent_menu->AddChild("Refresh Display", REFRESH_CMD_EVENT); 00299 00300 return root_menu_item; 00301 } 00302 00308 void Tesseract::do_re_display( 00309 BOOL8 (tesseract::Tesseract::*word_painter)(PAGE_RES_IT* pr_it)) { 00310 int block_count = 1; 00311 00312 image_win->Clear(); 00313 if (display_image != 0) { 00314 image_win->Image(pix_binary_, 0, 0); 00315 } 00316 00317 image_win->Brush(ScrollView::NONE); 00318 PAGE_RES_IT pr_it(current_page_res); 00319 for (WERD_RES* word = pr_it.word(); word != NULL; word = pr_it.forward()) { 00320 (this->*word_painter)(&pr_it); 00321 if (display_baselines && pr_it.row() != pr_it.prev_row()) 00322 pr_it.row()->row->plot_baseline(image_win, ScrollView::GREEN); 00323 if (display_blocks && pr_it.block() != pr_it.prev_block()) 00324 pr_it.block()->block->plot(image_win, block_count++, ScrollView::RED); 00325 } 00326 image_win->Update(); 00327 } 00328 00337 void Tesseract::pgeditor_main(int width, int height, PAGE_RES *page_res) { 00338 current_page_res = page_res; 00339 if (current_page_res->block_res_list.empty()) 00340 return; 00341 00342 recog_done = false; 00343 stillRunning = true; 00344 00345 build_image_window(width, height); 00346 word_display_mode.turn_on_bit(DF_EDGE_STEP); 00347 do_re_display(&tesseract::Tesseract::word_set_display); 00348 #ifndef GRAPHICS_DISABLED 00349 pe = new ParamsEditor(this, image_win); 00350 #endif 00351 PGEventHandler pgEventHandler(this); 00352 00353 image_win->AddEventHandler(&pgEventHandler); 00354 image_win->AddMessageBox(); 00355 00356 SVMenuNode* svMenuRoot = build_menu_new(); 00357 00358 svMenuRoot->BuildMenu(image_win); 00359 image_win->SetVisible(true); 00360 00361 image_win->AwaitEvent(SVET_DESTROY); 00362 image_win->AddEventHandler(NULL); 00363 } 00364 } // namespace tesseract 00365 00366 00373 void pgeditor_msg( // message display 00374 const char *msg) { 00375 image_win->AddMessage(msg); 00376 } 00377 00384 void pgeditor_show_point( // display coords 00385 SVEvent *event) { 00386 image_win->AddMessage("Pointing at(%d, %d)", event->x, event->y); 00387 } 00388 00396 namespace tesseract { 00397 BOOL8 Tesseract::process_cmd_win_event( // UI command semantics 00398 inT32 cmd_event, // which menu item? 00399 char *new_value // any prompt data 00400 ) { 00401 char msg[160]; 00402 BOOL8 exit = FALSE; 00403 00404 color_mode = CM_RAINBOW; 00405 00406 // Run recognition on the full page if needed. 00407 switch (cmd_event) { 00408 case BLAMER_CMD_EVENT: 00409 case SHOW_SUBSCRIPT_CMD_EVENT: 00410 case SHOW_SUPERSCRIPT_CMD_EVENT: 00411 case SHOW_ITALIC_CMD_EVENT: 00412 case SHOW_BOLD_CMD_EVENT: 00413 case SHOW_UNDERLINE_CMD_EVENT: 00414 case SHOW_FIXEDPITCH_CMD_EVENT: 00415 case SHOW_SERIF_CMD_EVENT: 00416 case SHOW_SMALLCAPS_CMD_EVENT: 00417 case SHOW_DROPCAPS_CMD_EVENT: 00418 if (!recog_done) { 00419 recog_all_words(current_page_res, NULL, NULL, NULL, 0); 00420 recog_done = true; 00421 } 00422 break; 00423 default: 00424 break; 00425 } 00426 00427 switch (cmd_event) { 00428 case NULL_CMD_EVENT: 00429 break; 00430 00431 case CHANGE_DISP_CMD_EVENT: 00432 case DUMP_WERD_CMD_EVENT: 00433 case SHOW_POINT_CMD_EVENT: 00434 case SHOW_BLN_WERD_CMD_EVENT: 00435 case RECOG_WERDS: 00436 case RECOG_PSEUDO: 00437 case SHOW_BLOB_FEATURES: 00438 mode =(CMD_EVENTS) cmd_event; 00439 break; 00440 case DEBUG_WERD_CMD_EVENT: 00441 mode = DEBUG_WERD_CMD_EVENT; 00442 word_config_ = image_win->ShowInputDialog("Config File Name"); 00443 break; 00444 case BOUNDING_BOX_CMD_EVENT: 00445 if (new_value[0] == 'T') 00446 word_display_mode.turn_on_bit(DF_BOX); 00447 else 00448 word_display_mode.turn_off_bit(DF_BOX); 00449 mode = CHANGE_DISP_CMD_EVENT; 00450 break; 00451 case BLAMER_CMD_EVENT: 00452 if (new_value[0] == 'T') 00453 word_display_mode.turn_on_bit(DF_BLAMER); 00454 else 00455 word_display_mode.turn_off_bit(DF_BLAMER); 00456 do_re_display(&tesseract::Tesseract::word_display); 00457 mode = CHANGE_DISP_CMD_EVENT; 00458 break; 00459 case CORRECT_TEXT_CMD_EVENT: 00460 if (new_value[0] == 'T') 00461 word_display_mode.turn_on_bit(DF_TEXT); 00462 else 00463 word_display_mode.turn_off_bit(DF_TEXT); 00464 mode = CHANGE_DISP_CMD_EVENT; 00465 break; 00466 case POLYGONAL_CMD_EVENT: 00467 if (new_value[0] == 'T') 00468 word_display_mode.turn_on_bit(DF_POLYGONAL); 00469 else 00470 word_display_mode.turn_off_bit(DF_POLYGONAL); 00471 mode = CHANGE_DISP_CMD_EVENT; 00472 break; 00473 case BL_NORM_CMD_EVENT: 00474 if (new_value[0] == 'T') 00475 word_display_mode.turn_on_bit(DF_BN_POLYGONAL); 00476 else 00477 word_display_mode.turn_off_bit(DF_BN_POLYGONAL); 00478 mode = CHANGE_DISP_CMD_EVENT; 00479 break; 00480 case BITMAP_CMD_EVENT: 00481 if (new_value[0] == 'T') 00482 word_display_mode.turn_on_bit(DF_EDGE_STEP); 00483 else 00484 word_display_mode.turn_off_bit(DF_EDGE_STEP); 00485 mode = CHANGE_DISP_CMD_EVENT; 00486 break; 00487 case UNIFORM_DISP_CMD_EVENT: 00488 do_re_display(&tesseract::Tesseract::word_set_display); 00489 break; 00490 case IMAGE_CMD_EVENT: 00491 display_image =(new_value[0] == 'T'); 00492 do_re_display(&tesseract::Tesseract::word_display); 00493 break; 00494 case BLOCKS_CMD_EVENT: 00495 display_blocks =(new_value[0] == 'T'); 00496 do_re_display(&tesseract::Tesseract::word_display); 00497 break; 00498 case BASELINES_CMD_EVENT: 00499 display_baselines =(new_value[0] == 'T'); 00500 do_re_display(&tesseract::Tesseract::word_display); 00501 break; 00502 case SHOW_SUBSCRIPT_CMD_EVENT: 00503 color_mode = CM_SUBSCRIPT; 00504 do_re_display(&tesseract::Tesseract::word_display); 00505 break; 00506 case SHOW_SUPERSCRIPT_CMD_EVENT: 00507 color_mode = CM_SUPERSCRIPT; 00508 do_re_display(&tesseract::Tesseract::word_display); 00509 break; 00510 case SHOW_ITALIC_CMD_EVENT: 00511 color_mode = CM_ITALIC; 00512 do_re_display(&tesseract::Tesseract::word_display); 00513 break; 00514 case SHOW_BOLD_CMD_EVENT: 00515 color_mode = CM_BOLD; 00516 do_re_display(&tesseract::Tesseract::word_display); 00517 break; 00518 case SHOW_UNDERLINE_CMD_EVENT: 00519 color_mode = CM_UNDERLINE; 00520 do_re_display(&tesseract::Tesseract::word_display); 00521 break; 00522 case SHOW_FIXEDPITCH_CMD_EVENT: 00523 color_mode = CM_FIXEDPITCH; 00524 do_re_display(&tesseract::Tesseract::word_display); 00525 break; 00526 case SHOW_SERIF_CMD_EVENT: 00527 color_mode = CM_SERIF; 00528 do_re_display(&tesseract::Tesseract::word_display); 00529 break; 00530 case SHOW_SMALLCAPS_CMD_EVENT: 00531 color_mode = CM_SMALLCAPS; 00532 do_re_display(&tesseract::Tesseract::word_display); 00533 break; 00534 case SHOW_DROPCAPS_CMD_EVENT: 00535 color_mode = CM_DROPCAPS; 00536 do_re_display(&tesseract::Tesseract::word_display); 00537 break; 00538 case REFRESH_CMD_EVENT: 00539 do_re_display(&tesseract::Tesseract::word_display); 00540 break; 00541 case QUIT_CMD_EVENT: 00542 exit = TRUE; 00543 ScrollView::Exit(); 00544 break; 00545 00546 default: 00547 sprintf(msg, "Unrecognised event " INT32FORMAT "(%s)", 00548 cmd_event, new_value); 00549 image_win->AddMessage(msg); 00550 break; 00551 } 00552 return exit; 00553 } 00554 00555 00565 void Tesseract::process_image_event( // action in image win 00566 const SVEvent &event) { 00567 // The following variable should remain static, since it is used by 00568 // debug editor, which uses a single Tesseract instance. 00569 static ICOORD down; 00570 ICOORD up; 00571 TBOX selection_box; 00572 char msg[80]; 00573 00574 switch(event.type) { 00575 00576 case SVET_SELECTION: 00577 if (event.type == SVET_SELECTION) { 00578 down.set_x(event.x + event.x_size); 00579 down.set_y(event.y + event.y_size); 00580 if (mode == SHOW_POINT_CMD_EVENT) 00581 show_point(current_page_res, event.x, event.y); 00582 } 00583 00584 up.set_x(event.x); 00585 up.set_y(event.y); 00586 00587 selection_box = TBOX(down, up); 00588 00589 switch(mode) { 00590 case CHANGE_DISP_CMD_EVENT: 00591 process_selected_words( 00592 current_page_res, 00593 selection_box, 00594 &tesseract::Tesseract::word_blank_and_set_display); 00595 break; 00596 case DUMP_WERD_CMD_EVENT: 00597 process_selected_words(current_page_res, 00598 selection_box, 00599 &tesseract::Tesseract::word_dumper); 00600 break; 00601 case SHOW_BLN_WERD_CMD_EVENT: 00602 process_selected_words(current_page_res, 00603 selection_box, 00604 &tesseract::Tesseract::word_bln_display); 00605 break; 00606 case DEBUG_WERD_CMD_EVENT: 00607 debug_word(current_page_res, selection_box); 00608 break; 00609 case SHOW_POINT_CMD_EVENT: 00610 break; // ignore up event 00611 00612 case RECOG_WERDS: 00613 image_win->AddMessage("Recogging selected words"); 00614 this->process_selected_words(current_page_res, 00615 selection_box, 00616 &Tesseract::recog_interactive); 00617 break; 00618 case RECOG_PSEUDO: 00619 image_win->AddMessage("Recogging selected blobs"); 00620 recog_pseudo_word(current_page_res, selection_box); 00621 break; 00622 case SHOW_BLOB_FEATURES: 00623 blob_feature_display(current_page_res, selection_box); 00624 break; 00625 00626 default: 00627 sprintf(msg, "Mode %d not yet implemented", mode); 00628 image_win->AddMessage(msg); 00629 break; 00630 } 00631 default: 00632 break; 00633 } 00634 } 00635 00641 void Tesseract::debug_word(PAGE_RES* page_res, const TBOX &selection_box) { 00642 ResetAdaptiveClassifier(); 00643 recog_all_words(page_res, NULL, &selection_box, word_config_.string(), 0); 00644 } 00645 } // namespace tesseract 00646 00647 00655 void show_point(PAGE_RES* page_res, float x, float y) { 00656 FCOORD pt(x, y); 00657 PAGE_RES_IT pr_it(page_res); 00658 00659 const int kBufsize = 512; 00660 char msg[kBufsize]; 00661 char *msg_ptr = msg; 00662 00663 msg_ptr += sprintf(msg_ptr, "Pt:(%0.3f, %0.3f) ", x, y); 00664 00665 for (WERD_RES* word = pr_it.word(); word != NULL; word = pr_it.forward()) { 00666 if (pr_it.row() != pr_it.prev_row() && 00667 pr_it.row()->row->bounding_box().contains(pt)) { 00668 msg_ptr += sprintf(msg_ptr, "BL(x)=%0.3f ", 00669 pr_it.row()->row->base_line(x)); 00670 } 00671 if (word->word->bounding_box().contains(pt)) { 00672 TBOX box = word->word->bounding_box(); 00673 msg_ptr += sprintf(msg_ptr, "Wd(%d, %d)/(%d, %d) ", 00674 box.left(), box.bottom(), 00675 box.right(), box.top()); 00676 C_BLOB_IT cblob_it(word->word->cblob_list()); 00677 for (cblob_it.mark_cycle_pt(); 00678 !cblob_it.cycled_list(); 00679 cblob_it.forward()) { 00680 C_BLOB* cblob = cblob_it.data(); 00681 box = cblob->bounding_box(); 00682 if (box.contains(pt)) { 00683 msg_ptr += sprintf(msg_ptr, 00684 "CBlb(%d, %d)/(%d, %d) ", 00685 box.left(), box.bottom(), 00686 box.right(), box.top()); 00687 } 00688 } 00689 } 00690 } 00691 image_win->AddMessage(msg); 00692 } 00693 00694 00695 /********************************************************************** 00696 * WERD PROCESSOR FUNCTIONS 00697 * ======================== 00698 * 00699 * These routines are invoked by one or more of: 00700 * process_all_words() 00701 * process_selected_words() 00702 * or 00703 * process_all_words_it() 00704 * process_selected_words_it() 00705 * for each word to be processed 00706 **********************************************************************/ 00707 00714 #endif // GRAPHICS_DISABLED 00715 namespace tesseract { 00716 #ifndef GRAPHICS_DISABLED 00717 BOOL8 Tesseract:: word_blank_and_set_display(PAGE_RES_IT* pr_it) { 00718 pr_it->word()->word->bounding_box().plot(image_win, ScrollView::BLACK, 00719 ScrollView::BLACK); 00720 return word_set_display(pr_it); 00721 } 00722 00723 00729 BOOL8 Tesseract::word_bln_display(PAGE_RES_IT* pr_it) { 00730 WERD_RES* word_res = pr_it->word(); 00731 if (word_res->chopped_word == NULL) { 00732 // Setup word normalization parameters. 00733 word_res->SetupForRecognition(unicharset, this, BestPix(), 00734 tessedit_ocr_engine_mode, NULL, 00735 classify_bln_numeric_mode, 00736 textord_use_cjk_fp_model, 00737 poly_allow_detailed_fx, 00738 pr_it->row()->row, pr_it->block()->block); 00739 } 00740 bln_word_window_handle()->Clear(); 00741 display_bln_lines(bln_word_window_handle(), ScrollView::CYAN, 00742 1.0, 0.0f, -1000.0f, 1000.0f); 00743 C_BLOB_IT it(word_res->word->cblob_list()); 00744 ScrollView::Color color = WERD::NextColor(ScrollView::BLACK); 00745 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { 00746 it.data()->plot_normed(word_res->denorm, color, ScrollView::BROWN, 00747 bln_word_window_handle()); 00748 color = WERD::NextColor(color); 00749 } 00750 bln_word_window_handle()->Update(); 00751 return TRUE; 00752 } 00753 00754 00755 00761 BOOL8 Tesseract::word_display(PAGE_RES_IT* pr_it) { 00762 WERD_RES* word_res = pr_it->word(); 00763 WERD* word = word_res->word; 00764 TBOX word_bb; // word bounding box 00765 int word_height; // ht of word BB 00766 BOOL8 displayed_something = FALSE; 00767 float shift; // from bot left 00768 C_BLOB_IT c_it; // cblob iterator 00769 00770 if (color_mode != CM_RAINBOW && word_res->box_word != NULL) { 00771 BoxWord* box_word = word_res->box_word; 00772 WERD_CHOICE* best_choice = word_res->best_choice; 00773 int length = box_word->length(); 00774 if (word_res->fontinfo == NULL) return false; 00775 const FontInfo& font_info = *word_res->fontinfo; 00776 for (int i = 0; i < length; ++i) { 00777 ScrollView::Color color = ScrollView::GREEN; 00778 switch (color_mode) { 00779 case CM_SUBSCRIPT: 00780 if (best_choice->BlobPosition(i) == SP_SUBSCRIPT) 00781 color = ScrollView::RED; 00782 break; 00783 case CM_SUPERSCRIPT: 00784 if (best_choice->BlobPosition(i) == SP_SUPERSCRIPT) 00785 color = ScrollView::RED; 00786 break; 00787 case CM_ITALIC: 00788 if (font_info.is_italic()) 00789 color = ScrollView::RED; 00790 break; 00791 case CM_BOLD: 00792 if (font_info.is_bold()) 00793 color = ScrollView::RED; 00794 break; 00795 case CM_FIXEDPITCH: 00796 if (font_info.is_fixed_pitch()) 00797 color = ScrollView::RED; 00798 break; 00799 case CM_SERIF: 00800 if (font_info.is_serif()) 00801 color = ScrollView::RED; 00802 break; 00803 case CM_SMALLCAPS: 00804 if (word_res->small_caps) 00805 color = ScrollView::RED; 00806 break; 00807 case CM_DROPCAPS: 00808 if (best_choice->BlobPosition(i) == SP_DROPCAP) 00809 color = ScrollView::RED; 00810 break; 00811 // TODO(rays) underline is currently completely unsupported. 00812 case CM_UNDERLINE: 00813 default: 00814 break; 00815 } 00816 image_win->Pen(color); 00817 TBOX box = box_word->BlobBox(i); 00818 image_win->Rectangle(box.left(), box.bottom(), box.right(), box.top()); 00819 } 00820 return true; 00821 } 00822 /* 00823 Note the double coercions of(COLOUR)((inT32)editor_image_word_bb_color) 00824 etc. are to keep the compiler happy. 00825 */ 00826 // display bounding box 00827 if (word->display_flag(DF_BOX)) { 00828 word->bounding_box().plot(image_win, 00829 (ScrollView::Color)((inT32) 00830 editor_image_word_bb_color), 00831 (ScrollView::Color)((inT32) 00832 editor_image_word_bb_color)); 00833 00834 ScrollView::Color c = (ScrollView::Color) 00835 ((inT32) editor_image_blob_bb_color); 00836 image_win->Pen(c); 00837 c_it.set_to_list(word->cblob_list()); 00838 for (c_it.mark_cycle_pt(); !c_it.cycled_list(); c_it.forward()) 00839 c_it.data()->bounding_box().plot(image_win); 00840 displayed_something = TRUE; 00841 } 00842 00843 // display edge steps 00844 if (word->display_flag(DF_EDGE_STEP)) { // edgesteps available 00845 word->plot(image_win); // rainbow colors 00846 displayed_something = TRUE; 00847 } 00848 00849 // display poly approx 00850 if (word->display_flag(DF_POLYGONAL)) { 00851 // need to convert 00852 TWERD* tword = TWERD::PolygonalCopy(poly_allow_detailed_fx, word); 00853 tword->plot(image_win); 00854 delete tword; 00855 displayed_something = TRUE; 00856 } 00857 00858 // Display correct text and blamer information. 00859 STRING text; 00860 STRING blame; 00861 if (word->display_flag(DF_TEXT) && word->text() != NULL) { 00862 text = word->text(); 00863 } 00864 if (word->display_flag(DF_BLAMER) && 00865 !(word_res->blamer_bundle != NULL && 00866 word_res->blamer_bundle->incorrect_result_reason() == IRR_CORRECT)) { 00867 text = ""; 00868 const BlamerBundle *blamer_bundle = word_res->blamer_bundle; 00869 if (blamer_bundle == NULL) { 00870 text += "NULL"; 00871 } else { 00872 text = blamer_bundle->TruthString(); 00873 } 00874 text += " -> "; 00875 STRING best_choice_str; 00876 if (word_res->best_choice == NULL) { 00877 best_choice_str = "NULL"; 00878 } else { 00879 word_res->best_choice->string_and_lengths(&best_choice_str, NULL); 00880 } 00881 text += best_choice_str; 00882 IncorrectResultReason reason = (blamer_bundle == NULL) ? 00883 IRR_PAGE_LAYOUT : blamer_bundle->incorrect_result_reason(); 00884 ASSERT_HOST(reason < IRR_NUM_REASONS) 00885 blame += " ["; 00886 blame += BlamerBundle::IncorrectReasonName(reason); 00887 blame += "]"; 00888 } 00889 if (text.length() > 0) { 00890 word_bb = word->bounding_box(); 00891 image_win->Pen(ScrollView::RED); 00892 word_height = word_bb.height(); 00893 int text_height = 0.50 * word_height; 00894 if (text_height > 20) text_height = 20; 00895 image_win->TextAttributes("Arial", text_height, false, false, false); 00896 shift = (word_height < word_bb.width()) ? 0.25 * word_height : 0.0f; 00897 image_win->Text(word_bb.left() + shift, 00898 word_bb.bottom() + 0.25 * word_height, text.string()); 00899 if (blame.length() > 0) { 00900 image_win->Text(word_bb.left() + shift, 00901 word_bb.bottom() + 0.25 * word_height - text_height, 00902 blame.string()); 00903 } 00904 00905 displayed_something = TRUE; 00906 } 00907 00908 if (!displayed_something) // display BBox anyway 00909 word->bounding_box().plot(image_win, 00910 (ScrollView::Color)((inT32) editor_image_word_bb_color), 00911 (ScrollView::Color)((inT32) 00912 editor_image_word_bb_color)); 00913 return TRUE; 00914 } 00915 #endif // GRAPHICS_DISABLED 00916 00922 BOOL8 Tesseract::word_dumper(PAGE_RES_IT* pr_it) { 00923 if (pr_it->block()->block != NULL) { 00924 tprintf("\nBlock data...\n"); 00925 pr_it->block()->block->print(NULL, FALSE); 00926 } 00927 tprintf("\nRow data...\n"); 00928 pr_it->row()->row->print(NULL); 00929 tprintf("\nWord data...\n"); 00930 WERD_RES* word_res = pr_it->word(); 00931 word_res->word->print(); 00932 if (word_res->blamer_bundle != NULL && wordrec_debug_blamer && 00933 word_res->blamer_bundle->incorrect_result_reason() != IRR_CORRECT) { 00934 tprintf("Current blamer debug: %s\n", 00935 word_res->blamer_bundle->debug().string()); 00936 } 00937 return TRUE; 00938 } 00939 00940 #ifndef GRAPHICS_DISABLED 00941 00946 BOOL8 Tesseract::word_set_display(PAGE_RES_IT* pr_it) { 00947 WERD* word = pr_it->word()->word; 00948 word->set_display_flag(DF_BOX, word_display_mode.bit(DF_BOX)); 00949 word->set_display_flag(DF_TEXT, word_display_mode.bit(DF_TEXT)); 00950 word->set_display_flag(DF_POLYGONAL, word_display_mode.bit(DF_POLYGONAL)); 00951 word->set_display_flag(DF_EDGE_STEP, word_display_mode.bit(DF_EDGE_STEP)); 00952 word->set_display_flag(DF_BN_POLYGONAL, 00953 word_display_mode.bit(DF_BN_POLYGONAL)); 00954 word->set_display_flag(DF_BLAMER, word_display_mode.bit(DF_BLAMER)); 00955 return word_display(pr_it); 00956 } 00957 00958 // page_res is non-const because the iterator doesn't know if you are going 00959 // to change the items it points to! Really a const here though. 00960 void Tesseract::blob_feature_display(PAGE_RES* page_res, 00961 const TBOX& selection_box) { 00962 PAGE_RES_IT* it = make_pseudo_word(page_res, selection_box); 00963 if (it != NULL) { 00964 WERD_RES* word_res = it->word(); 00965 word_res->x_height = it->row()->row->x_height(); 00966 word_res->SetupForRecognition(unicharset, this, BestPix(), 00967 tessedit_ocr_engine_mode, NULL, 00968 classify_bln_numeric_mode, 00969 textord_use_cjk_fp_model, 00970 poly_allow_detailed_fx, 00971 it->row()->row, it->block()->block); 00972 TWERD* bln_word = word_res->chopped_word; 00973 TBLOB* bln_blob = bln_word->blobs[0]; 00974 INT_FX_RESULT_STRUCT fx_info; 00975 GenericVector<INT_FEATURE_STRUCT> bl_features; 00976 GenericVector<INT_FEATURE_STRUCT> cn_features; 00977 Classify::ExtractFeatures(*bln_blob, classify_nonlinear_norm, &bl_features, 00978 &cn_features, &fx_info, NULL); 00979 // Display baseline features. 00980 ScrollView* bl_win = CreateFeatureSpaceWindow("BL Features", 512, 0); 00981 ClearFeatureSpaceWindow(baseline, bl_win); 00982 for (int f = 0; f < bl_features.size(); ++f) 00983 RenderIntFeature(bl_win, &bl_features[f], ScrollView::GREEN); 00984 bl_win->Update(); 00985 // Display cn features. 00986 ScrollView* cn_win = CreateFeatureSpaceWindow("CN Features", 512, 0); 00987 ClearFeatureSpaceWindow(character, cn_win); 00988 for (int f = 0; f < cn_features.size(); ++f) 00989 RenderIntFeature(cn_win, &cn_features[f], ScrollView::GREEN); 00990 cn_win->Update(); 00991 00992 it->DeleteCurrentWord(); 00993 delete it; 00994 } 00995 } 00996 00997 00998 #endif // GRAPHICS_DISABLED 00999 01000 } // namespace tesseract 01001 01002 01003