tesseract  3.05.02
con_comp.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: con_comp.cpp
3  * Description: Implementation of a Connected Component class
4  * Author: Ahmad Abdulkader
5  * Created: 2007
6  *
7  * (C) Copyright 2008, Google Inc.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include "con_comp.h"
23 #include "cube_const.h"
24 
25 namespace tesseract {
26 
28  head_ = NULL;
29  tail_ = NULL;
30  left_ = 0;
31  top_ = 0;
32  right_ = 0;
33  bottom_ = 0;
34  left_most_ = false;
35  right_most_ = false;
36  id_ = -1;
37  pt_cnt_ = 0;
38 }
39 
41  if (head_ != NULL) {
42  ConCompPt *pt_ptr = head_;
43  while (pt_ptr != NULL) {
44  ConCompPt *pptNext = pt_ptr->Next();
45  delete pt_ptr;
46  pt_ptr = pptNext;
47  }
48  head_ = NULL;
49  }
50 }
51 
52 // adds a pt to the conn comp and updates its boundaries
53 bool ConComp::Add(int x, int y) {
54  ConCompPt *pt_ptr = new ConCompPt(x, y);
55 
56  if (head_ == NULL) {
57  left_ = x;
58  right_ = x;
59  top_ = y;
60  bottom_ = y;
61 
62  head_ = pt_ptr;
63  } else {
64  left_ = left_ <= x ? left_ : x;
65  top_ = top_ <= y ? top_ : y;
66  right_ = right_ >= x ? right_ : x;
67  bottom_ = bottom_ >= y ? bottom_ : y;
68  }
69 
70  if (tail_ != NULL) {
71  tail_->SetNext(pt_ptr);
72  }
73 
74  tail_ = pt_ptr;
75  pt_cnt_++;
76  return true;
77 }
78 
79 // merges two connected components
80 bool ConComp::Merge(ConComp *concomp) {
81  if (head_ == NULL || tail_ == NULL ||
82  concomp->head_ == NULL || concomp->tail_ == NULL) {
83  return false;
84  }
85 
86  tail_->SetNext(concomp->head_);
87  tail_ = concomp->tail_;
88  left_ = left_ <= concomp->left_ ? left_ : concomp->left_;
89  top_ = top_ <= concomp->top_ ? top_ : concomp->top_;
90  right_ = right_ >= concomp->right_ ? right_ : concomp->right_;
91  bottom_ = bottom_ >= concomp->bottom_ ? bottom_ : concomp->bottom_;
92  pt_cnt_ += concomp->pt_cnt_;
93 
94  concomp->head_ = NULL;
95  concomp->tail_ = NULL;
96 
97  return true;
98 }
99 
100 // Creates the x-coord density histogram after spreading
101 // each x-coord position by the HIST_WND_RATIO fraction of the
102 // height of the ConComp, but limited to max_hist_wnd
103 int *ConComp::CreateHistogram(int max_hist_wnd) {
104  int wid = right_ - left_ + 1,
105  hgt = bottom_ - top_ + 1,
106  hist_wnd = static_cast<int>(hgt * HIST_WND_RATIO);
107 
108  if (hist_wnd > max_hist_wnd) {
109  hist_wnd = max_hist_wnd;
110  }
111 
112  // alloc memo for histogram
113  int *hist_array = new int[wid];
114 
115  memset(hist_array, 0, wid * sizeof(*hist_array));
116 
117  // compute windowed histogram
118  ConCompPt *pt_ptr = head_;
119 
120  while (pt_ptr != NULL) {
121  int x = pt_ptr->x() - left_,
122  xw = x - hist_wnd;
123 
124  for (int xdel = -hist_wnd; xdel <= hist_wnd; xdel++, xw++) {
125  if (xw >= 0 && xw < wid) {
126  hist_array[xw]++;
127  }
128  }
129 
130  pt_ptr = pt_ptr->Next();
131  }
132 
133  return hist_array;
134 }
135 
136 // find out the seg pts by looking for local minima in the histogram
137 int *ConComp::SegmentHistogram(int *hist_array, int *seg_pt_cnt) {
138  // init
139  (*seg_pt_cnt) = 0;
140 
141  int wid = right_ - left_ + 1,
142  hgt = bottom_ - top_ + 1;
143 
144  int *x_seg_pt = new int[wid];
145 
146  int seg_pt_wnd = static_cast<int>(hgt * SEG_PT_WND_RATIO);
147 
148  if (seg_pt_wnd > 1) {
149  seg_pt_wnd = 1;
150  }
151 
152  for (int x = 2; x < (wid - 2); x++) {
153  if (hist_array[x] < hist_array[x - 1] &&
154  hist_array[x] < hist_array[x - 2] &&
155  hist_array[x] <= hist_array[x + 1] &&
156  hist_array[x] <= hist_array[x + 2]) {
157  x_seg_pt[(*seg_pt_cnt)++] = x;
158  x += seg_pt_wnd;
159  } else if (hist_array[x] <= hist_array[x - 1] &&
160  hist_array[x] <= hist_array[x - 2] &&
161  hist_array[x] < hist_array[x + 1] &&
162  hist_array[x] < hist_array[x + 2]) {
163  x_seg_pt[(*seg_pt_cnt)++] = x;
164  x += seg_pt_wnd;
165  }
166  }
167 
168  // no segments, nothing to do
169  if ((*seg_pt_cnt) == 0) {
170  delete []x_seg_pt;
171  return NULL;
172  }
173 
174  return x_seg_pt;
175 }
176 
177 // segments a concomp based on pixel density histogram local minima
178 // if there were none found, it returns NULL
179 // this is more useful than creating a clone of itself
180 ConComp **ConComp::Segment(int max_hist_wnd, int *concomp_cnt) {
181  // init
182  (*concomp_cnt) = 0;
183 
184  // No pts
185  if (head_ == NULL) {
186  return NULL;
187  }
188 
189  int seg_pt_cnt = 0;
190 
191  // create the histogram
192  int *hist_array = CreateHistogram(max_hist_wnd);
193  if (hist_array == NULL) {
194  return NULL;
195  }
196 
197  int *x_seg_pt = SegmentHistogram(hist_array, &seg_pt_cnt);
198 
199  // free histogram
200  delete []hist_array;
201 
202  // no segments, nothing to do
203  if (seg_pt_cnt == 0) {
204  delete []x_seg_pt;
205  return NULL;
206  }
207 
208  // create concomp array
209  ConComp **concomp_array = new ConComp *[seg_pt_cnt + 1];
210 
211  for (int concomp = 0; concomp <= seg_pt_cnt; concomp++) {
212  concomp_array[concomp] = new ConComp();
213 
214  // split concomps inherit the ID this concomp
215  concomp_array[concomp]->SetID(id_);
216  }
217 
218  // set the left and right most attributes of the
219  // appropriate concomps
220  concomp_array[0]->left_most_ = true;
221  concomp_array[seg_pt_cnt]->right_most_ = true;
222 
223  // assign pts to concomps
224  ConCompPt *pt_ptr = head_;
225  while (pt_ptr != NULL) {
226  int seg_pt;
227 
228  // find the first seg-pt that exceeds the x value
229  // of the pt
230  for (seg_pt = 0; seg_pt < seg_pt_cnt; seg_pt++) {
231  if ((x_seg_pt[seg_pt] + left_) > pt_ptr->x()) {
232  break;
233  }
234  }
235 
236  // add the pt to the proper concomp
237  if (concomp_array[seg_pt]->Add(pt_ptr->x(), pt_ptr->y()) == false) {
238  delete []x_seg_pt;
239  delete []concomp_array;
240  return NULL;
241  }
242 
243  pt_ptr = pt_ptr->Next();
244  }
245 
246  delete []x_seg_pt;
247 
248  (*concomp_cnt) = (seg_pt_cnt + 1);
249 
250  return concomp_array;
251 }
252 
253 // Shifts the co-ordinates of all points by the specified x & y deltas
254 void ConComp::Shift(int dx, int dy) {
255  ConCompPt *pt_ptr = head_;
256 
257  while (pt_ptr != NULL) {
258  pt_ptr->Shift(dx, dy);
259  pt_ptr = pt_ptr->Next();
260  }
261 
262  left_ += dx;
263  right_ += dx;
264  top_ += dy;
265  bottom_ += dy;
266 }
267 
268 } // namespace tesseract
#define SEG_PT_WND_RATIO
Definition: cube_const.h:33
int * CreateHistogram(int max_hist_wnd)
Definition: con_comp.cpp:103
#define HIST_WND_RATIO
Definition: cube_const.h:32
virtual ~ConComp()
Definition: con_comp.cpp:40
ConCompPt * Next()
Definition: con_comp.h:50
ConComp ** Segment(int max_hist_wnd, int *concomp_cnt)
Definition: con_comp.cpp:180
void Shift(int dx, int dy)
Definition: con_comp.cpp:254
bool Add(int x, int y)
Definition: con_comp.cpp:53
int * SegmentHistogram(int *hist_array, int *seg_pt_cnt)
Definition: con_comp.cpp:137
void SetNext(ConCompPt *pt)
Definition: con_comp.h:51
void SetID(int id)
Definition: con_comp.h:95
void Shift(int dx, int dy)
Definition: con_comp.h:46
bool Merge(ConComp *con_comp)
Definition: con_comp.cpp:80