1 // (C) Copyright 2017, Google Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 // http://www.apache.org/licenses/LICENSE-2.0
6 // Unless required by applicable law or agreed to in writing, software
7 // distributed under the License is distributed on an "AS IS" BASIS,
8 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 // See the License for the specific language governing permissions and
10 // limitations under the License.
11 
12 #include <allheaders.h>
13 #include <tesseract/baseapi.h>
14 #include <tesseract/resultiterator.h>
15 #include <string>
16 #include "boxread.h"
17 #include "rect.h"
18 
19 #include "include_gunit.h"
20 
21 namespace tesseract {
22 
23 const char *kTruthTextWords = "To simple burn running of goods lately.\n";
24 const char *kTruthTextLine = "Tosimpleburnrunningofgoodslately.\n";
25 
26 // The fixture for testing Tesseract.
27 class ApplyBoxTest : public testing::Test {
28 protected:
TestDataNameToPath(const std::string & name)29   std::string TestDataNameToPath(const std::string &name) {
30     return file::JoinPath(TESTING_DIR, name);
31   }
TessdataPath()32   std::string TessdataPath() {
33     return TESSDATA_DIR;
34   }
35 
ApplyBoxTest()36   ApplyBoxTest() {
37     src_pix_ = nullptr;
38   }
~ApplyBoxTest()39   ~ApplyBoxTest() override {
40     src_pix_.destroy();
41   }
42 
SetImage(const char * filename)43   bool SetImage(const char *filename) {
44     bool found = false;
45     src_pix_.destroy();
46     src_pix_ = pixRead(TestDataNameToPath(filename).c_str());
47     if (api_.Init(TessdataPath().c_str(), "eng", tesseract::OEM_TESSERACT_ONLY) != -1) {
48       api_.SetPageSegMode(tesseract::PSM_SINGLE_BLOCK);
49       api_.SetImage(src_pix_);
50       api_.SetVariable("tessedit_make_boxes_from_boxes", "1");
51       api_.SetInputName(TestDataNameToPath(filename).c_str());
52       found = true;
53     }
54     return found;
55   }
56 
57   // Runs ApplyBoxes (via setting the appropriate variables and Recognize)
58   // and checks that the output ocr text matches the truth_str, and that
59   // the boxes match the given box file well enough.
60   // If line_mode is true, ApplyBoxes is run in line segmentation mode,
61   // otherwise the input box file is assumed to have character-level boxes.
VerifyBoxesAndText(const char * imagefile,const char * truth_str,const char * target_box_file,bool line_mode)62   void VerifyBoxesAndText(const char *imagefile, const char *truth_str, const char *target_box_file,
63                           bool line_mode) {
64     if (!SetImage(imagefile)) {
65       // eng.traineddata not found or other problem during Init.
66       GTEST_SKIP();
67       return;
68     }
69     if (line_mode) {
70       api_.SetVariable("tessedit_resegment_from_line_boxes", "1");
71     } else {
72       api_.SetVariable("tessedit_resegment_from_boxes", "1");
73     }
74     api_.Recognize(nullptr);
75     char *ocr_text = api_.GetUTF8Text();
76     EXPECT_STREQ(truth_str, ocr_text);
77     delete[] ocr_text;
78     // Test the boxes by reading the target box file in parallel with the
79     // bounding boxes in the ocr output.
80     std::string box_filename = TestDataNameToPath(target_box_file);
81     FILE *box_file = OpenBoxFile(box_filename.c_str());
82     ASSERT_TRUE(box_file != nullptr);
83     int height = pixGetHeight(src_pix_);
84     ResultIterator *it = api_.GetIterator();
85     do {
86       int left, top, right, bottom;
87       EXPECT_TRUE(it->BoundingBox(tesseract::RIL_SYMBOL, &left, &top, &right, &bottom));
88       TBOX ocr_box(ICOORD(left, height - bottom), ICOORD(right, height - top));
89       int line_number = 0;
90       TBOX truth_box;
91       std::string box_text;
92       EXPECT_TRUE(ReadNextBox(0, &line_number, box_file, box_text, &truth_box));
93       // Testing for major overlap is a bit weak, but if they all
94       // major overlap successfully, then it has to be fairly close.
95       EXPECT_TRUE(ocr_box.major_overlap(truth_box));
96       // Also check that the symbol text matches the box text.
97       char *symbol_text = it->GetUTF8Text(tesseract::RIL_SYMBOL);
98       EXPECT_STREQ(box_text.c_str(), symbol_text);
99       delete[] symbol_text;
100     } while (it->Next(tesseract::RIL_SYMBOL));
101     delete it;
102   }
103 
104   Image src_pix_;
105   std::string ocr_text_;
106   tesseract::TessBaseAPI api_;
107 };
108 
109 // Tests character-level applyboxes on normal Times New Roman.
TEST_F(ApplyBoxTest,TimesCharLevel)110 TEST_F(ApplyBoxTest, TimesCharLevel) {
111   VerifyBoxesAndText("trainingtimes.tif", kTruthTextWords, "trainingtimes.box", false);
112 }
113 
114 // Tests character-level applyboxes on italic Times New Roman.
TEST_F(ApplyBoxTest,ItalicCharLevel)115 TEST_F(ApplyBoxTest, ItalicCharLevel) {
116   VerifyBoxesAndText("trainingital.tif", kTruthTextWords, "trainingital.box", false);
117 }
118 
119 // Tests line-level applyboxes on normal Times New Roman.
TEST_F(ApplyBoxTest,TimesLineLevel)120 TEST_F(ApplyBoxTest, TimesLineLevel) {
121   VerifyBoxesAndText("trainingtimesline.tif", kTruthTextLine, "trainingtimes.box", true);
122 }
123 
124 // Tests line-level applyboxes on italic Times New Roman.
TEST_F(ApplyBoxTest,ItalLineLevel)125 TEST_F(ApplyBoxTest, ItalLineLevel) {
126   VerifyBoxesAndText("trainingitalline.tif", kTruthTextLine, "trainingital.box", true);
127 }
128 
129 } // namespace tesseract
130