2012-02-02 11:02:16 +08:00
|
|
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
|
|
|
// Author: rays@google.com (Ray Smith)
|
|
|
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Filename: classifier_tester.cpp
|
|
|
|
// Purpose: Tests a character classifier on data as formatted for training,
|
|
|
|
// but doesn't have to be the same as the training data.
|
|
|
|
// Author: Ray Smith
|
|
|
|
|
2013-09-23 23:26:50 +08:00
|
|
|
#include <stdio.h>
|
2012-02-02 11:02:16 +08:00
|
|
|
#ifndef USE_STD_NAMESPACE
|
|
|
|
#include "base/commandlineflags.h"
|
2015-08-10 00:09:52 +08:00
|
|
|
#endif // USE_STD_NAMESPACE
|
2012-02-02 11:02:16 +08:00
|
|
|
#include "baseapi.h"
|
|
|
|
#include "commontraining.h"
|
|
|
|
#include "mastertrainer.h"
|
|
|
|
#include "params.h"
|
|
|
|
#include "strngs.h"
|
|
|
|
#include "tessclassifier.h"
|
|
|
|
|
|
|
|
STRING_PARAM_FLAG(classifier, "", "Classifier to test");
|
|
|
|
STRING_PARAM_FLAG(lang, "eng", "Language to test");
|
|
|
|
STRING_PARAM_FLAG(tessdata_dir, "", "Directory of traineddata files");
|
2013-09-23 23:26:50 +08:00
|
|
|
DECLARE_INT_PARAM_FLAG(debug_level);
|
2012-02-02 11:02:16 +08:00
|
|
|
|
|
|
|
enum ClassifierName {
|
|
|
|
CN_PRUNER,
|
|
|
|
CN_FULL,
|
|
|
|
CN_COUNT
|
|
|
|
};
|
|
|
|
|
2017-01-26 08:20:19 +08:00
|
|
|
const char* names[] = {"pruner", "full", nullptr};
|
2012-02-02 11:02:16 +08:00
|
|
|
|
2013-09-23 23:26:50 +08:00
|
|
|
static tesseract::ShapeClassifier* InitializeClassifier(
|
|
|
|
const char* classifer_name, const UNICHARSET& unicharset,
|
|
|
|
int argc, char **argv,
|
|
|
|
tesseract::TessBaseAPI** api) {
|
|
|
|
// Decode the classifier string.
|
|
|
|
ClassifierName classifier = CN_COUNT;
|
|
|
|
for (int c = 0; c < CN_COUNT; ++c) {
|
|
|
|
if (strcmp(classifer_name, names[c]) == 0) {
|
|
|
|
classifier = static_cast<ClassifierName>(c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (classifier == CN_COUNT) {
|
|
|
|
fprintf(stderr, "Invalid classifier name:%s\n", FLAGS_classifier.c_str());
|
2016-12-13 15:08:01 +08:00
|
|
|
return nullptr;
|
2013-09-23 23:26:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We need to initialize tesseract to test.
|
|
|
|
*api = new tesseract::TessBaseAPI;
|
|
|
|
tesseract::OcrEngineMode engine_mode = tesseract::OEM_TESSERACT_ONLY;
|
2016-12-13 15:08:01 +08:00
|
|
|
tesseract::Tesseract* tesseract = nullptr;
|
|
|
|
tesseract::Classify* classify = nullptr;
|
2015-08-10 00:09:52 +08:00
|
|
|
if (
|
2013-09-23 23:26:50 +08:00
|
|
|
classifier == CN_PRUNER || classifier == CN_FULL) {
|
|
|
|
if ((*api)->Init(FLAGS_tessdata_dir.c_str(), FLAGS_lang.c_str(),
|
|
|
|
engine_mode) < 0) {
|
|
|
|
fprintf(stderr, "Tesseract initialization failed!\n");
|
2016-12-13 15:08:01 +08:00
|
|
|
return nullptr;
|
2013-09-23 23:26:50 +08:00
|
|
|
}
|
|
|
|
tesseract = const_cast<tesseract::Tesseract*>((*api)->tesseract());
|
|
|
|
classify = reinterpret_cast<tesseract::Classify*>(tesseract);
|
2016-12-13 15:08:01 +08:00
|
|
|
if (classify->shape_table() == nullptr) {
|
2013-09-23 23:26:50 +08:00
|
|
|
fprintf(stderr, "Tesseract must contain a ShapeTable!\n");
|
2016-12-13 15:08:01 +08:00
|
|
|
return nullptr;
|
2013-09-23 23:26:50 +08:00
|
|
|
}
|
|
|
|
}
|
2016-12-13 15:08:01 +08:00
|
|
|
tesseract::ShapeClassifier* shape_classifier = nullptr;
|
2013-09-23 23:26:50 +08:00
|
|
|
|
|
|
|
if (classifier == CN_PRUNER) {
|
|
|
|
shape_classifier = new tesseract::TessClassifier(true, classify);
|
|
|
|
} else if (classifier == CN_FULL) {
|
|
|
|
shape_classifier = new tesseract::TessClassifier(false, classify);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s tester not yet implemented\n", classifer_name);
|
2016-12-13 15:08:01 +08:00
|
|
|
return nullptr;
|
2013-09-23 23:26:50 +08:00
|
|
|
}
|
|
|
|
tprintf("Testing classifier %s:\n", classifer_name);
|
|
|
|
return shape_classifier;
|
|
|
|
}
|
|
|
|
|
2012-02-02 11:02:16 +08:00
|
|
|
// This program has complex setup requirements, so here is some help:
|
|
|
|
// Two different modes, tr files and serialized mastertrainer.
|
|
|
|
// From tr files:
|
|
|
|
// classifier_tester -U unicharset -F font_properties -X xheights
|
|
|
|
// -classifier x -lang lang [-output_trainer trainer] *.tr
|
|
|
|
// From a serialized trainer:
|
|
|
|
// classifier_tester -input_trainer trainer [-lang lang] -classifier x
|
|
|
|
//
|
|
|
|
// In the first case, the unicharset must be the unicharset from within
|
|
|
|
// the classifier under test, and the font_properties and xheights files must
|
|
|
|
// match the files used during training.
|
|
|
|
// In the second case, the trainer file must have been prepared from
|
|
|
|
// some previous run of shapeclustering, mftraining, or classifier_tester
|
|
|
|
// using the same conditions as above, ie matching unicharset/font_properties.
|
|
|
|
//
|
|
|
|
// Available values of classifier (x above) are:
|
|
|
|
// pruner : Tesseract class pruner only.
|
|
|
|
// full : Tesseract full classifier.
|
|
|
|
// with an input trainer.)
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
ParseArguments(&argc, &argv);
|
2013-09-23 23:26:50 +08:00
|
|
|
STRING file_prefix;
|
2017-01-26 08:20:19 +08:00
|
|
|
tesseract::MasterTrainer* trainer =
|
|
|
|
tesseract::LoadTrainingData(argc, argv, false, nullptr, &file_prefix);
|
2013-09-23 23:26:50 +08:00
|
|
|
tesseract::TessBaseAPI* api;
|
2012-02-02 11:02:16 +08:00
|
|
|
// Decode the classifier string.
|
2013-09-23 23:26:50 +08:00
|
|
|
tesseract::ShapeClassifier* shape_classifier = InitializeClassifier(
|
|
|
|
FLAGS_classifier.c_str(), trainer->unicharset(), argc, argv, &api);
|
2016-12-13 15:08:01 +08:00
|
|
|
if (shape_classifier == nullptr) {
|
2013-09-23 23:26:50 +08:00
|
|
|
fprintf(stderr, "Classifier init failed!:%s\n", FLAGS_classifier.c_str());
|
2012-02-02 11:02:16 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We want to test junk as well if it is available.
|
2013-09-23 23:26:50 +08:00
|
|
|
// trainer->IncludeJunk();
|
2012-02-02 11:02:16 +08:00
|
|
|
// We want to test with replicated samples too.
|
|
|
|
trainer->ReplicateAndRandomizeSamplesIfRequired();
|
|
|
|
|
2017-01-26 08:20:19 +08:00
|
|
|
trainer->TestClassifierOnSamples(tesseract::CT_UNICHAR_TOP1_ERR,
|
2013-09-23 23:26:50 +08:00
|
|
|
MAX(3, FLAGS_debug_level), false,
|
2016-12-13 15:08:01 +08:00
|
|
|
shape_classifier, nullptr);
|
2012-02-02 11:02:16 +08:00
|
|
|
delete shape_classifier;
|
2013-09-23 23:26:50 +08:00
|
|
|
delete api;
|
2012-02-02 11:02:16 +08:00
|
|
|
delete trainer;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
} /* main */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|