tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/boxword.cpp
Go to the documentation of this file.
00001 
00002 // File:        boxword.h
00003 // Description: Class to represent the bounding boxes of the output.
00004 // Author:      Ray Smith
00005 // Created:     Tue May 25 14:18:14 PDT 2010
00006 //
00007 // (C) Copyright 2010, 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 //
00019 
00020 #include "blobs.h"
00021 #include "boxword.h"
00022 #include "normalis.h"
00023 #include "ocrblock.h"
00024 #include "pageres.h"
00025 
00026 namespace tesseract {
00027 
00028 // Clip output boxes to input blob boxes for bounds that are within this
00029 // tolerance. Otherwise, the blob may be chopped and we have to just use
00030 // the word bounding box.
00031 const int kBoxClipTolerance = 2;
00032 
00033 BoxWord::BoxWord() : length_(0) {
00034 }
00035 
00036 BoxWord::BoxWord(const BoxWord& src) {
00037   CopyFrom(src);
00038 }
00039 
00040 BoxWord::~BoxWord() {
00041 }
00042 
00043 BoxWord& BoxWord::operator=(const BoxWord& src) {
00044   CopyFrom(src);
00045   return *this;
00046 }
00047 
00048 void BoxWord::CopyFrom(const BoxWord& src) {
00049   bbox_ = src.bbox_;
00050   length_ = src.length_;
00051   boxes_.clear();
00052   boxes_.reserve(length_);
00053   for (int i = 0; i < length_; ++i)
00054     boxes_.push_back(src.boxes_[i]);
00055 }
00056 
00057 // Factory to build a BoxWord from a TWERD using the DENORMs on each blob to
00058 // switch back to original image coordinates.
00059 BoxWord* BoxWord::CopyFromNormalized(TWERD* tessword) {
00060   BoxWord* boxword = new BoxWord();
00061   // Count the blobs.
00062   boxword->length_ = tessword->NumBlobs();
00063   // Allocate memory.
00064   boxword->boxes_.reserve(boxword->length_);
00065 
00066   for (int b = 0; b < boxword->length_; ++b) {
00067     TBLOB* tblob = tessword->blobs[b];
00068     TBOX blob_box;
00069     for (TESSLINE* outline = tblob->outlines; outline != NULL;
00070          outline = outline->next) {
00071       EDGEPT* edgept = outline->loop;
00072       // Iterate over the edges.
00073       do {
00074         if (!edgept->IsHidden() || !edgept->prev->IsHidden()) {
00075           ICOORD pos(edgept->pos.x, edgept->pos.y);
00076           TPOINT denormed;
00077           tblob->denorm().DenormTransform(NULL, edgept->pos, &denormed);
00078           pos.set_x(denormed.x);
00079           pos.set_y(denormed.y);
00080           TBOX pt_box(pos, pos);
00081           blob_box += pt_box;
00082         }
00083         edgept = edgept->next;
00084       } while (edgept != outline->loop);
00085     }
00086     boxword->boxes_.push_back(blob_box);
00087   }
00088   boxword->ComputeBoundingBox();
00089   return boxword;
00090 }
00091 
00092 // Clean up the bounding boxes from the polygonal approximation by
00093 // expanding slightly, then clipping to the blobs from the original_word
00094 // that overlap. If not null, the block provides the inverse rotation.
00095 void BoxWord::ClipToOriginalWord(const BLOCK* block, WERD* original_word) {
00096   for (int i = 0; i < length_; ++i) {
00097     TBOX box = boxes_[i];
00098     // Expand by a single pixel, as the poly approximation error is 1 pixel.
00099     box = TBOX(box.left() - 1, box.bottom() - 1,
00100                box.right() + 1, box.top() + 1);
00101     // Now find the original box that matches.
00102     TBOX original_box;
00103     C_BLOB_IT b_it(original_word->cblob_list());
00104     for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
00105       TBOX blob_box = b_it.data()->bounding_box();
00106       if (block != NULL)
00107         blob_box.rotate(block->re_rotation());
00108       if (blob_box.major_overlap(box)) {
00109         original_box += blob_box;
00110       }
00111     }
00112     if (!original_box.null_box()) {
00113       if (NearlyEqual<int>(original_box.left(), box.left(), kBoxClipTolerance))
00114         box.set_left(original_box.left());
00115       if (NearlyEqual<int>(original_box.right(), box.right(),
00116                            kBoxClipTolerance))
00117         box.set_right(original_box.right());
00118       if (NearlyEqual<int>(original_box.top(), box.top(), kBoxClipTolerance))
00119         box.set_top(original_box.top());
00120       if (NearlyEqual<int>(original_box.bottom(), box.bottom(),
00121                            kBoxClipTolerance))
00122         box.set_bottom(original_box.bottom());
00123     }
00124     original_box = original_word->bounding_box();
00125     if (block != NULL)
00126       original_box.rotate(block->re_rotation());
00127     boxes_[i] = box.intersection(original_box);
00128   }
00129   ComputeBoundingBox();
00130 }
00131 
00132 // Merges the boxes from start to end, not including end, and deletes
00133 // the boxes between start and end.
00134 void BoxWord::MergeBoxes(int start, int end) {
00135   start = ClipToRange(start, 0, length_);
00136   end = ClipToRange(end, 0, length_);
00137   if (end <= start + 1)
00138     return;
00139   for (int i = start + 1; i < end; ++i) {
00140     boxes_[start] += boxes_[i];
00141   }
00142   int shrinkage = end - 1 - start;
00143   length_ -= shrinkage;
00144   for (int i = start + 1; i < length_; ++i)
00145     boxes_[i] = boxes_[i + shrinkage];
00146   boxes_.truncate(length_);
00147 }
00148 
00149 // Inserts a new box before the given index.
00150 // Recomputes the bounding box.
00151 void BoxWord::InsertBox(int index, const TBOX& box) {
00152   if (index < length_)
00153     boxes_.insert(box, index);
00154   else
00155     boxes_.push_back(box);
00156   length_ = boxes_.size();
00157   ComputeBoundingBox();
00158 }
00159 
00160 // Deletes the box with the given index, and shuffles up the rest.
00161 // Recomputes the bounding box.
00162 void BoxWord::DeleteBox(int index) {
00163   ASSERT_HOST(0 <= index && index < length_);
00164   boxes_.remove(index);
00165   --length_;
00166   ComputeBoundingBox();
00167 }
00168 
00169 // Deletes all the boxes stored in BoxWord.
00170 void BoxWord::DeleteAllBoxes() {
00171   length_ = 0;
00172   boxes_.clear();
00173   bbox_ = TBOX();
00174 }
00175 
00176 // Computes the bounding box of the word.
00177 void BoxWord::ComputeBoundingBox() {
00178   bbox_ = TBOX();
00179   for (int i = 0; i < length_; ++i)
00180     bbox_ += boxes_[i];
00181 }
00182 
00183 // This and other putatively are the same, so call the (permanent) callback
00184 // for each blob index where the bounding boxes match.
00185 // The callback is deleted on completion.
00186 void BoxWord::ProcessMatchedBlobs(const TWERD& other,
00187                                   TessCallback1<int>* cb) const {
00188   for (int i = 0; i < length_ && i < other.NumBlobs(); ++i) {
00189     TBOX blob_box = other.blobs[i]->bounding_box();
00190     if (blob_box == boxes_[i])
00191       cb->Run(i);
00192   }
00193   delete cb;
00194 }
00195 
00196 }  // namespace tesseract.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines