Tesseract
3.02
|
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