Skip to content

Commit

Permalink
Final part of endian improvement. Adds big-endian support to lstm and…
Browse files Browse the repository at this point in the history
… fixes issue 518
  • Loading branch information
theraysmith committed May 3, 2017
1 parent 6ac31dc commit 8e79297
Show file tree
Hide file tree
Showing 50 changed files with 299 additions and 376 deletions.
2 changes: 1 addition & 1 deletion ccmain/linerec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void Tesseract::TrainLineRecognizer(const STRING& input_imagename,
DocumentData images(lstmf_name);
if (applybox_page > 0) {
// Load existing document for the previous pages.
if (!images.LoadDocument(lstmf_name.string(), "eng", 0, 0, NULL)) {
if (!images.LoadDocument(lstmf_name.string(), 0, 0, nullptr)) {
tprintf("Failed to read training data from %s!\n", lstmf_name.string());
return;
}
Expand Down
8 changes: 2 additions & 6 deletions ccmain/tessedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,9 @@ bool Tesseract::init_tesseract_lang_data(
#ifndef ANDROID_BUILD
if (tessedit_ocr_engine_mode == OEM_LSTM_ONLY ||
tessedit_ocr_engine_mode == OEM_TESSERACT_LSTM_COMBINED) {
if (mgr->swap()) {
tprintf("Error: LSTM requested on big-endian hardware!!\n");
tprintf("Big-endian not yet supported! Loading tesseract.\n");
tessedit_ocr_engine_mode.set_value(OEM_TESSERACT_ONLY);
} else if (mgr->GetComponent(TESSDATA_LSTM, &fp)) {
if (mgr->GetComponent(TESSDATA_LSTM, &fp)) {
lstm_recognizer_ = new LSTMRecognizer;
ASSERT_HOST(lstm_recognizer_->DeSerialize(mgr->swap(), &fp));
ASSERT_HOST(lstm_recognizer_->DeSerialize(&fp));
if (lstm_use_matrix) lstm_recognizer_->LoadDictionary(language, mgr);
} else {
tprintf("Error: LSTM requested, but not present!! Loading tesseract.\n");
Expand Down
39 changes: 18 additions & 21 deletions ccstruct/fontinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ bool FontInfo::Serialize(FILE* fp) const {
}
// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool FontInfo::DeSerialize(bool swap, TFile* fp) {
if (!read_info(fp, this, swap)) return false;
if (!read_spacing_info(fp, this, swap)) return false;
bool FontInfo::DeSerialize(TFile* fp) {
if (!read_info(fp, this)) return false;
if (!read_spacing_info(fp, this)) return false;
return true;
}

Expand All @@ -51,9 +51,9 @@ bool FontInfoTable::Serialize(FILE* fp) const {
}
// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool FontInfoTable::DeSerialize(bool swap, TFile* fp) {
bool FontInfoTable::DeSerialize(TFile* fp) {
truncate(0);
return this->DeSerializeClasses(swap, fp);
return this->DeSerializeClasses(fp);
}

// Returns true if the given set of fonts includes one with the same
Expand Down Expand Up @@ -149,14 +149,14 @@ void FontSetDeleteCallback(FontSet fs) {

/*---------------------------------------------------------------------------*/
// Callbacks used by UnicityTable to read/write FontInfo/FontSet structures.
bool read_info(TFile* f, FontInfo* fi, bool swap) {
bool read_info(TFile* f, FontInfo* fi) {
inT32 size;
if (f->FReadEndian(&size, sizeof(size), 1, swap) != 1) return false;
if (f->FReadEndian(&size, sizeof(size), 1) != 1) return false;
char* font_name = new char[size + 1];
fi->name = font_name;
if (f->FRead(font_name, sizeof(*font_name), size) != size) return false;
font_name[size] = '\0';
if (f->FReadEndian(&fi->properties, sizeof(fi->properties), 1, swap) != 1)
if (f->FReadEndian(&fi->properties, sizeof(fi->properties), 1) != 1)
return false;
return true;
}
Expand All @@ -170,28 +170,26 @@ bool write_info(FILE* f, const FontInfo& fi) {
return true;
}

bool read_spacing_info(TFile* f, FontInfo* fi, bool swap) {
bool read_spacing_info(TFile* f, FontInfo* fi) {
inT32 vec_size, kern_size;
if (f->FReadEndian(&vec_size, sizeof(vec_size), 1, swap) != 1) return false;
if (f->FReadEndian(&vec_size, sizeof(vec_size), 1) != 1) return false;
ASSERT_HOST(vec_size >= 0);
if (vec_size == 0) return true;
fi->init_spacing(vec_size);
for (int i = 0; i < vec_size; ++i) {
FontSpacingInfo *fs = new FontSpacingInfo();
if (f->FReadEndian(&fs->x_gap_before, sizeof(fs->x_gap_before), 1, swap) !=
1 ||
f->FReadEndian(&fs->x_gap_after, sizeof(fs->x_gap_after), 1, swap) !=
1 ||
f->FReadEndian(&kern_size, sizeof(kern_size), 1, swap) != 1) {
if (f->FReadEndian(&fs->x_gap_before, sizeof(fs->x_gap_before), 1) != 1 ||
f->FReadEndian(&fs->x_gap_after, sizeof(fs->x_gap_after), 1) != 1 ||
f->FReadEndian(&kern_size, sizeof(kern_size), 1) != 1) {
delete fs;
return false;
}
if (kern_size < 0) { // indication of a NULL entry in fi->spacing_vec
delete fs;
continue;
}
if (kern_size > 0 && (!fs->kerned_unichar_ids.DeSerialize(swap, f) ||
!fs->kerned_x_gaps.DeSerialize(swap, f))) {
if (kern_size > 0 && (!fs->kerned_unichar_ids.DeSerialize(f) ||
!fs->kerned_x_gaps.DeSerialize(f))) {
delete fs;
return false;
}
Expand Down Expand Up @@ -229,11 +227,10 @@ bool write_spacing_info(FILE* f, const FontInfo& fi) {
return true;
}

bool read_set(TFile* f, FontSet* fs, bool swap) {
if (f->FReadEndian(&fs->size, sizeof(fs->size), 1, swap) != 1) return false;
bool read_set(TFile* f, FontSet* fs) {
if (f->FReadEndian(&fs->size, sizeof(fs->size), 1) != 1) return false;
fs->configs = new int[fs->size];
if (f->FReadEndian(fs->configs, sizeof(fs->configs[0]), fs->size, swap) !=
fs->size)
if (f->FReadEndian(fs->configs, sizeof(fs->configs[0]), fs->size) != fs->size)
return false;
return true;
}
Expand Down
10 changes: 5 additions & 5 deletions ccstruct/fontinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ struct FontInfo {
bool Serialize(FILE* fp) const;
// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool DeSerialize(bool swap, TFile* fp);
bool DeSerialize(TFile* fp);

// Reserves unicharset_size spots in spacing_vec.
void init_spacing(int unicharset_size) {
Expand Down Expand Up @@ -152,7 +152,7 @@ class FontInfoTable : public GenericVector<FontInfo> {
bool Serialize(FILE* fp) const;
// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool DeSerialize(bool swap, TFile* fp);
bool DeSerialize(TFile* fp);

// Returns true if the given set of fonts includes one with the same
// properties as font_id.
Expand All @@ -177,11 +177,11 @@ void FontInfoDeleteCallback(FontInfo f);
void FontSetDeleteCallback(FontSet fs);

// Callbacks used by UnicityTable to read/write FontInfo/FontSet structures.
bool read_info(TFile* f, FontInfo* fi, bool swap);
bool read_info(TFile* f, FontInfo* fi);
bool write_info(FILE* f, const FontInfo& fi);
bool read_spacing_info(TFile* f, FontInfo* fi, bool swap);
bool read_spacing_info(TFile* f, FontInfo* fi);
bool write_spacing_info(FILE* f, const FontInfo& fi);
bool read_set(TFile* f, FontSet* fs, bool swap);
bool read_set(TFile* f, FontSet* fs);
bool write_set(FILE* f, const FontSet& fs);

} // namespace tesseract.
Expand Down
56 changes: 29 additions & 27 deletions ccstruct/imagedata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ bool ImageData::Serialize(TFile* fp) const {
if (!imagefilename_.Serialize(fp)) return false;
if (fp->FWrite(&page_number_, sizeof(page_number_), 1) != 1) return false;
if (!image_data_.Serialize(fp)) return false;
if (!language_.Serialize(fp)) return false;
if (!transcription_.Serialize(fp)) return false;
// WARNING: Will not work across different endian machines.
if (!boxes_.Serialize(fp)) return false;
Expand All @@ -177,30 +178,32 @@ bool ImageData::Serialize(TFile* fp) const {

// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool ImageData::DeSerialize(bool swap, TFile* fp) {
if (!imagefilename_.DeSerialize(swap, fp)) return false;
if (fp->FRead(&page_number_, sizeof(page_number_), 1) != 1) return false;
if (swap) ReverseN(&page_number_, sizeof(page_number_));
if (!image_data_.DeSerialize(swap, fp)) return false;
if (!transcription_.DeSerialize(swap, fp)) return false;
bool ImageData::DeSerialize(TFile* fp) {
if (!imagefilename_.DeSerialize(fp)) return false;
if (fp->FReadEndian(&page_number_, sizeof(page_number_), 1) != 1)
return false;
if (!image_data_.DeSerialize(fp)) return false;
if (!language_.DeSerialize(fp)) return false;
if (!transcription_.DeSerialize(fp)) return false;
// WARNING: Will not work across different endian machines.
if (!boxes_.DeSerialize(swap, fp)) return false;
if (!box_texts_.DeSerializeClasses(swap, fp)) return false;
if (!boxes_.DeSerialize(fp)) return false;
if (!box_texts_.DeSerializeClasses(fp)) return false;
inT8 vertical = 0;
if (fp->FRead(&vertical, sizeof(vertical), 1) != 1) return false;
vertical_text_ = vertical != 0;
return true;
}

// As DeSerialize, but only seeks past the data - hence a static method.
bool ImageData::SkipDeSerialize(bool swap, TFile* fp) {
if (!STRING::SkipDeSerialize(swap, fp)) return false;
bool ImageData::SkipDeSerialize(TFile* fp) {
if (!STRING::SkipDeSerialize(fp)) return false;
inT32 page_number;
if (fp->FRead(&page_number, sizeof(page_number), 1) != 1) return false;
if (!GenericVector<char>::SkipDeSerialize(swap, fp)) return false;
if (!STRING::SkipDeSerialize(swap, fp)) return false;
if (!GenericVector<TBOX>::SkipDeSerialize(swap, fp)) return false;
if (!GenericVector<STRING>::SkipDeSerializeClasses(swap, fp)) return false;
if (!GenericVector<char>::SkipDeSerialize(fp)) return false;
if (!STRING::SkipDeSerialize(fp)) return false;
if (!STRING::SkipDeSerialize(fp)) return false;
if (!GenericVector<TBOX>::SkipDeSerialize(fp)) return false;
if (!GenericVector<STRING>::SkipDeSerializeClasses(fp)) return false;
inT8 vertical = 0;
return fp->FRead(&vertical, sizeof(vertical), 1) == 1;
}
Expand Down Expand Up @@ -384,21 +387,19 @@ DocumentData::~DocumentData() {

// Reads all the pages in the given lstmf filename to the cache. The reader
// is used to read the file.
bool DocumentData::LoadDocument(const char* filename, const char* lang,
int start_page, inT64 max_memory,
FileReader reader) {
SetDocument(filename, lang, max_memory, reader);
bool DocumentData::LoadDocument(const char* filename, int start_page,
inT64 max_memory, FileReader reader) {
SetDocument(filename, max_memory, reader);
pages_offset_ = start_page;
return ReCachePages();
}

// Sets up the document, without actually loading it.
void DocumentData::SetDocument(const char* filename, const char* lang,
inT64 max_memory, FileReader reader) {
void DocumentData::SetDocument(const char* filename, inT64 max_memory,
FileReader reader) {
SVAutoLock lock_p(&pages_mutex_);
SVAutoLock lock(&general_mutex_);
document_name_ = filename;
lang_ = lang;
pages_offset_ = -1;
max_memory_ = max_memory;
reader_ = reader;
Expand Down Expand Up @@ -522,7 +523,7 @@ bool DocumentData::ReCachePages() {
pages_.truncate(0);
TFile fp;
if (!fp.Open(document_name_, reader_) ||
!PointerVector<ImageData>::DeSerializeSize(false, &fp, &loaded_pages) ||
!PointerVector<ImageData>::DeSerializeSize(&fp, &loaded_pages) ||
loaded_pages <= 0) {
tprintf("Deserialize header failed: %s\n", document_name_.string());
return false;
Expand All @@ -534,15 +535,17 @@ bool DocumentData::ReCachePages() {
for (page = 0; page < loaded_pages; ++page) {
if (page < pages_offset_ ||
(max_memory_ > 0 && memory_used() > max_memory_)) {
if (!PointerVector<ImageData>::DeSerializeSkip(false, &fp)) break;
if (!PointerVector<ImageData>::DeSerializeSkip(&fp)) {
tprintf("Deserializeskip failed\n");
break;
}
} else {
if (!pages_.DeSerializeElement(false, &fp)) break;
if (!pages_.DeSerializeElement(&fp)) break;
ImageData* image_data = pages_.back();
if (image_data->imagefilename().length() == 0) {
image_data->set_imagefilename(document_name_);
image_data->set_page_number(page);
}
image_data->set_language(lang_);
set_memory_used(memory_used() + image_data->MemoryUsed());
}
}
Expand All @@ -567,7 +570,6 @@ DocumentCache::~DocumentCache() {}
// Adds all the documents in the list of filenames, counting memory.
// The reader is used to read the files.
bool DocumentCache::LoadDocuments(const GenericVector<STRING>& filenames,
const char* lang,
CachingStrategy cache_strategy,
FileReader reader) {
cache_strategy_ = cache_strategy;
Expand All @@ -580,7 +582,7 @@ bool DocumentCache::LoadDocuments(const GenericVector<STRING>& filenames,
for (int arg = 0; arg < filenames.size(); ++arg) {
STRING filename = filenames[arg];
DocumentData* document = new DocumentData(filename);
document->SetDocument(filename.string(), lang, fair_share_memory, reader);
document->SetDocument(filename.string(), fair_share_memory, reader);
AddToCache(document);
}
if (!documents_.empty()) {
Expand Down
16 changes: 6 additions & 10 deletions ccstruct/imagedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ class ImageData {
// Writes to the given file. Returns false in case of error.
bool Serialize(TFile* fp) const;
// Reads from the given file. Returns false in case of error.
// If swap is true, assumes a big/little-endian swap is needed.
bool DeSerialize(bool swap, TFile* fp);
bool DeSerialize(TFile* fp);
// As DeSerialize, but only seeks past the data - hence a static method.
static bool SkipDeSerialize(bool swap, tesseract::TFile* fp);
static bool SkipDeSerialize(tesseract::TFile* fp);

// Other accessors.
const STRING& imagefilename() const {
Expand Down Expand Up @@ -210,11 +209,10 @@ class DocumentData {

// Reads all the pages in the given lstmf filename to the cache. The reader
// is used to read the file.
bool LoadDocument(const char* filename, const char* lang, int start_page,
inT64 max_memory, FileReader reader);
bool LoadDocument(const char* filename, int start_page, inT64 max_memory,
FileReader reader);
// Sets up the document, without actually loading it.
void SetDocument(const char* filename, const char* lang, inT64 max_memory,
FileReader reader);
void SetDocument(const char* filename, inT64 max_memory, FileReader reader);
// Writes all the pages to the given filename. Returns false on error.
bool SaveDocument(const char* filename, FileWriter writer);
bool SaveToBuffer(GenericVector<char>* buffer);
Expand Down Expand Up @@ -286,8 +284,6 @@ class DocumentData {
private:
// A name for this document.
STRING document_name_;
// The language of this document.
STRING lang_;
// A group of pages that corresponds in some loose way to a document.
PointerVector<ImageData> pages_;
// Page number of the first index in pages_.
Expand Down Expand Up @@ -325,7 +321,7 @@ class DocumentCache {
}
// Adds all the documents in the list of filenames, counting memory.
// The reader is used to read the files.
bool LoadDocuments(const GenericVector<STRING>& filenames, const char* lang,
bool LoadDocuments(const GenericVector<STRING>& filenames,
CachingStrategy cache_strategy, FileReader reader);

// Adds document to the cache.
Expand Down
23 changes: 7 additions & 16 deletions ccstruct/matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,11 @@ class GENERIC_2D_ARRAY {
}
return true;
}
bool DeSerialize(bool swap, tesseract::TFile* fp) {
if (!DeSerializeSize(swap, fp)) return false;
if (fp->FRead(&empty_, sizeof(empty_), 1) != 1) return false;
if (swap) ReverseN(&empty_, sizeof(empty_));
bool DeSerialize(tesseract::TFile* fp) {
if (!DeSerializeSize(fp)) return false;
if (fp->FReadEndian(&empty_, sizeof(empty_), 1) != 1) return false;
int size = num_elements();
if (fp->FRead(array_, sizeof(*array_), size) != size) return false;
if (swap) {
for (int i = 0; i < size; ++i)
ReverseN(&array_[i], sizeof(array_[i]));
}
if (fp->FReadEndian(array_, sizeof(*array_), size) != size) return false;
return true;
}

Expand Down Expand Up @@ -487,14 +482,10 @@ class GENERIC_2D_ARRAY {
Resize(size1, size2, empty_);
return true;
}
bool DeSerializeSize(bool swap, tesseract::TFile* fp) {
bool DeSerializeSize(tesseract::TFile* fp) {
inT32 size1, size2;
if (fp->FRead(&size1, sizeof(size1), 1) != 1) return false;
if (fp->FRead(&size2, sizeof(size2), 1) != 1) return false;
if (swap) {
ReverseN(&size1, sizeof(size1));
ReverseN(&size2, sizeof(size2));
}
if (fp->FReadEndian(&size1, sizeof(size1), 1) != 1) return false;
if (fp->FReadEndian(&size2, sizeof(size2), 1) != 1) return false;
Resize(size1, size2, empty_);
return true;
}
Expand Down
Loading

0 comments on commit 8e79297

Please sign in to comment.