aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2008-10-02 11:06:36 -0700
committerIliyan Malchev <malchev@google.com>2008-10-09 14:27:53 -0700
commit6c98ac770461cc841619984aa4003f4b835949a8 (patch)
treed5b03f339f00bedfa5f3c85c3fb460f7d24d933a
parentad76e2d027e090acc9c39ba94633a00875124946 (diff)
downloadtesseract-6c98ac770461cc841619984aa4003f4b835949a8.tar.gz
8370000
Signed-off-by: Iliyan Malchev <malchev@google.com>
-rw-r--r--ccmain/baseapi.cpp87
-rw-r--r--ccmain/baseapi.h9
-rw-r--r--ccmain/tesseractmain.cpp4
-rw-r--r--classify/adaptmatch.cpp30
-rw-r--r--classify/adaptmatch.h5
-rw-r--r--classify/classify.cpp2
-rw-r--r--classify/classify.h38
-rw-r--r--classify/intproto.h6
-rw-r--r--dict/dawg.cpp12
-rw-r--r--dict/dict.h3
-rw-r--r--dict/permdawg.cpp17
-rw-r--r--dict/permute.cpp13
-rw-r--r--wordrec/tface.cpp6
-rw-r--r--wordrec/tface.h4
-rw-r--r--wordrec/wordrec.h2
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