Tesseract  3.02
tesseract-ocr/cube/search_node.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        search_node.cpp
00003  * Description: Implementation of the Beam Search Node Class
00004  * Author:    Ahmad Abdulkader
00005  * Created:   2008
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 "search_node.h"
00021 
00022 namespace tesseract {
00023 
00024 // The constructor updates the best paths and costs:
00025 //  mean_char_reco_cost_ (returned by BestRecoCost()) is the mean
00026 //    char_reco cost of the best_path, including this node.
00027 //  best_path_reco_cost is the total char_reco_cost of the best_path,
00028 //    but excludes the char_reco_cost of this node.
00029 //  best_cost is the mean mixed cost, i.e., mean_char_reco_cost_ +
00030 //    current language model cost, all weighted by the cube context's
00031 //    RecoWgt parameter
00032 SearchNode::SearchNode(CubeRecoContext *cntxt, SearchNode *parent_node,
00033                        int char_reco_cost, LangModEdge *edge, int col_idx) {
00034   // copy data members
00035   cntxt_ = cntxt;
00036   lang_mod_edge_ = edge;
00037   col_idx_ = col_idx;
00038   parent_node_ = parent_node;
00039   char_reco_cost_ = char_reco_cost;
00040 
00041   // the string of this node is the same as that of the language model edge
00042   str_ = (edge == NULL ? NULL : edge->EdgeString());
00043 
00044   // compute best path total reco cost
00045   best_path_reco_cost_ = (parent_node_ == NULL) ?  0 :
00046       parent_node_->CharRecoCost() + parent_node_->BestPathRecoCost();
00047 
00048   // update best path length
00049   best_path_len_ = (parent_node_ == NULL) ?
00050       1 : parent_node_->BestPathLength() + 1;
00051   if (edge != NULL && edge->IsRoot() && parent_node_ != NULL) {
00052     best_path_len_++;
00053   }
00054 
00055   // compute best reco cost mean cost
00056   mean_char_reco_cost_ = static_cast<int>(
00057       (best_path_reco_cost_ + char_reco_cost_) /
00058       static_cast<double>(best_path_len_));
00059 
00060   // get language model cost
00061   int lm_cost = LangModCost(lang_mod_edge_, parent_node_);
00062 
00063   // compute aggregate best cost
00064   best_cost_ = static_cast<int>(cntxt_->Params()->RecoWgt() *
00065                                 (best_path_reco_cost_ + char_reco_cost_) /
00066                                 static_cast<double>(best_path_len_)
00067                                 ) + lm_cost;
00068 }
00069 
00070 SearchNode::~SearchNode() {
00071   if (lang_mod_edge_ != NULL) {
00072     delete lang_mod_edge_;
00073   }
00074 }
00075 
00076 // update the parent_node node if provides a better (less) cost
00077 bool SearchNode::UpdateParent(SearchNode *new_parent, int new_reco_cost,
00078                               LangModEdge *new_edge) {
00079   if (lang_mod_edge_ == NULL) {
00080     if (new_edge != NULL) {
00081       return false;
00082     }
00083   } else {
00084     // to update the parent_node, we have to have the same target
00085     // state and char
00086     if (new_edge == NULL || !lang_mod_edge_->IsIdentical(new_edge) ||
00087         !SearchNode::IdenticalPath(parent_node_, new_parent)) {
00088       return false;
00089     }
00090   }
00091 
00092   // compute the path cost and combined cost of the new path
00093   int new_best_path_reco_cost;
00094   int new_cost;
00095   int new_best_path_len;
00096 
00097   new_best_path_reco_cost = (new_parent == NULL) ?
00098       0 : new_parent->BestPathRecoCost() + new_parent->CharRecoCost();
00099 
00100   new_best_path_len =
00101       (new_parent == NULL) ? 1 : new_parent->BestPathLength() + 1;
00102 
00103   // compute the new language model cost
00104   int new_lm_cost = LangModCost(new_edge, new_parent);
00105 
00106   new_cost = static_cast<int>(cntxt_->Params()->RecoWgt() *
00107                               (new_best_path_reco_cost + new_reco_cost) /
00108                               static_cast<double>(new_best_path_len)
00109                               ) + new_lm_cost;
00110 
00111   // update if it is better (less) than the current one
00112   if (best_cost_ > new_cost) {
00113     parent_node_ = new_parent;
00114     char_reco_cost_ = new_reco_cost;
00115     best_path_reco_cost_ = new_best_path_reco_cost;
00116     best_path_len_ = new_best_path_len;
00117     mean_char_reco_cost_ = static_cast<int>(
00118         (best_path_reco_cost_ + char_reco_cost_) /
00119         static_cast<double>(best_path_len_));
00120     best_cost_ = static_cast<int>(cntxt_->Params()->RecoWgt() *
00121                                   (best_path_reco_cost_ + char_reco_cost_) /
00122                                   static_cast<double>(best_path_len_)
00123                                   ) + new_lm_cost;
00124     return true;
00125   }
00126   return false;
00127 }
00128 
00129 char_32 *SearchNode::PathString() {
00130   SearchNode *node = this;
00131 
00132   // compute string length
00133   int len = 0;
00134 
00135   while (node != NULL) {
00136     if (node->str_ != NULL) {
00137       len += CubeUtils::StrLen(node->str_);
00138     }
00139 
00140     // if the edge is a root and does not have a NULL parent, account for space
00141     LangModEdge *lm_edge = node->LangModelEdge();
00142     if (lm_edge != NULL && lm_edge->IsRoot() && node->ParentNode() != NULL) {
00143       len++;
00144     }
00145 
00146     node = node->parent_node_;
00147   }
00148 
00149   char_32 *char_ptr = new char_32[len + 1];
00150   if (char_ptr == NULL) {
00151     return NULL;
00152   }
00153 
00154   int ch_idx = len;
00155 
00156   node = this;
00157   char_ptr[ch_idx--] = 0;
00158 
00159   while (node != NULL) {
00160     int str_len = ((node->str_ == NULL) ? 0 : CubeUtils::StrLen(node->str_));
00161     while (str_len > 0) {
00162       char_ptr[ch_idx--] = node->str_[--str_len];
00163     }
00164 
00165     // if the edge is a root and does not have a NULL parent, insert a space
00166     LangModEdge *lm_edge = node->LangModelEdge();
00167     if (lm_edge != NULL && lm_edge->IsRoot() && node->ParentNode() != NULL) {
00168       char_ptr[ch_idx--] = (char_32)' ';
00169     }
00170 
00171     node = node->parent_node_;
00172   }
00173 
00174   return char_ptr;
00175 }
00176 
00177 // compares the path of two nodes and checks if its identical
00178 bool SearchNode::IdenticalPath(SearchNode *node1, SearchNode *node2) {
00179   if (node1 != NULL && node2 != NULL &&
00180       node1->best_path_len_ != node2->best_path_len_) {
00181     return false;
00182   }
00183 
00184   // backtrack until either a root or a NULL edge is reached
00185   while (node1 != NULL && node2 != NULL) {
00186     if (node1->str_ != node2->str_) {
00187       return false;
00188     }
00189 
00190     // stop if either nodes is a root
00191     if (node1->LangModelEdge()->IsRoot() || node2->LangModelEdge()->IsRoot()) {
00192       break;
00193     }
00194 
00195     node1 = node1->parent_node_;
00196     node2 = node2->parent_node_;
00197   }
00198 
00199   return ((node1 == NULL && node2 == NULL) ||
00200           (node1 != NULL && node1->LangModelEdge()->IsRoot() &&
00201            node2 != NULL && node2->LangModelEdge()->IsRoot()));
00202 }
00203 
00204 // Computes the language model cost of a path
00205 int SearchNode::LangModCost(LangModEdge *current_lm_edge,
00206                             SearchNode *parent_node) {
00207   int lm_cost = 0;
00208   int node_cnt = 0;
00209 
00210   do {
00211     // check if root
00212     bool is_root = ((current_lm_edge != NULL && current_lm_edge->IsRoot()) ||
00213                     parent_node == NULL);
00214     if (is_root) {
00215       node_cnt++;
00216       lm_cost += (current_lm_edge == NULL ? 0 : current_lm_edge->PathCost());
00217     }
00218 
00219     // continue until we hit a null parent
00220     if (parent_node == NULL) {
00221       break;
00222     }
00223 
00224     // get the previous language model edge
00225     current_lm_edge = parent_node->LangModelEdge();
00226     // back track
00227     parent_node = parent_node->ParentNode();
00228   } while (true);
00229 
00230   return static_cast<int>(lm_cost / static_cast<double>(node_cnt));
00231 }
00232 }  // namespace tesseract