tesseract  3.04.01
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
imagedata.cpp
Go to the documentation of this file.
1 // File: imagedata.h
3 // Description: Class to hold information about a single multi-page tiff
4 // training file and its corresponding boxes or text file.
5 // Author: Ray Smith
6 // Created: Tue May 28 08:56:06 PST 2013
7 //
8 // (C) Copyright 2013, Google Inc.
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 
20 // Include automatically generated configuration file if running autoconf.
21 #ifdef HAVE_CONFIG_H
22 #include "config_auto.h"
23 #endif
24 
25 #include "imagedata.h"
26 
27 #include "allheaders.h"
28 #include "boxread.h"
29 #include "callcpp.h"
30 #include "helpers.h"
31 #include "tprintf.h"
32 
33 namespace tesseract {
34 
35 WordFeature::WordFeature() : x_(0), y_(0), dir_(0) {
36 }
37 
39  : x_(IntCastRounded(fcoord.x())),
40  y_(ClipToRange(IntCastRounded(fcoord.y()), 0, MAX_UINT8)),
41  dir_(dir) {
42 }
43 
44 // Computes the maximum x and y value in the features.
46  int* max_x, int* max_y) {
47  *max_x = 0;
48  *max_y = 0;
49  for (int f = 0; f < features.size(); ++f) {
50  if (features[f].x_ > *max_x) *max_x = features[f].x_;
51  if (features[f].y_ > *max_y) *max_y = features[f].y_;
52  }
53 }
54 
55 // Draws the features in the given window.
57  ScrollView* window) {
58 #ifndef GRAPHICS_DISABLED
59  for (int f = 0; f < features.size(); ++f) {
60  FCOORD pos(features[f].x_, features[f].y_);
61  FCOORD dir;
62  dir.from_direction(features[f].dir_);
63  dir *= 8.0f;
64  window->SetCursor(IntCastRounded(pos.x() - dir.x()),
65  IntCastRounded(pos.y() - dir.y()));
66  window->DrawTo(IntCastRounded(pos.x() + dir.x()),
67  IntCastRounded(pos.y() + dir.y()));
68  }
69 #endif
70 }
71 
72 // Writes to the given file. Returns false in case of error.
73 bool WordFeature::Serialize(FILE* fp) const {
74  if (fwrite(&x_, sizeof(x_), 1, fp) != 1) return false;
75  if (fwrite(&y_, sizeof(y_), 1, fp) != 1) return false;
76  if (fwrite(&dir_, sizeof(dir_), 1, fp) != 1) return false;
77  return true;
78 }
79 // Reads from the given file. Returns false in case of error.
80 // If swap is true, assumes a big/little-endian swap is needed.
81 bool WordFeature::DeSerialize(bool swap, FILE* fp) {
82  if (fread(&x_, sizeof(x_), 1, fp) != 1) return false;
83  if (swap) ReverseN(&x_, sizeof(x_));
84  if (fread(&y_, sizeof(y_), 1, fp) != 1) return false;
85  if (fread(&dir_, sizeof(dir_), 1, fp) != 1) return false;
86  return true;
87 }
88 
90  const GenericVector<WordFeature>& word_features,
91  GenericVector<FloatWordFeature>* float_features) {
92  for (int i = 0; i < word_features.size(); ++i) {
94  f.x = word_features[i].x();
95  f.y = word_features[i].y();
96  f.dir = word_features[i].dir();
97  f.x_bucket = 0; // Will set it later.
98  float_features->push_back(f);
99  }
100 }
101 
102 // Sort function to sort first by x-bucket, then by y.
103 /* static */
104 int FloatWordFeature::SortByXBucket(const void* v1, const void* v2) {
105  const FloatWordFeature* f1 = reinterpret_cast<const FloatWordFeature*>(v1);
106  const FloatWordFeature* f2 = reinterpret_cast<const FloatWordFeature*>(v2);
107  int x_diff = f1->x_bucket - f2->x_bucket;
108  if (x_diff == 0) return f1->y - f2->y;
109  return x_diff;
110 }
111 
112 ImageData::ImageData() : page_number_(-1), vertical_text_(false) {
113 }
114 // Takes ownership of the pix and destroys it.
115 ImageData::ImageData(bool vertical, Pix* pix)
116  : page_number_(0), vertical_text_(vertical) {
117  SetPix(pix);
118 }
120 }
121 
122 // Builds and returns an ImageData from the basic data. Note that imagedata,
123 // truth_text, and box_text are all the actual file data, NOT filenames.
124 ImageData* ImageData::Build(const char* name, int page_number, const char* lang,
125  const char* imagedata, int imagedatasize,
126  const char* truth_text, const char* box_text) {
127  ImageData* image_data = new ImageData();
128  image_data->imagefilename_ = name;
129  image_data->page_number_ = page_number;
130  image_data->language_ = lang;
131  // Save the imagedata.
132  image_data->image_data_.init_to_size(imagedatasize, 0);
133  memcpy(&image_data->image_data_[0], imagedata, imagedatasize);
134  if (!image_data->AddBoxes(box_text)) {
135  if (truth_text == NULL || truth_text[0] == '\0') {
136  tprintf("Error: No text corresponding to page %d from image %s!\n",
137  page_number, name);
138  delete image_data;
139  return NULL;
140  }
141  image_data->transcription_ = truth_text;
142  // If we have no boxes, the transcription is in the 0th box_texts_.
143  image_data->box_texts_.push_back(truth_text);
144  // We will create a box for the whole image on PreScale, to save unpacking
145  // the image now.
146  } else if (truth_text != NULL && truth_text[0] != '\0' &&
147  image_data->transcription_ != truth_text) {
148  // Save the truth text as it is present and disagrees with the box text.
149  image_data->transcription_ = truth_text;
150  }
151  return image_data;
152 }
153 
154 // Writes to the given file. Returns false in case of error.
155 bool ImageData::Serialize(TFile* fp) const {
156  if (!imagefilename_.Serialize(fp)) return false;
157  if (fp->FWrite(&page_number_, sizeof(page_number_), 1) != 1) return false;
158  if (!image_data_.Serialize(fp)) return false;
159  if (!transcription_.Serialize(fp)) return false;
160  // WARNING: Will not work across different endian machines.
161  if (!boxes_.Serialize(fp)) return false;
162  if (!box_texts_.SerializeClasses(fp)) return false;
163  inT8 vertical = vertical_text_;
164  if (fp->FWrite(&vertical, sizeof(vertical), 1) != 1) return false;
165  return true;
166 }
167 
168 // Reads from the given file. Returns false in case of error.
169 // If swap is true, assumes a big/little-endian swap is needed.
170 bool ImageData::DeSerialize(bool swap, TFile* fp) {
171  if (!imagefilename_.DeSerialize(swap, fp)) return false;
172  if (fp->FRead(&page_number_, sizeof(page_number_), 1) != 1) return false;
173  if (swap) ReverseN(&page_number_, sizeof(page_number_));
174  if (!image_data_.DeSerialize(swap, fp)) return false;
175  if (!transcription_.DeSerialize(swap, fp)) return false;
176  // WARNING: Will not work across different endian machines.
177  if (!boxes_.DeSerialize(swap, fp)) return false;
178  if (!box_texts_.DeSerializeClasses(swap, fp)) return false;
179  inT8 vertical = 0;
180  if (fp->FRead(&vertical, sizeof(vertical), 1) != 1) return false;
181  vertical_text_ = vertical != 0;
182  return true;
183 }
184 
185 // Saves the given Pix as a PNG-encoded string and destroys it.
186 void ImageData::SetPix(Pix* pix) {
187  SetPixInternal(pix, &image_data_);
188 }
189 
190 // Returns the Pix image for *this. Must be pixDestroyed after use.
191 Pix* ImageData::GetPix() const {
192  return GetPixInternal(image_data_);
193 }
194 
195 // Gets anything and everything with a non-NULL pointer, prescaled to a
196 // given target_height (if 0, then the original image height), and aligned.
197 // Also returns (if not NULL) the width and height of the scaled image.
198 // The return value is the scale factor that was applied to the image to
199 // achieve the target_height.
200 float ImageData::PreScale(int target_height, Pix** pix,
201  int* scaled_width, int* scaled_height,
202  GenericVector<TBOX>* boxes) const {
203  int input_width = 0;
204  int input_height = 0;
205  Pix* src_pix = GetPix();
206  ASSERT_HOST(src_pix != NULL);
207  input_width = pixGetWidth(src_pix);
208  input_height = pixGetHeight(src_pix);
209  if (target_height == 0)
210  target_height = input_height;
211  float im_factor = static_cast<float>(target_height) / input_height;
212  if (scaled_width != NULL)
213  *scaled_width = IntCastRounded(im_factor * input_width);
214  if (scaled_height != NULL)
215  *scaled_height = target_height;
216  if (pix != NULL) {
217  // Get the scaled image.
218  pixDestroy(pix);
219  *pix = pixScale(src_pix, im_factor, im_factor);
220  if (*pix == NULL) {
221  tprintf("Scaling pix of size %d, %d by factor %g made null pix!!\n",
222  input_width, input_height, im_factor);
223  }
224  if (scaled_width != NULL)
225  *scaled_width = pixGetWidth(*pix);
226  if (scaled_height != NULL)
227  *scaled_height = pixGetHeight(*pix);
228  }
229  pixDestroy(&src_pix);
230  if (boxes != NULL) {
231  // Get the boxes.
232  boxes->truncate(0);
233  for (int b = 0; b < boxes_.size(); ++b) {
234  TBOX box = boxes_[b];
235  box.scale(im_factor);
236  boxes->push_back(box);
237  }
238  if (boxes->empty()) {
239  // Make a single box for the whole image.
240  TBOX box(0, 0, im_factor * input_width, target_height);
241  boxes->push_back(box);
242  }
243  }
244  return im_factor;
245 }
246 
248  return image_data_.size();
249 }
250 
251 // Draws the data in a new window.
252 void ImageData::Display() const {
253 #ifndef GRAPHICS_DISABLED
254  const int kTextSize = 64;
255  // Draw the image.
256  Pix* pix = GetPix();
257  if (pix == NULL) return;
258  int width = pixGetWidth(pix);
259  int height = pixGetHeight(pix);
260  ScrollView* win = new ScrollView("Imagedata", 100, 100,
261  2 * (width + 2 * kTextSize),
262  2 * (height + 4 * kTextSize),
263  width + 10, height + 3 * kTextSize, true);
264  win->Image(pix, 0, height - 1);
265  pixDestroy(&pix);
266  // Draw the boxes.
267  win->Pen(ScrollView::RED);
268  win->Brush(ScrollView::NONE);
269  win->TextAttributes("Arial", kTextSize, false, false, false);
270  for (int b = 0; b < boxes_.size(); ++b) {
271  boxes_[b].plot(win);
272  win->Text(boxes_[b].left(), height + kTextSize, box_texts_[b].string());
273  TBOX scaled(boxes_[b]);
274  scaled.scale(256.0 / height);
275  scaled.plot(win);
276  }
277  // The full transcription.
278  win->Pen(ScrollView::CYAN);
279  win->Text(0, height + kTextSize * 2, transcription_.string());
280  // Add the features.
281  win->Pen(ScrollView::GREEN);
282  win->Update();
283  window_wait(win);
284 #endif
285 }
286 
287 // Adds the supplied boxes and transcriptions that correspond to the correct
288 // page number.
290  const GenericVector<STRING>& texts,
291  const GenericVector<int>& box_pages) {
292  // Copy the boxes and make the transcription.
293  for (int i = 0; i < box_pages.size(); ++i) {
294  if (page_number_ >= 0 && box_pages[i] != page_number_) continue;
295  transcription_ += texts[i];
296  boxes_.push_back(boxes[i]);
297  box_texts_.push_back(texts[i]);
298  }
299 }
300 
301 // Saves the given Pix as a PNG-encoded string and destroys it.
302 void ImageData::SetPixInternal(Pix* pix, GenericVector<char>* image_data) {
303  l_uint8* data;
304  size_t size;
305  pixWriteMem(&data, &size, pix, IFF_PNG);
306  pixDestroy(&pix);
307  image_data->init_to_size(size, 0);
308  memcpy(&(*image_data)[0], data, size);
309  free(data);
310 }
311 
312 // Returns the Pix image for the image_data. Must be pixDestroyed after use.
313 Pix* ImageData::GetPixInternal(const GenericVector<char>& image_data) {
314  Pix* pix = NULL;
315  if (!image_data.empty()) {
316  // Convert the array to an image.
317  const unsigned char* u_data =
318  reinterpret_cast<const unsigned char*>(&image_data[0]);
319  pix = pixReadMem(u_data, image_data.size());
320  }
321  return pix;
322 }
323 
324 // Parses the text string as a box file and adds any discovered boxes that
325 // match the page number. Returns false on error.
326 bool ImageData::AddBoxes(const char* box_text) {
327  if (box_text != NULL && box_text[0] != '\0') {
329  GenericVector<STRING> texts;
330  GenericVector<int> box_pages;
331  if (ReadMemBoxes(page_number_, false, box_text, &boxes,
332  &texts, NULL, &box_pages)) {
333  AddBoxes(boxes, texts, box_pages);
334  return true;
335  } else {
336  tprintf("Error: No boxes for page %d from image %s!\n",
337  page_number_, imagefilename_.string());
338  }
339  }
340  return false;
341 }
342 
344  : document_name_(name), pages_offset_(0), total_pages_(0),
345  memory_used_(0), max_memory_(0), reader_(NULL) {}
346 
348 
349 // Reads all the pages in the given lstmf filename to the cache. The reader
350 // is used to read the file.
351 bool DocumentData::LoadDocument(const char* filename, const char* lang,
352  int start_page, inT64 max_memory,
353  FileReader reader) {
354  document_name_ = filename;
355  lang_ = lang;
356  pages_offset_ = start_page;
357  max_memory_ = max_memory;
358  reader_ = reader;
359  return ReCachePages();
360 }
361 
362 // Writes all the pages to the given filename. Returns false on error.
363 bool DocumentData::SaveDocument(const char* filename, FileWriter writer) {
364  TFile fp;
365  fp.OpenWrite(NULL);
366  if (!pages_.Serialize(&fp) || !fp.CloseWrite(filename, writer)) {
367  tprintf("Serialize failed: %s\n", filename);
368  return false;
369  }
370  return true;
371 }
373  TFile fp;
374  fp.OpenWrite(buffer);
375  return pages_.Serialize(&fp);
376 }
377 
378 // Returns a pointer to the page with the given index, modulo the total
379 // number of pages, recaching if needed.
380 const ImageData* DocumentData::GetPage(int index) {
381  index = Modulo(index, total_pages_);
382  if (index < pages_offset_ || index >= pages_offset_ + pages_.size()) {
383  pages_offset_ = index;
384  if (!ReCachePages()) return NULL;
385  }
386  return pages_[index - pages_offset_];
387 }
388 
389 // Loads as many pages can fit in max_memory_ starting at index pages_offset_.
390 bool DocumentData::ReCachePages() {
391  // Read the file.
392  TFile fp;
393  if (!fp.Open(document_name_, reader_)) return false;
394  memory_used_ = 0;
395  if (!pages_.DeSerialize(false, &fp)) {
396  tprintf("Deserialize failed: %s\n", document_name_.string());
397  pages_.truncate(0);
398  return false;
399  }
400  total_pages_ = pages_.size();
401  pages_offset_ %= total_pages_;
402  // Delete pages before the first one we want, and relocate the rest.
403  int page;
404  for (page = 0; page < pages_.size(); ++page) {
405  if (page < pages_offset_) {
406  delete pages_[page];
407  pages_[page] = NULL;
408  } else {
409  ImageData* image_data = pages_[page];
410  if (max_memory_ > 0 && page > pages_offset_ &&
411  memory_used_ + image_data->MemoryUsed() > max_memory_)
412  break; // Don't go over memory quota unless the first image.
413  if (image_data->imagefilename().length() == 0) {
414  image_data->set_imagefilename(document_name_);
415  image_data->set_page_number(page);
416  }
417  image_data->set_language(lang_);
418  memory_used_ += image_data->MemoryUsed();
419  if (pages_offset_ != 0) {
420  pages_[page - pages_offset_] = image_data;
421  pages_[page] = NULL;
422  }
423  }
424  }
425  pages_.truncate(page - pages_offset_);
426  tprintf("Loaded %d/%d pages (%d-%d) of document %s\n",
427  pages_.size(), total_pages_, pages_offset_,
428  pages_offset_ + pages_.size(), document_name_.string());
429  return !pages_.empty();
430 }
431 
432 // Adds the given page data to this document, counting up memory.
434  pages_.push_back(page);
435  memory_used_ += page->MemoryUsed();
436 }
437 
438 // A collection of DocumentData that knows roughly how much memory it is using.
440  : total_pages_(0), memory_used_(0), max_memory_(max_memory) {}
442 
443 // Adds all the documents in the list of filenames, counting memory.
444 // The reader is used to read the files.
446  const char* lang, FileReader reader) {
447  inT64 fair_share_memory = max_memory_ / filenames.size();
448  for (int arg = 0; arg < filenames.size(); ++arg) {
449  STRING filename = filenames[arg];
450  DocumentData* document = new DocumentData(filename);
451  if (document->LoadDocument(filename.string(), lang, 0,
452  fair_share_memory, reader)) {
453  AddToCache(document);
454  } else {
455  tprintf("Failed to load image %s!\n", filename.string());
456  delete document;
457  }
458  }
459  tprintf("Loaded %d pages, total %gMB\n",
460  total_pages_, memory_used_ / 1048576.0);
461  return total_pages_ > 0;
462 }
463 
464 // Adds document to the cache, throwing out other documents if needed.
466  inT64 new_memory = data->memory_used();
467  memory_used_ += new_memory;
468  documents_.push_back(data);
469  total_pages_ += data->NumPages();
470  // Delete the first item in the array, and other pages of the same name
471  // while memory is full.
472  while (memory_used_ >= max_memory_ && max_memory_ > 0) {
473  tprintf("Memory used=%lld vs max=%lld, discarding doc of size %lld\n",
474  memory_used_ , max_memory_, documents_[0]->memory_used());
475  memory_used_ -= documents_[0]->memory_used();
476  total_pages_ -= documents_[0]->NumPages();
477  documents_.remove(0);
478  }
479  return true;
480 }
481 
482 // Finds and returns a document by name.
483 DocumentData* DocumentCache::FindDocument(const STRING& document_name) const {
484  for (int i = 0; i < documents_.size(); ++i) {
485  if (documents_[i]->document_name() == document_name)
486  return documents_[i];
487  }
488  return NULL;
489 }
490 
491 // Returns a page by serial number, selecting them in a round-robin fashion
492 // from all the documents.
494  int document_index = serial % documents_.size();
495  return documents_[document_index]->GetPage(serial / documents_.size());
496 }
497 
498 } // namespace tesseract.
bool DeSerialize(bool swap, FILE *fp)
Definition: strngs.cpp:163
int size() const
Definition: genericvector.h:72
void truncate(int size)
static ImageData * Build(const char *name, int page_number, const char *lang, const char *imagedata, int imagedatasize, const char *truth_text, const char *box_text)
Definition: imagedata.cpp:124
bool DeSerializeClasses(bool swap, FILE *fp)
bool ReadMemBoxes(int target_page, bool skip_blanks, const char *box_data, GenericVector< TBOX > *boxes, GenericVector< STRING > *texts, GenericVector< STRING > *box_texts, GenericVector< int > *pages)
Definition: boxread.cpp:64
bool(* FileReader)(const STRING &filename, GenericVector< char > *data)
bool DeSerialize(bool swap, TFile *fp)
Definition: imagedata.cpp:170
int IntCastRounded(double x)
Definition: helpers.h:172
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
float x() const
Definition: points.h:209
int push_back(T object)
#define tprintf(...)
Definition: tprintf.h:31
SIGNED char inT8
Definition: host.h:98
bool Serialize(FILE *fp) const
Definition: imagedata.cpp:73
void ReverseN(void *ptr, int num_bytes)
Definition: helpers.h:177
int MemoryUsed() const
Definition: imagedata.cpp:247
float PreScale(int target_height, Pix **pix, int *scaled_width, int *scaled_height, GenericVector< TBOX > *boxes) const
Definition: imagedata.cpp:200
bool Serialize(FILE *fp) const
void Brush(Color color)
Definition: scrollview.cpp:732
const ImageData * GetPageBySerial(int serial)
Definition: imagedata.cpp:493
void AddBoxes(const GenericVector< TBOX > &boxes, const GenericVector< STRING > &texts, const GenericVector< int > &box_pages)
Definition: imagedata.cpp:289
int NumPages() const
Definition: imagedata.h:205
const ImageData * GetPage(int index)
Definition: imagedata.cpp:380
int dir() const
Definition: imagedata.h:55
char window_wait(ScrollView *win)
Definition: callcpp.cpp:111
bool SerializeClasses(FILE *fp) const
static void Draw(const GenericVector< WordFeature > &features, ScrollView *window)
Definition: imagedata.cpp:56
bool SaveDocument(const char *filename, FileWriter writer)
Definition: imagedata.cpp:363
void Image(struct Pix *image, int x_pos, int y_pos)
Definition: scrollview.cpp:773
bool Serialize(FILE *fp) const
Definition: strngs.cpp:148
void init_to_size(int size, T t)
bool DeSerialize(bool swap, FILE *fp)
DocumentCache(inT64 max_memory)
Definition: imagedata.cpp:439
void OpenWrite(GenericVector< char > *data)
Definition: serialis.cpp:109
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:658
void DrawTo(int x, int y)
Definition: scrollview.cpp:531
bool DeSerialize(bool swap, FILE *fp)
Definition: imagedata.cpp:81
Pix * GetPix() const
Definition: imagedata.cpp:191
void Pen(Color color)
Definition: scrollview.cpp:726
bool LoadDocuments(const GenericVector< STRING > &filenames, const char *lang, FileReader reader)
Definition: imagedata.cpp:445
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:641
void SetPix(Pix *pix)
Definition: imagedata.cpp:186
DocumentData * FindDocument(const STRING &document_name) const
Definition: imagedata.cpp:483
bool CloseWrite(const STRING &filename, FileWriter writer)
Definition: serialis.cpp:123
long long int inT64
Definition: host.h:108
void AddPageToDocument(ImageData *page)
Definition: imagedata.cpp:433
bool empty() const
Definition: genericvector.h:84
void Display() const
Definition: imagedata.cpp:252
void from_direction(uinT8 direction)
Definition: points.cpp:115
int page_number() const
Definition: imagedata.h:114
static int SortByXBucket(const void *, const void *)
Definition: imagedata.cpp:104
Definition: rect.h:30
const GenericVector< TBOX > & boxes() const
Definition: imagedata.h:132
float y() const
Definition: points.h:212
bool AddToCache(DocumentData *data)
Definition: imagedata.cpp:465
int Modulo(int a, int b)
Definition: helpers.h:157
DocumentData(const STRING &name)
Definition: imagedata.cpp:343
name_table name
#define MAX_UINT8
Definition: host.h:121
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:115
Definition: strngs.h:44
unsigned char uinT8
Definition: host.h:99
int FWrite(const void *buffer, int size, int count)
Definition: serialis.cpp:131
inT64 memory_used() const
Definition: imagedata.h:208
const GenericVector< char > & image_data() const
Definition: imagedata.h:120
bool(* FileWriter)(const GenericVector< char > &data, const STRING &filename)
const char * string() const
Definition: strngs.cpp:193
static void ComputeSize(const GenericVector< WordFeature > &features, int *max_x, int *max_y)
Definition: imagedata.cpp:45
bool SaveToBuffer(GenericVector< char > *buffer)
Definition: imagedata.cpp:372
static void Update()
Definition: scrollview.cpp:715
#define ASSERT_HOST(x)
Definition: errcode.h:84
Definition: points.h:189
bool LoadDocument(const char *filename, const char *lang, int start_page, inT64 max_memory, FileReader reader)
Definition: imagedata.cpp:351
bool Serialize(TFile *fp) const
Definition: imagedata.cpp:155
bool Open(const STRING &filename, FileReader reader)
Definition: serialis.cpp:35
void scale(const float f)
Definition: rect.h:171
int FRead(void *buffer, int size, int count)
Definition: serialis.cpp:91
static void FromWordFeatures(const GenericVector< WordFeature > &word_features, GenericVector< FloatWordFeature > *float_features)
Definition: imagedata.cpp:89
void plot(ScrollView *fd) const
Definition: rect.h:278