Coverage Report

Created: 2025-06-13 07:02

/src/tesseract/src/textord/edgloop.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 * File:        edgloop.cpp  (Formerly edgeloop.c)
3
 * Description: Functions to clean up an outline before approximation.
4
 * Author:      Ray Smith
5
 *
6
 * (C) Copyright 1991, Hewlett-Packard Ltd.
7
 ** Licensed under the Apache License, Version 2.0 (the "License");
8
 ** you may not use this file except in compliance with the License.
9
 ** You may obtain a copy of the License at
10
 ** http://www.apache.org/licenses/LICENSE-2.0
11
 ** Unless required by applicable law or agreed to in writing, software
12
 ** distributed under the License is distributed on an "AS IS" BASIS,
13
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 ** See the License for the specific language governing permissions and
15
 ** limitations under the License.
16
 *
17
 **********************************************************************/
18
19
// Include automatically generated configuration file if running autoconf.
20
#ifdef HAVE_CONFIG_H
21
#  include "config_auto.h"
22
#endif
23
24
#include "scanedg.h"
25
26
#include "edgloop.h"
27
28
namespace tesseract {
29
30
1.71M
#define MINEDGELENGTH 8 // min decent length
31
32
/**********************************************************************
33
 * complete_edge
34
 *
35
 * Complete the edge by cleaning it up.
36
 **********************************************************************/
37
38
void complete_edge(CRACKEDGE *start, // start of loop
39
1.16M
                   C_OUTLINE_IT *outline_it) {
40
1.16M
  ScrollView::Color colour; // colour to draw in
41
1.16M
  int16_t looplength;       // steps in loop
42
1.16M
  ICOORD botleft;           // bounding box
43
1.16M
  ICOORD topright;
44
1.16M
  C_OUTLINE *outline; // new outline
45
46
  // check length etc.
47
1.16M
  colour = check_path_legal(start);
48
49
1.16M
  if (colour == ScrollView::RED || colour == ScrollView::BLUE) {
50
611k
    looplength = loop_bounding_box(start, botleft, topright);
51
611k
    outline = new C_OUTLINE(start, botleft, topright, looplength);
52
    // add to list
53
611k
    outline_it->add_after_then_move(outline);
54
611k
  }
55
1.16M
}
56
57
/**********************************************************************
58
 * check_path_legal
59
 *
60
 * Check that the outline is legal for length and for chaincode sum.
61
 * The return value is RED for a normal black-inside outline,
62
 * BLUE for a white-inside outline, MAGENTA if it is too short,
63
 * YELLOW if it is too long, and GREEN if it is illegal.
64
 * These colours are used to draw the raw outline.
65
 **********************************************************************/
66
67
ScrollView::Color check_path_legal( // certify outline
68
    CRACKEDGE *start                // start of loop
69
1.16M
) {
70
1.16M
  int lastchain;     // last chain code
71
1.16M
  int chaindiff;     // chain code diff
72
1.16M
  int32_t length;    // length of loop
73
1.16M
  int32_t chainsum;  // sum of chain diffs
74
1.16M
  CRACKEDGE *edgept; // current point
75
1.16M
  constexpr ERRCODE ED_ILLEGAL_SUM("Illegal sum of chain codes");
76
77
1.16M
  length = 0;
78
1.16M
  chainsum = 0; // sum of chain codes
79
1.16M
  edgept = start;
80
1.16M
  lastchain = edgept->prev->stepdir; // previous chain code
81
16.7M
  do {
82
16.7M
    length++;
83
16.7M
    if (edgept->stepdir != lastchain) {
84
      // chain code difference
85
10.4M
      chaindiff = edgept->stepdir - lastchain;
86
10.4M
      if (chaindiff > 2) {
87
1.15M
        chaindiff -= 4;
88
9.26M
      } else if (chaindiff < -2) {
89
1.55M
        chaindiff += 4;
90
1.55M
      }
91
10.4M
      chainsum += chaindiff; // sum differences
92
10.4M
      lastchain = edgept->stepdir;
93
10.4M
    }
94
16.7M
    edgept = edgept->next;
95
16.7M
  } while (edgept != start && length < C_OUTLINE::kMaxOutlineLength);
96
97
1.16M
  if ((chainsum != 4 && chainsum != -4) || edgept != start || length < MINEDGELENGTH) {
98
551k
    if (edgept != start) {
99
0
      return ScrollView::YELLOW;
100
551k
    } else if (length < MINEDGELENGTH) {
101
551k
      return ScrollView::MAGENTA;
102
551k
    } else {
103
0
      ED_ILLEGAL_SUM.error("check_path_legal", TESSLOG, "chainsum=%d", chainsum);
104
0
      return ScrollView::GREEN;
105
0
    }
106
551k
  }
107
  // colour on inside
108
611k
  return chainsum < 0 ? ScrollView::BLUE : ScrollView::RED;
109
1.16M
}
110
111
/**********************************************************************
112
 * loop_bounding_box
113
 *
114
 * Find the bounding box of the edge loop.
115
 **********************************************************************/
116
117
int16_t loop_bounding_box( // get bounding box
118
    CRACKEDGE *&start,     // edge loop
119
    ICOORD &botleft,       // bounding box
120
611k
    ICOORD &topright) {
121
611k
  int16_t length;       // length of loop
122
611k
  int16_t leftmost;     // on top row
123
611k
  CRACKEDGE *edgept;    // current point
124
611k
  CRACKEDGE *realstart; // topleft start
125
126
611k
  edgept = start;
127
611k
  realstart = start;
128
611k
  botleft = topright = ICOORD(edgept->pos.x(), edgept->pos.y());
129
611k
  leftmost = edgept->pos.x();
130
611k
  length = 0; // coutn length
131
14.4M
  do {
132
14.4M
    edgept = edgept->next;
133
14.4M
    if (edgept->pos.x() < botleft.x()) {
134
      // get bounding box
135
1.04M
      botleft.set_x(edgept->pos.x());
136
13.3M
    } else if (edgept->pos.x() > topright.x()) {
137
785k
      topright.set_x(edgept->pos.x());
138
785k
    }
139
14.4M
    if (edgept->pos.y() < botleft.y()) {
140
      // get bounding box
141
138k
      botleft.set_y(edgept->pos.y());
142
14.2M
    } else if (edgept->pos.y() > topright.y()) {
143
3.36M
      realstart = edgept;
144
3.36M
      leftmost = edgept->pos.x();
145
3.36M
      topright.set_y(edgept->pos.y());
146
10.9M
    } else if (edgept->pos.y() == topright.y() && edgept->pos.x() < leftmost) {
147
      // leftmost on line
148
1.78M
      leftmost = edgept->pos.x();
149
1.78M
      realstart = edgept;
150
1.78M
    }
151
14.4M
    length++; // count elements
152
14.4M
  } while (edgept != start);
153
611k
  start = realstart; // shift it to topleft
154
611k
  return length;
155
611k
}
156
157
} // namespace tesseract