Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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 {
26 CubeObject::CubeObject(CubeRecoContext *cntxt, CharSamp *char_samp) {
27 Init();
28 char_samp_ = char_samp;
29 cntxt_ = cntxt;
30 }
31
32 CubeObject::CubeObject(CubeRecoContext *cntxt, IMAGE *img,
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
40 CubeObject::CubeObject(CubeRecoContext *cntxt, Pix *pix,
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
76 CubeObject::~CubeObject() {
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
209 WordAltList *CubeObject::RecognizeWord(LangModel *lang_mod) {
210 return Recognize(lang_mod, true);
211 }
212
213 // Recognize the member char sample as a word
214 WordAltList *CubeObject::RecognizePhrase(LangModel *lang_mod) {
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.
246 CharAltList *CubeObject::RecognizeChar() {
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
256 bool CubeObject::Normalize() {
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 }