Tesseract  3.02
tesseract-ocr/cube/con_comp.cpp
Go to the documentation of this file.
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