tesseract v5.3.3.20231005
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.
19const int kXBuckets = 16;
20const int kYBuckets = 24;
21const int kThetaBuckets = 13;
22
23namespace tesseract {
24
26protected:
27 void SetUp() override {
28 std::locale::global(std::locale(""));
29 }
30
31public:
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.
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 double y
#define GTEST_SKIP()
Definition: gtest.h:1889
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:2043
#define EXPECT_TRUE(condition)
Definition: gtest.h:1982
#define EXPECT_LE(val1, val2)
Definition: gtest.h:2047
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)