diff options
author | Iliyan Malchev <malchev@google.com> | 2008-10-02 11:06:36 -0700 |
---|---|---|
committer | Iliyan Malchev <malchev@google.com> | 2008-10-09 14:27:53 -0700 |
commit | 6c98ac770461cc841619984aa4003f4b835949a8 (patch) | |
tree | d5b03f339f00bedfa5f3c85c3fb460f7d24d933a | |
parent | ad76e2d027e090acc9c39ba94633a00875124946 (diff) | |
download | tesseract-6c98ac770461cc841619984aa4003f4b835949a8.tar.gz |
8370000
Signed-off-by: Iliyan Malchev <malchev@google.com>
-rw-r--r-- | ccmain/baseapi.cpp | 87 | ||||
-rw-r--r-- | ccmain/baseapi.h | 9 | ||||
-rw-r--r-- | ccmain/tesseractmain.cpp | 4 | ||||
-rw-r--r-- | classify/adaptmatch.cpp | 30 | ||||
-rw-r--r-- | classify/adaptmatch.h | 5 | ||||
-rw-r--r-- | classify/classify.cpp | 2 | ||||
-rw-r--r-- | classify/classify.h | 38 | ||||
-rw-r--r-- | classify/intproto.h | 6 | ||||
-rw-r--r-- | dict/dawg.cpp | 12 | ||||
-rw-r--r-- | dict/dict.h | 3 | ||||
-rw-r--r-- | dict/permdawg.cpp | 17 | ||||
-rw-r--r-- | dict/permute.cpp | 13 | ||||
-rw-r--r-- | wordrec/tface.cpp | 6 | ||||
-rw-r--r-- | wordrec/tface.h | 4 | ||||
-rw-r--r-- | wordrec/wordrec.h | 2 |
15 files changed, 158 insertions, 80 deletions
diff --git a/ccmain/baseapi.cpp b/ccmain/baseapi.cpp index 38cf99e..ffa33d4 100644 --- a/ccmain/baseapi.cpp +++ b/ccmain/baseapi.cpp @@ -1146,4 +1146,91 @@ int TessBaseAPI::TesseractExtractResult(char** text, return n; } +// This method returns the features associated with the current image. +// Make sure setimage has been called before calling this method. +void TessBaseAPI::GetFeatures(INT_FEATURE_ARRAY int_features, + int* num_features) { + if (page_res_ != NULL) + ClearResults(); + if (!threshold_done_) + Threshold(); + // We have only one block, which is of the size of the page. + BLOCK_LIST* blocks = new BLOCK_LIST; + BLOCK *block = new BLOCK("", // filename. + TRUE, // proportional. + 0, // kerning. + 0, // spacing. + 0, // Left. + 0, // Bottom. + page_image.get_xsize(), // Right. + page_image.get_ysize()); // Top. + ICOORD bleft, tright; + block->bounding_box (bleft, tright); + + BLOCK_IT block_it_add = blocks; + block_it_add.add_to_end(block); + + ICOORD page_tr(page_image.get_xsize(), page_image.get_ysize()); + TEXTROW tessrow; + make_tess_row(NULL, // Denormalizer. + &tessrow); // Output row. + LINE_STATS line_stats; + GetLineStatsFromRow(&tessrow, &line_stats); + + // Perform a CC analysis to detect the blobs. + BLOCK_IT block_it = blocks; + for (block_it.mark_cycle_pt (); !block_it.cycled_list (); + block_it.forward ()) { + BLOCK* block = block_it.data(); +#ifndef GRAPHICS_DISABLED + extract_edges(NULL, // Scrollview window. + &page_image, // Image. + &page_image, // Thresholded image. + page_tr, // corner of page. + block); // block. +#else + extract_edges(&page_image, // Image. + &page_image, // Thresholded image. + page_tr, // corner of page. + block); // block. +#endif + C_BLOB_IT blob_it = block->blob_list(); + PBLOB *pblob = new PBLOB; + // Iterate over all blobs found and get their features. + for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); + blob_it.forward()) { + C_BLOB* blob = blob_it.data(); + blob = blob; + PBLOB c_as_p(blob, page_image.get_ysize()); + merge_blobs(pblob, &c_as_p); + } + + PBLOB_LIST *pblob_list = new PBLOB_LIST; + PBLOB_IT pblob_it(pblob_list); + pblob_it.add_after_then_move(pblob); + WERD word(pblob_list, // Blob list. + 0, // Blanks in front. + " "); // Correct text. + ROW *row = make_tess_ocrrow(0, // baseline. + page_image.get_ysize(), // xheight. + 0, // ascent. + 0); // descent. + word.baseline_normalise(row); + delete row; + if (pblob->out_list () == NULL) { + tprintf("Blob list is empty"); + } + TBLOB* tblob = make_tess_blob(pblob, // Blob. + TRUE); // Flatten. + + CLASS_NORMALIZATION_ARRAY norm_array; + inT32 len; + *num_features = tesseract_->GetCharNormFeatures( + tblob, &line_stats, + tesseract_->PreTrainedTemplates, + int_features, norm_array, &len); + } + delete blocks; +} + } // namespace tesseract. diff --git a/ccmain/baseapi.h b/ccmain/baseapi.h index 6500912..a660392 100644 --- a/ccmain/baseapi.h +++ b/ccmain/baseapi.h @@ -30,6 +30,11 @@ struct Pix; struct ETEXT_STRUCT; struct OSResults; +#define MAX_NUM_INT_FEATURES 512 +struct INT_FEATURE_STRUCT; +typedef INT_FEATURE_STRUCT *INT_FEATURE; +typedef INT_FEATURE_STRUCT INT_FEATURE_ARRAY[MAX_NUM_INT_FEATURES]; + namespace tesseract { class Tesseract; @@ -239,6 +244,10 @@ class TessBaseAPI { // Return the Orientation And Script void DetectOS(OSResults*); + // This method returns the features associated with the input image. + void GetFeatures(INT_FEATURE_ARRAY int_features, + int* num_features); + protected: // Common code for setting the image. Returns true if Init has been called. bool InternalSetImage(); diff --git a/ccmain/tesseractmain.cpp b/ccmain/tesseractmain.cpp index 24eafd5..b289df4 100644 --- a/ccmain/tesseractmain.cpp +++ b/ccmain/tesseractmain.cpp @@ -116,8 +116,10 @@ void TesseractImage(const char* input_file, IMAGE* image, text = api->GetBoxText(); else if (tessedit_write_unlv) text = api->GetUNLVText(); - else + else { + printf("that's the shit!\n"); text = api->GetUTF8Text(); + } *text_out += text; delete [] text; } else { diff --git a/classify/adaptmatch.cpp b/classify/adaptmatch.cpp index 766170d..3d2dfc9 100644 --- a/classify/adaptmatch.cpp +++ b/classify/adaptmatch.cpp @@ -277,12 +277,6 @@ make_toggle_var(EnableAdaptiveDebugger, 0, MakeEnableAdaptiveDebugger, INT_VAR(matcher_debug_level, 0, "Matcher Debug Level"); INT_VAR(matcher_debug_flags, 0, "Matcher Debug Flags"); -make_toggle_var(EnableLearning, 1, MakeEnableLearning, -18, 4, SetEnableLearning, "Enable learning"); -/* PREV DEFAULT 0 */ - /*record it for multiple pages */ -static int old_enable_learning = 1; - make_int_var(LearningDebugLevel, 0, MakeLearningDebugLevel, 18, 5, SetLearningDebugLevel, "Learning Debug Level: "); @@ -707,8 +701,6 @@ void Classify::InitAdaptiveClassifier() { free_adapted_templates(AdaptedTemplates); AdaptedTemplates = NewAdaptedTemplates(true); } - old_enable_learning = EnableLearning; - } /* InitAdaptiveClassifier */ void Classify::ResetAdaptiveClassifier() { @@ -740,7 +732,6 @@ void InitAdaptiveClassifierVars() { MakeUsePreAdaptedTemplates(); MakeSaveAdaptedTemplates(); - MakeEnableLearning(); MakeEnableAdaptiveDebugger(); MakeLearningDebugLevel(); MakeEnableIntFX(); @@ -794,11 +785,10 @@ void Classify::PrintAdaptiveStatistics(FILE *File) { PrintAdaptedTemplates(File, AdaptedTemplates); #endif } /* PrintAdaptiveStatistics */ -} // namespace tesseract /*---------------------------------------------------------------------------*/ -void SettupPass1() { +void Classify::SettupPass1() { /* ** Parameters: none ** Globals: @@ -817,7 +807,7 @@ void SettupPass1() { disabled, then it will remain disabled. This is only put here to make it very clear that learning is controlled directly by the global setting of EnableLearning. */ - EnableLearning = old_enable_learning; + EnableLearning = classify_enable_learning; SettupStopperPass1(); @@ -825,7 +815,7 @@ void SettupPass1() { /*---------------------------------------------------------------------------*/ -void SettupPass2() { +void Classify::SettupPass2() { /* ** Parameters: none ** Globals: @@ -845,7 +835,6 @@ void SettupPass2() { /*---------------------------------------------------------------------------*/ -namespace tesseract { void Classify::InitAdaptedClass(TBLOB *Blob, LINE_STATS *LineStats, CLASS_ID ClassId, @@ -1390,7 +1379,7 @@ void Classify::MasterMatcher(INT_TEMPLATES templates, IntegerMatcher(ClassForClassId(templates, class_id), protos, configs, final_results->BlobLength, num_features, features, norm_factors[class_id], - &int_result, NO_DEBUG); + &int_result, debug); // Compute class feature corrections. double miss_penalty = tessedit_class_miss_scale * int_result.FeatureMisses; @@ -1483,10 +1472,10 @@ UNICHAR_ID *Classify::BaselineClassifier(TBLOB *Blob, /*---------------------------------------------------------------------------*/ -void Classify::CharNormClassifier(TBLOB *Blob, - LINE_STATS *LineStats, - INT_TEMPLATES Templates, - ADAPT_RESULTS *Results) { +int Classify::CharNormClassifier(TBLOB *Blob, + LINE_STATS *LineStats, + INT_TEMPLATES Templates, + ADAPT_RESULTS *Results) { /* ** Parameters: ** Blob @@ -1524,7 +1513,7 @@ void Classify::CharNormClassifier(TBLOB *Blob, IntFeatures, CharNormArray, &(Results->BlobLength)); if (NumFeatures <= 0) - return; + return 0; NumClasses = ClassPruner(Templates, NumFeatures, IntFeatures, CharNormArray, @@ -1542,6 +1531,7 @@ void Classify::CharNormClassifier(TBLOB *Blob, MasterMatcher(Templates, NumFeatures, IntFeatures, CharNormArray, NULL, matcher_debug_flags, NumClasses, Results->CPResults, Results); + return NumFeatures; } /* CharNormClassifier */ diff --git a/classify/adaptmatch.h b/classify/adaptmatch.h index 9d1f60a..8ff2ab8 100644 --- a/classify/adaptmatch.h +++ b/classify/adaptmatch.h @@ -48,11 +48,6 @@ extern int LearningDebugLevel; void InitAdaptiveClassifierVars(); -void SettupPass1(); - -void SettupPass2(); - - int GetAdaptiveFeatures(TBLOB *Blob, LINE_STATS *LineStats, INT_FEATURE_ARRAY IntFeatures, diff --git a/classify/classify.cpp b/classify/classify.cpp index 09dfa5c..152f25f 100644 --- a/classify/classify.cpp +++ b/classify/classify.cpp @@ -54,6 +54,8 @@ void delete_callback_fs(FontSet fs) { namespace tesseract { Classify::Classify() : INT_MEMBER(tessedit_single_match, FALSE, "Top choice only from CP"), + BOOL_MEMBER(classify_enable_learning, true, "Enable adaptive classifier"), + EnableLearning(true), dict_(&image_) { fontinfo_table_.set_compare_callback( NewPermanentCallback(compare_fontinfo)); diff --git a/classify/classify.h b/classify/classify.h index 3c3d67c..04b6ae0 100644 --- a/classify/classify.h +++ b/classify/classify.h @@ -101,22 +101,22 @@ class Classify : public CCStruct { CLASS_ID ClassId, FLOAT32 Rating, int ConfigId); - #ifndef GRAPHICS_DISABLED +#ifndef GRAPHICS_DISABLED void DebugAdaptiveClassifier(TBLOB *Blob, LINE_STATS *LineStats, ADAPT_RESULTS *Results); - #endif - void - GetAdaptThresholds (TWERD * Word, - LINE_STATS * LineStats, - const WERD_CHOICE& BestChoice, - const WERD_CHOICE& BestRawChoice, FLOAT32 Thresholds[]); +#endif + void GetAdaptThresholds (TWERD * Word, + LINE_STATS * LineStats, + const WERD_CHOICE& BestChoice, + const WERD_CHOICE& BestRawChoice, + FLOAT32 Thresholds[]); -int MakeNewTemporaryConfig(ADAPT_TEMPLATES Templates, - CLASS_ID ClassId, - int NumFeatures, - INT_FEATURE_ARRAY Features, - FEATURE_SET FloatFeatures); + int MakeNewTemporaryConfig(ADAPT_TEMPLATES Templates, + CLASS_ID ClassId, + int NumFeatures, + INT_FEATURE_ARRAY Features, + FEATURE_SET FloatFeatures); void MakePermanent(ADAPT_TEMPLATES Templates, CLASS_ID ClassId, int ConfigId, @@ -134,10 +134,10 @@ int MakeNewTemporaryConfig(ADAPT_TEMPLATES Templates, LINE_STATS *LineStats, ADAPT_TEMPLATES Templates, ADAPT_RESULTS *Results); - void CharNormClassifier(TBLOB *Blob, - LINE_STATS *LineStats, - INT_TEMPLATES Templates, - ADAPT_RESULTS *Results); + int CharNormClassifier(TBLOB *Blob, + LINE_STATS *LineStats, + INT_TEMPLATES Templates, + ADAPT_RESULTS *Results); UNICHAR_ID *GetAmbiguities(TBLOB *Blob, LINE_STATS *LineStats, CLASS_ID CorrectClass); @@ -153,6 +153,8 @@ int MakeNewTemporaryConfig(ADAPT_TEMPLATES Templates, const WERD_CHOICE &RawChoiceWord); void EndAdaptiveClassifier(); void PrintAdaptiveStatistics(FILE *File); + void SettupPass1(); + void SettupPass2(); void AdaptiveClassifier(TBLOB *Blob, TBLOB *DotBlob, TEXTROW *Row, @@ -207,6 +209,10 @@ int MakeNewTemporaryConfig(ADAPT_TEMPLATES Templates, BIT_VECTOR AllProtosOff; BIT_VECTOR AllConfigsOff; BIT_VECTOR TempProtoMask; + // External control of adaption. + BOOL_VAR_H(classify_enable_learning, true, "Enable adaptive classifier"); + // Internal control of Adaption so it doesn't work on pass2. + bool EnableLearning; /* normmatch.cpp */ NORM_PROTOS *NormProtos; /* font detection ***********************************************************/ diff --git a/classify/intproto.h b/classify/intproto.h index ca643fe..04dffdc 100644 --- a/classify/intproto.h +++ b/classify/intproto.h @@ -157,16 +157,14 @@ INT_TEMPLATES_STRUCT, *INT_TEMPLATES; #define MAX_NUM_INT_FEATURES 512 #define INT_CHAR_NORM_RANGE 256 -typedef struct +struct INT_FEATURE_STRUCT { uinT8 X; uinT8 Y; uinT8 Theta; inT8 CP_misses; -} - +}; -INT_FEATURE_STRUCT; typedef INT_FEATURE_STRUCT *INT_FEATURE; typedef INT_FEATURE_STRUCT INT_FEATURE_ARRAY[MAX_NUM_INT_FEATURES]; diff --git a/dict/dawg.cpp b/dict/dawg.cpp index 72e8c5f..670103f 100644 --- a/dict/dawg.cpp +++ b/dict/dawg.cpp @@ -63,18 +63,6 @@ EDGE_REF edge_char_of(EDGE_ARRAY dawg, if (edge_occupied (dawg, edge)) { do { -#if 0 - // TODO(rays) Turn dawg to a class so this can be used properly. - // The maximum value of edge is unknown to this function, but could - // easily be stored in a dawg class. - if ((edge < 0 || edge >= MAX_NUM_EDGES_IN_SQUISHED_DAWG_FILE) - && edge != NO_EDGE) { - tprintf("Impossible return from edge_char_of: node=" REFFORMAT - ", ch=%d, edge=" REFFORMAT "\n", *node, - static_cast<unsigned char>(dummy_word[char_index]), edge); - return NO_EDGE; - } -#endif if ((edge_letter (dawg, edge) == character) && (! word_end || end_of_word(dawg,edge))) return (edge); diff --git a/dict/dict.h b/dict/dict.h index 57eeb1d..6791fdb 100644 --- a/dict/dict.h +++ b/dict/dict.h @@ -98,8 +98,7 @@ class Dict EDGE_ARRAY dawg, char permuter, CHOICES_LIST character_choices, - A_CHOICE *best_choice, - inT16 system_words); + A_CHOICE *best_choice); void adjust_word(A_CHOICE *best_choice, float *certainty_array); /* permute.cpp *************************************************************/ diff --git a/dict/permdawg.cpp b/dict/permdawg.cpp index dca7004..13c7165 100644 --- a/dict/permdawg.cpp +++ b/dict/permdawg.cpp @@ -239,8 +239,13 @@ void Dict::append_next_choice( /*previous option */ adjust_word(better_choice, certainty_array); push_on(*result, better_choice); - set_hyphen_word(word, unichar_lengths, unichar_offsets, - rating, node, char_choice_index, fragment_lengths); + if (permuter == SYSTEM_DAWG_PERM) { + // Until dawg is a class, it is only safe to use set_hyphen_word + // on a single dawg type, as it saves permuter state to use on another + // word in hyphen_state, and this *must* apply to the same dawg. + set_hyphen_word(word, unichar_lengths, unichar_offsets, + rating, node, char_choice_index, fragment_lengths); + } } /* Look up char in DAWG */ else { @@ -369,8 +374,7 @@ void Dict::dawg_permute_and_select(const char *string, EDGE_ARRAY dawg, char permuter, CHOICES_LIST character_choices, - A_CHOICE *best_choice, - inT16 system_words) { + A_CHOICE *best_choice) { CHOICES result = NIL; char word[UNICHAR_LEN * MAX_WERD_LENGTH + 1]; char unichar_lengths[MAX_WERD_LENGTH + 1]; @@ -408,7 +412,10 @@ void Dict::dawg_permute_and_select(const char *string, unichar_lengths[hyphen_base_size() - 1]; char_choice_index = hyphen_char_choice_size(); word_index = strlen (hyphen_unichar_lengths); - if (system_words) + if (permuter == SYSTEM_DAWG_PERM) + // Until dawg is a class, it is only safe to use set_hyphen_word + // on a single dawg type, as it saves permuter state to use on another + // word in hyphen_state, and this *must* apply to the same dawg. dawg_node = hyphen_state; } diff --git a/dict/permute.cpp b/dict/permute.cpp index 1b12fc7..7079e97 100644 --- a/dict/permute.cpp +++ b/dict/permute.cpp @@ -1681,15 +1681,14 @@ A_CHOICE *Dict::permute_words(CHOICES_LIST char_choices, float rating_limit) { } else { - dawg_permute_and_select ("system words:", word_dawg, SYSTEM_DAWG_PERM, - char_choices, best_choice, TRUE); + dawg_permute_and_select("system words:", word_dawg, SYSTEM_DAWG_PERM, + char_choices, best_choice); - dawg_permute_and_select ("document_words", document_words, - DOC_DAWG_PERM, char_choices, best_choice, - FALSE); + dawg_permute_and_select("document_words", document_words, + DOC_DAWG_PERM, char_choices, best_choice); - dawg_permute_and_select ("user words", user_words, USER_DAWG_PERM, - char_choices, best_choice, FALSE); + dawg_permute_and_select("user words", user_words, USER_DAWG_PERM, + char_choices, best_choice); } return (best_choice); diff --git a/wordrec/tface.cpp b/wordrec/tface.cpp index 1ce840d..0fd43a4 100644 --- a/wordrec/tface.cpp +++ b/wordrec/tface.cpp @@ -198,7 +198,6 @@ void Wordrec::program_editdown(inT32 elasped_time) { getDict().end_permute(); free_variables(); } -} // namespace tesseract /********************************************************************** @@ -206,7 +205,7 @@ void Wordrec::program_editdown(inT32 elasped_time) { * * Get ready to do some pass 1 stuff. **********************************************************************/ -void set_pass1() { +void Wordrec::set_pass1() { blob_skip = FALSE; ok_split = 70.0; num_seg_states = 15; @@ -220,7 +219,7 @@ void set_pass1() { * * Get ready to do some pass 2 stuff. **********************************************************************/ -void set_pass2() { +void Wordrec::set_pass2() { blob_skip = FALSE; ok_split = pass2_ok_split; num_seg_states = pass2_seg_states; @@ -234,7 +233,6 @@ void set_pass2() { * * Recognize a word. **********************************************************************/ -namespace tesseract { BLOB_CHOICE_LIST_VECTOR *Wordrec::cc_recog(TWERD *tessword, WERD_CHOICE *best_choice, WERD_CHOICE *best_raw_choice, diff --git a/wordrec/tface.h b/wordrec/tface.h index 681fd4f..a62de84 100644 --- a/wordrec/tface.h +++ b/wordrec/tface.h @@ -11,8 +11,4 @@ ----------------------------------------------------------------------------*/ void edit_with_ocr(const char *imagename); -void set_pass1(); - -void set_pass2(); - #endif diff --git a/wordrec/wordrec.h b/wordrec/wordrec.h index 0f30e21..886f092 100644 --- a/wordrec/wordrec.h +++ b/wordrec/wordrec.h @@ -42,6 +42,8 @@ class Wordrec : public Classify { BOOL8 tester, BOOL8 trainer); void program_editdown(inT32 elasped_time); + void set_pass1(); + void set_pass2(); int end_recog(); int start_recog(const char *configfile, const char *textbase); BLOB_CHOICE_LIST *call_matcher( //call a matcher |