Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cube_object.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: cube_object.cpp
3  * Description: Implementation of the Cube Object Class
4  * Author: Ahmad Abdulkader
5  * Created: 2007
6  *
7  * (C) Copyright 2008, Google Inc.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include <math.h>
21 #include "cube_object.h"
22 #include "cube_utils.h"
23 #include "word_list_lang_model.h"
24 
25 namespace tesseract {
27  Init();
28  char_samp_ = char_samp;
29  cntxt_ = cntxt;
30 }
31 
33  int left, int top, int wid, int hgt) {
34  Init();
35  char_samp_ = CubeUtils::CharSampleFromImg(img, left, top, wid, hgt);
36  own_char_samp_ = true;
37  cntxt_ = cntxt;
38 }
39 
41  int left, int top, int wid, int hgt) {
42  Init();
43  char_samp_ = CubeUtils::CharSampleFromPix(pix, left, top, wid, hgt);
44  own_char_samp_ = true;
45  cntxt_ = cntxt;
46 }
47 
48 // Data member initialization function
49 void CubeObject::Init() {
50  char_samp_ = NULL;
51  own_char_samp_ = false;
52  alt_list_ = NULL;
53  srch_obj_ = NULL;
54  deslanted_alt_list_ = NULL;
55  deslanted_srch_obj_ = NULL;
56  deslanted_ = false;
57  deslanted_char_samp_ = NULL;
58  beam_obj_ = NULL;
59  deslanted_beam_obj_ = NULL;
60  cntxt_ = NULL;
61 }
62 
63 // Cleanup function
64 void CubeObject::Cleanup() {
65  if (alt_list_ != NULL) {
66  delete alt_list_;
67  alt_list_ = NULL;
68  }
69 
70  if (deslanted_alt_list_ != NULL) {
71  delete deslanted_alt_list_;
72  deslanted_alt_list_ = NULL;
73  }
74 }
75 
77  if (char_samp_ != NULL && own_char_samp_ == true) {
78  delete char_samp_;
79  char_samp_ = NULL;
80  }
81 
82  if (srch_obj_ != NULL) {
83  delete srch_obj_;
84  srch_obj_ = NULL;
85  }
86 
87  if (deslanted_srch_obj_ != NULL) {
88  delete deslanted_srch_obj_;
89  deslanted_srch_obj_ = NULL;
90  }
91 
92  if (beam_obj_ != NULL) {
93  delete beam_obj_;
94  beam_obj_ = NULL;
95  }
96 
97  if (deslanted_beam_obj_ != NULL) {
98  delete deslanted_beam_obj_;
99  deslanted_beam_obj_ = NULL;
100  }
101 
102  if (deslanted_char_samp_ != NULL) {
103  delete deslanted_char_samp_;
104  deslanted_char_samp_ = NULL;
105  }
106 
107  Cleanup();
108 }
109 
110 // Actually do the recognition using the specified language mode. If none
111 // is specified, the default language model in the CubeRecoContext is used.
112 // Returns the sorted list of alternate answers
113 // The Word mode determines whether recognition is done as a word or a phrase
114 WordAltList *CubeObject::Recognize(LangModel *lang_mod, bool word_mode) {
115  if (char_samp_ == NULL) {
116  return NULL;
117  }
118 
119  // clear alt lists
120  Cleanup();
121 
122  // no specified language model, use the one in the reco context
123  if (lang_mod == NULL) {
124  lang_mod = cntxt_->LangMod();
125  }
126 
127  // normalize if necessary
128  if (cntxt_->SizeNormalization()) {
129  Normalize();
130  }
131 
132  // assume not de-slanted by default
133  deslanted_ = false;
134 
135  // create a beam search object
136  if (beam_obj_ == NULL) {
137  beam_obj_ = new BeamSearch(cntxt_, word_mode);
138  if (beam_obj_ == NULL) {
139  fprintf(stderr, "Cube ERROR (CubeObject::Recognize): could not construct "
140  "BeamSearch\n");
141  return NULL;
142  }
143  }
144 
145  // create a cube search object
146  if (srch_obj_ == NULL) {
147  srch_obj_ = new CubeSearchObject(cntxt_, char_samp_);
148  if (srch_obj_ == NULL) {
149  fprintf(stderr, "Cube ERROR (CubeObject::Recognize): could not construct "
150  "CubeSearchObject\n");
151  return NULL;
152  }
153  }
154 
155  // run a beam search against the tesslang model
156  alt_list_ = beam_obj_->Search(srch_obj_, lang_mod);
157 
158  // deslant (if supported by language) and re-reco if probability is low enough
159  if (cntxt_->HasItalics() == true &&
160  (alt_list_ == NULL || alt_list_->AltCount() < 1 ||
161  alt_list_->AltCost(0) > CubeUtils::Prob2Cost(kMinProbSkipDeslanted))) {
162 
163  if (deslanted_beam_obj_ == NULL) {
164  deslanted_beam_obj_ = new BeamSearch(cntxt_);
165  if (deslanted_beam_obj_ == NULL) {
166  fprintf(stderr, "Cube ERROR (CubeObject::Recognize): could not "
167  "construct deslanted BeamSearch\n");
168  return false;
169  }
170  }
171 
172  if (deslanted_srch_obj_ == NULL) {
173  deslanted_char_samp_ = char_samp_->Clone();
174  if (deslanted_char_samp_ == NULL) {
175  fprintf(stderr, "Cube ERROR (CubeObject::Recognize): could not "
176  "construct deslanted CharSamp\n");
177  return NULL;
178  }
179 
180  if (deslanted_char_samp_->Deslant() == false) {
181  return NULL;
182  }
183 
184  deslanted_srch_obj_ = new CubeSearchObject(cntxt_, deslanted_char_samp_);
185  if (deslanted_srch_obj_ == NULL) {
186  fprintf(stderr, "Cube ERROR (CubeObject::Recognize): could not "
187  "construct deslanted CubeSearchObject\n");
188  return NULL;
189  }
190  }
191 
192  // run a beam search against the tesslang model
193  deslanted_alt_list_ = deslanted_beam_obj_->Search(deslanted_srch_obj_,
194  lang_mod);
195  // should we use de-slanted altlist?
196  if (deslanted_alt_list_ != NULL && deslanted_alt_list_->AltCount() > 0) {
197  if (alt_list_ == NULL || alt_list_->AltCount() < 1 ||
198  deslanted_alt_list_->AltCost(0) < alt_list_->AltCost(0)) {
199  deslanted_ = true;
200  return deslanted_alt_list_;
201  }
202  }
203  }
204 
205  return alt_list_;
206 }
207 
208 // Recognize the member char sample as a word
210  return Recognize(lang_mod, true);
211 }
212 
213 // Recognize the member char sample as a word
215  return Recognize(lang_mod, false);
216 }
217 
218 // Computes the cost of a specific string. This is done by performing
219 // recognition of a language model that allows only the specified word
220 int CubeObject::WordCost(const char *str) {
221  WordListLangModel *lang_mod = new WordListLangModel(cntxt_);
222  if (lang_mod == NULL) {
223  return WORST_COST;
224  }
225 
226  if (lang_mod->AddString(str) == false) {
227  delete lang_mod;
228  return WORST_COST;
229  }
230 
231  // run a beam search against the single string wordlist model
232  WordAltList *alt_list = RecognizeWord(lang_mod);
233  delete lang_mod;
234 
235  int cost = WORST_COST;
236  if (alt_list != NULL) {
237  if (alt_list->AltCount() > 0) {
238  cost = alt_list->AltCost(0);
239  }
240  }
241 
242  return cost;
243 }
244 
245 // Recognizes a single character and returns the list of results.
247  if (char_samp_ == NULL) return NULL;
248  CharAltList* alt_list = NULL;
249  CharClassifier *char_classifier = cntxt_->Classifier();
250  ASSERT_HOST(char_classifier != NULL);
251  alt_list = char_classifier->Classify(char_samp_);
252  return alt_list;
253 }
254 
255 // Normalize the input word bitmap to have a minimum aspect ratio
257  // create a cube search object
258  CubeSearchObject *srch_obj = new CubeSearchObject(cntxt_, char_samp_);
259  if (srch_obj == NULL) {
260  return false;
261  }
262  // Perform over-segmentation
263  int seg_cnt = srch_obj->SegPtCnt();
264  // Only perform normalization if segment count is large enough
265  if (seg_cnt < kMinNormalizationSegmentCnt) {
266  delete srch_obj;
267  return true;
268  }
269  // compute the mean AR of the segments
270  double ar_mean = 0.0;
271  for (int seg_idx = 0; seg_idx <= seg_cnt; seg_idx++) {
272  CharSamp *seg_samp = srch_obj->CharSample(seg_idx - 1, seg_idx);
273  if (seg_samp != NULL && seg_samp->Width() > 0) {
274  ar_mean += (1.0 * seg_samp->Height() / seg_samp->Width());
275  }
276  }
277  ar_mean /= (seg_cnt + 1);
278  // perform normalization if segment AR is too high
279  if (ar_mean > kMinNormalizationAspectRatio) {
280  // scale down the image in the y-direction to attain AR
281  CharSamp *new_samp = char_samp_->Scale(char_samp_->Width(),
282  2.0 * char_samp_->Height() / ar_mean,
283  false);
284  if (new_samp != NULL) {
285  // free existing char samp if owned
286  if (own_char_samp_) {
287  delete char_samp_;
288  }
289  // update with new scaled charsamp and set ownership flag
290  char_samp_ = new_samp;
291  own_char_samp_ = true;
292  }
293  }
294  delete srch_obj;
295  return true;
296 }
297 }