Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: con_comp.cpp 00003 * Description: Implementation of a Connected Component class 00004 * Author: Ahmad Abdulkader 00005 * Created: 2007 00006 * 00007 * (C) Copyright 2008, Google Inc. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #include <stdlib.h> 00021 #include <string.h> 00022 #include "con_comp.h" 00023 #include "cube_const.h" 00024 00025 namespace tesseract { 00026 00027 ConComp::ConComp() { 00028 head_ = NULL; 00029 tail_ = NULL; 00030 left_ = 0; 00031 top_ = 0; 00032 right_ = 0; 00033 bottom_ = 0; 00034 left_most_ = false; 00035 right_most_ = false; 00036 id_ = -1; 00037 pt_cnt_ = 0; 00038 } 00039 00040 ConComp::~ConComp() { 00041 if (head_ != NULL) { 00042 ConCompPt *pt_ptr = head_; 00043 while (pt_ptr != NULL) { 00044 ConCompPt *pptNext = pt_ptr->Next(); 00045 delete pt_ptr; 00046 pt_ptr = pptNext; 00047 } 00048 head_ = NULL; 00049 } 00050 } 00051 00052 // adds a pt to the conn comp and updates its boundaries 00053 bool ConComp::Add(int x, int y) { 00054 ConCompPt *pt_ptr = new ConCompPt(x, y); 00055 if (pt_ptr == NULL) { 00056 return false; 00057 } 00058 00059 if (head_ == NULL) { 00060 left_ = x; 00061 right_ = x; 00062 top_ = y; 00063 bottom_ = y; 00064 00065 head_ = pt_ptr; 00066 } else { 00067 left_ = left_ <= x ? left_ : x; 00068 top_ = top_ <= y ? top_ : y; 00069 right_ = right_ >= x ? right_ : x; 00070 bottom_ = bottom_ >= y ? bottom_ : y; 00071 } 00072 00073 if (tail_ != NULL) { 00074 tail_->SetNext(pt_ptr); 00075 } 00076 00077 tail_ = pt_ptr; 00078 pt_cnt_++; 00079 return true; 00080 } 00081 00082 // merges two connected components 00083 bool ConComp::Merge(ConComp *concomp) { 00084 if (head_ == NULL || tail_ == NULL || 00085 concomp->head_ == NULL || concomp->tail_ == NULL) { 00086 return false; 00087 } 00088 00089 tail_->SetNext(concomp->head_); 00090 tail_ = concomp->tail_; 00091 left_ = left_ <= concomp->left_ ? left_ : concomp->left_; 00092 top_ = top_ <= concomp->top_ ? top_ : concomp->top_; 00093 right_ = right_ >= concomp->right_ ? right_ : concomp->right_; 00094 bottom_ = bottom_ >= concomp->bottom_ ? bottom_ : concomp->bottom_; 00095 pt_cnt_ += concomp->pt_cnt_; 00096 00097 concomp->head_ = NULL; 00098 concomp->tail_ = NULL; 00099 00100 return true; 00101 } 00102 00103 // Creates the x-coord density histogram after spreading 00104 // each x-coord position by the HIST_WND_RATIO fraction of the 00105 // height of the ConComp, but limited to max_hist_wnd 00106 int *ConComp::CreateHistogram(int max_hist_wnd) { 00107 int wid = right_ - left_ + 1, 00108 hgt = bottom_ - top_ + 1, 00109 hist_wnd = static_cast<int>(hgt * HIST_WND_RATIO); 00110 00111 if (hist_wnd > max_hist_wnd) { 00112 hist_wnd = max_hist_wnd; 00113 } 00114 00115 // alloc memo for histogram 00116 int *hist_array = new int[wid]; 00117 if (hist_array == NULL) { 00118 return NULL; 00119 } 00120 00121 memset(hist_array, 0, wid * sizeof(*hist_array)); 00122 00123 // compute windowed histogram 00124 ConCompPt *pt_ptr = head_; 00125 00126 while (pt_ptr != NULL) { 00127 int x = pt_ptr->x() - left_, 00128 xw = x - hist_wnd; 00129 00130 for (int xdel = -hist_wnd; xdel <= hist_wnd; xdel++, xw++) { 00131 if (xw >= 0 && xw < wid) { 00132 hist_array[xw]++; 00133 } 00134 } 00135 00136 pt_ptr = pt_ptr->Next(); 00137 } 00138 00139 return hist_array; 00140 } 00141 00142 // find out the seg pts by looking for local minima in the histogram 00143 int *ConComp::SegmentHistogram(int *hist_array, int *seg_pt_cnt) { 00144 // init 00145 (*seg_pt_cnt) = 0; 00146 00147 int wid = right_ - left_ + 1, 00148 hgt = bottom_ - top_ + 1; 00149 00150 int *x_seg_pt = new int[wid]; 00151 if (x_seg_pt == NULL) { 00152 return NULL; 00153 } 00154 00155 int seg_pt_wnd = static_cast<int>(hgt * SEG_PT_WND_RATIO); 00156 00157 if (seg_pt_wnd > 1) { 00158 seg_pt_wnd = 1; 00159 } 00160 00161 for (int x = 2; x < (wid - 2); x++) { 00162 if (hist_array[x] < hist_array[x - 1] && 00163 hist_array[x] < hist_array[x - 2] && 00164 hist_array[x] <= hist_array[x + 1] && 00165 hist_array[x] <= hist_array[x + 2]) { 00166 x_seg_pt[(*seg_pt_cnt)++] = x; 00167 x += seg_pt_wnd; 00168 } else if (hist_array[x] <= hist_array[x - 1] && 00169 hist_array[x] <= hist_array[x - 2] && 00170 hist_array[x] < hist_array[x + 1] && 00171 hist_array[x] < hist_array[x + 2]) { 00172 x_seg_pt[(*seg_pt_cnt)++] = x; 00173 x += seg_pt_wnd; 00174 } 00175 } 00176 00177 // no segments, nothing to do 00178 if ((*seg_pt_cnt) == 0) { 00179 delete []x_seg_pt; 00180 return NULL; 00181 } 00182 00183 return x_seg_pt; 00184 } 00185 00186 // segments a concomp based on pixel density histogram local minima 00187 // if there were none found, it returns NULL 00188 // this is more useful than creating a clone of itself 00189 ConComp **ConComp::Segment(int max_hist_wnd, int *concomp_cnt) { 00190 // init 00191 (*concomp_cnt) = 0; 00192 00193 // No pts 00194 if (head_ == NULL) { 00195 return NULL; 00196 } 00197 00198 int seg_pt_cnt = 0; 00199 00200 // create the histogram 00201 int *hist_array = CreateHistogram(max_hist_wnd); 00202 if (hist_array == NULL) { 00203 return NULL; 00204 } 00205 00206 int *x_seg_pt = SegmentHistogram(hist_array, &seg_pt_cnt); 00207 00208 // free histogram 00209 delete []hist_array; 00210 00211 // no segments, nothing to do 00212 if (seg_pt_cnt == 0) { 00213 return NULL; 00214 } 00215 00216 // create concomp array 00217 ConComp **concomp_array = new ConComp *[seg_pt_cnt + 1]; 00218 if (concomp_array == NULL) { 00219 delete []x_seg_pt; 00220 return NULL; 00221 } 00222 00223 for (int concomp = 0; concomp <= seg_pt_cnt; concomp++) { 00224 concomp_array[concomp] = new ConComp(); 00225 if (concomp_array[concomp] == NULL) { 00226 delete []x_seg_pt; 00227 delete []concomp_array; 00228 return NULL; 00229 } 00230 00231 // split concomps inherit the ID this concomp 00232 concomp_array[concomp]->SetID(id_); 00233 } 00234 00235 // set the left and right most attributes of the 00236 // appropriate concomps 00237 concomp_array[0]->left_most_ = true; 00238 concomp_array[seg_pt_cnt]->right_most_ = true; 00239 00240 // assign pts to concomps 00241 ConCompPt *pt_ptr = head_; 00242 while (pt_ptr != NULL) { 00243 int seg_pt; 00244 00245 // find the first seg-pt that exceeds the x value 00246 // of the pt 00247 for (seg_pt = 0; seg_pt < seg_pt_cnt; seg_pt++) { 00248 if ((x_seg_pt[seg_pt] + left_) > pt_ptr->x()) { 00249 break; 00250 } 00251 } 00252 00253 // add the pt to the proper concomp 00254 if (concomp_array[seg_pt]->Add(pt_ptr->x(), pt_ptr->y()) == false) { 00255 delete []x_seg_pt; 00256 delete []concomp_array; 00257 return NULL; 00258 } 00259 00260 pt_ptr = pt_ptr->Next(); 00261 } 00262 00263 delete []x_seg_pt; 00264 00265 (*concomp_cnt) = (seg_pt_cnt + 1); 00266 00267 return concomp_array; 00268 } 00269 00270 // Shifts the co-ordinates of all points by the specified x & y deltas 00271 void ConComp::Shift(int dx, int dy) { 00272 ConCompPt *pt_ptr = head_; 00273 00274 while (pt_ptr != NULL) { 00275 pt_ptr->Shift(dx, dy); 00276 pt_ptr = pt_ptr->Next(); 00277 } 00278 00279 left_ += dx; 00280 right_ += dx; 00281 top_ += dy; 00282 bottom_ += dy; 00283 } 00284 00285 } // namespace tesseract