tesseract  5.0.0
intfeaturemap_test.cc
Go to the documentation of this file.
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 "intfeaturemap.h"
13 #include "intfeaturespace.h"
14 
15 #include "include_gunit.h"
16 
17 // Random re-quantization to test that they don't have to be easy.
18 // WARNING! Change these and change the expected_misses calculation below.
19 const int kXBuckets = 16;
20 const int kYBuckets = 24;
21 const int kThetaBuckets = 13;
22 
23 namespace tesseract {
24 
25 class IntFeatureMapTest : public testing::Test {
26 protected:
27  void SetUp() override {
28  std::locale::global(std::locale(""));
29  }
30 
31 public:
32  // Expects that the given vector has contiguous integer values in the
33  // range [start, end).
34  void ExpectContiguous(const std::vector<int> &v, int start, int end) {
35  for (int i = start; i < end; ++i) {
36  EXPECT_EQ(i, v[i - start]);
37  }
38  }
39 };
40 
41 // Tests the IntFeatureMap and implicitly the IntFeatureSpace underneath.
42 TEST_F(IntFeatureMapTest, Exhaustive) {
43 #ifdef DISABLED_LEGACY_ENGINE
44  // Skip test because IntFeatureSpace is missing.
45  GTEST_SKIP();
46 #else
47  IntFeatureSpace space;
49  IntFeatureMap map;
50  map.Init(space);
52  auto features = std::make_unique<INT_FEATURE_STRUCT[]>(total_size);
53  // Fill the features with every value.
54  for (int y = 0; y < kIntFeatureExtent; ++y) {
55  for (int x = 0; x < kIntFeatureExtent; ++x) {
56  for (int theta = 0; theta < kIntFeatureExtent; ++theta) {
57  int f_index = (y * kIntFeatureExtent + x) * kIntFeatureExtent + theta;
58  features[f_index].X = x;
59  features[f_index].Y = y;
60  features[f_index].Theta = theta;
61  }
62  }
63  }
64  std::vector<int> index_features;
65  map.IndexAndSortFeatures(features.get(), total_size, &index_features);
66  EXPECT_EQ(total_size, index_features.size());
67  int total_buckets = kXBuckets * kYBuckets * kThetaBuckets;
68  std::vector<int> map_features;
69  int misses = map.MapIndexedFeatures(index_features, &map_features);
70  EXPECT_EQ(0, misses);
71  EXPECT_EQ(total_buckets, map_features.size());
72  ExpectContiguous(map_features, 0, total_buckets);
73  EXPECT_EQ(total_buckets, map.compact_size());
74  EXPECT_EQ(total_buckets, map.sparse_size());
75 
76  // Every offset should be within dx, dy, dtheta of the start point.
77  int dx = kIntFeatureExtent / kXBuckets + 1;
78  int dy = kIntFeatureExtent / kYBuckets + 1;
79  int dtheta = kIntFeatureExtent / kThetaBuckets + 1;
80  int bad_offsets = 0;
81  for (int index = 0; index < total_buckets; ++index) {
82  for (int dir = -tesseract::kNumOffsetMaps; dir <= tesseract::kNumOffsetMaps; ++dir) {
83  int offset_index = map.OffsetFeature(index, dir);
84  if (dir == 0) {
85  EXPECT_EQ(index, offset_index);
86  } else if (offset_index >= 0) {
88  INT_FEATURE_STRUCT f2 = map.InverseIndexFeature(offset_index);
89  EXPECT_TRUE(f.X != f2.X || f.Y != f2.Y || f.Theta != f2.Theta);
90  EXPECT_LE(abs(f.X - f2.X), dx);
91  EXPECT_LE(abs(f.Y - f2.Y), dy);
92  int theta_delta = abs(f.Theta - f2.Theta);
93  if (theta_delta > kIntFeatureExtent / 2) {
94  theta_delta = kIntFeatureExtent - theta_delta;
95  }
96  EXPECT_LE(theta_delta, dtheta);
97  } else {
98  ++bad_offsets;
100  }
101  }
102  }
103  EXPECT_LE(bad_offsets, (kXBuckets + kYBuckets) * kThetaBuckets);
104 
105  // To test the mapping further, delete the 1st and last map feature, and
106  // test again.
107  map.DeleteMapFeature(0);
108  map.DeleteMapFeature(total_buckets - 1);
109  map.FinalizeMapping(nullptr);
110  map.IndexAndSortFeatures(features.get(), total_size, &index_features);
111  // Has no effect on index features.
112  EXPECT_EQ(total_size, index_features.size());
113  misses = map.MapIndexedFeatures(index_features, &map_features);
114  int expected_misses = (kIntFeatureExtent / kXBuckets) * (kIntFeatureExtent / kYBuckets) *
116  expected_misses += (kIntFeatureExtent / kXBuckets) * (kIntFeatureExtent / kYBuckets + 1) *
118  EXPECT_EQ(expected_misses, misses);
119  EXPECT_EQ(total_buckets - 2, map_features.size());
120  ExpectContiguous(map_features, 0, total_buckets - 2);
121  EXPECT_EQ(total_buckets - 2, map.compact_size());
122  EXPECT_EQ(total_buckets, map.sparse_size());
123 #endif
124 }
125 
126 } // namespace tesseract
const int kIntFeatureExtent
const int kThetaBuckets
const int kYBuckets
const int kXBuckets
TEST_F(EuroText, FastLatinOCR)
void Init(uint8_t xbuckets, uint8_t ybuckets, uint8_t thetabuckets)
int MapIndexedFeatures(const std::vector< int > &index_features, std::vector< int > *map_features) const
INT_FEATURE_STRUCT InverseIndexFeature(int index_feature) const
int OffsetFeature(int index_feature, int dir) const
void DeleteMapFeature(int map_feature)
void Init(const IntFeatureSpace &feature_space)
void IndexAndSortFeatures(const INT_FEATURE_STRUCT *features, int num_features, std::vector< int > *sorted_features) const
int FinalizeMapping(SampleIterator *it)
void ExpectContiguous(const std::vector< int > &v, int start, int end)