Tesseract
3.02
|
00001 00002 // File: workingpartset.cpp 00003 // Description: Class to hold a working set of partitions of the page 00004 // during construction of text/image regions. 00005 // Author: Ray Smith 00006 // Created: Tue Ocr 28 17:21:01 PDT 2008 00007 // 00008 // (C) Copyright 2008, Google Inc. 00009 // Licensed under the Apache License, Version 2.0 (the "License"); 00010 // you may not use this file except in compliance with the License. 00011 // You may obtain a copy of the License at 00012 // http://www.apache.org/licenses/LICENSE-2.0 00013 // Unless required by applicable law or agreed to in writing, software 00014 // distributed under the License is distributed on an "AS IS" BASIS, 00015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 // See the License for the specific language governing permissions and 00017 // limitations under the License. 00018 // 00020 00021 #include "workingpartset.h" 00022 #include "colpartition.h" 00023 00024 namespace tesseract { 00025 00026 ELISTIZE(WorkingPartSet) 00027 00028 // Add the partition to this WorkingPartSet. Unrelated partitions are 00029 // stored in the order in which they are received, but if the partition 00030 // has a SingletonPartner, make sure that it stays with its partner. 00031 void WorkingPartSet::AddPartition(ColPartition* part) { 00032 ColPartition* partner = part->SingletonPartner(true); 00033 if (partner != NULL) { 00034 ASSERT_HOST(partner->SingletonPartner(false) == part); 00035 } 00036 if (latest_part_ == NULL || partner == NULL) { 00037 // This partition goes at the end of the list 00038 part_it_.move_to_last(); 00039 } else if (latest_part_->SingletonPartner(false) != part) { 00040 // Reposition the iterator to the correct partner, or at the end. 00041 for (part_it_.move_to_first(); !part_it_.at_last() && 00042 part_it_.data() != partner; 00043 part_it_.forward()); 00044 } 00045 part_it_.add_after_then_move(part); 00046 latest_part_ = part; 00047 } 00048 00049 // Make blocks out of any partitions in this WorkingPartSet, and append 00050 // them to the end of the blocks list. bleft, tright and resolution give 00051 // the bounds and resolution of the source image, so that blocks can be 00052 // made to fit in the bounds. 00053 // All ColPartitions go in the used_parts list, as they need to be kept 00054 // around, but are no longer needed. 00055 void WorkingPartSet::ExtractCompletedBlocks(const ICOORD& bleft, 00056 const ICOORD& tright, 00057 int resolution, 00058 ColPartition_LIST* used_parts, 00059 BLOCK_LIST* blocks, 00060 TO_BLOCK_LIST* to_blocks) { 00061 MakeBlocks(bleft, tright, resolution, used_parts); 00062 BLOCK_IT block_it(blocks); 00063 block_it.move_to_last(); 00064 block_it.add_list_after(&completed_blocks_); 00065 TO_BLOCK_IT to_block_it(to_blocks); 00066 to_block_it.move_to_last(); 00067 to_block_it.add_list_after(&to_blocks_); 00068 } 00069 00070 // Insert the given blocks at the front of the completed_blocks_ list so 00071 // they can be kept in the correct reading order. 00072 void WorkingPartSet::InsertCompletedBlocks(BLOCK_LIST* blocks, 00073 TO_BLOCK_LIST* to_blocks) { 00074 BLOCK_IT block_it(&completed_blocks_); 00075 block_it.add_list_before(blocks); 00076 TO_BLOCK_IT to_block_it(&to_blocks_); 00077 to_block_it.add_list_before(to_blocks); 00078 } 00079 00080 // Make a block using lines parallel to the given vector that fit between 00081 // the min and max coordinates specified by the ColPartitions. 00082 // Construct a block from the given list of partitions. 00083 void WorkingPartSet::MakeBlocks(const ICOORD& bleft, const ICOORD& tright, 00084 int resolution, ColPartition_LIST* used_parts) { 00085 part_it_.move_to_first(); 00086 while (!part_it_.empty()) { 00087 // Gather a list of ColPartitions in block_parts that will be split 00088 // by linespacing into smaller blocks. 00089 ColPartition_LIST block_parts; 00090 ColPartition_IT block_it(&block_parts); 00091 ColPartition* next_part = NULL; 00092 bool text_block = false; 00093 do { 00094 ColPartition* part = part_it_.extract(); 00095 if (part->blob_type() == BRT_UNKNOWN || part->blob_type() == BRT_TEXT) 00096 text_block = true; 00097 part->set_working_set(NULL); 00098 part_it_.forward(); 00099 block_it.add_after_then_move(part); 00100 next_part = part->SingletonPartner(false); 00101 if (part_it_.empty() || next_part != part_it_.data()) { 00102 // Sequences of partitions can get split by titles. 00103 next_part = NULL; 00104 } 00105 // Merge adjacent blocks that are of the same type and let the 00106 // linespacing determine the real boundaries. 00107 if (next_part == NULL && !part_it_.empty()) { 00108 ColPartition* next_block_part = part_it_.data(); 00109 const TBOX& part_box = part->bounding_box(); 00110 const TBOX& next_box = next_block_part->bounding_box(); 00111 00112 // In addition to the same type, the next box must not be above the 00113 // current box, nor (if image) too far below. 00114 PolyBlockType type = part->type(), next_type = next_block_part->type(); 00115 if (ColPartition::TypesSimilar(type, next_type) && 00116 next_box.bottom() <= part_box.top() && 00117 (text_block || 00118 part_box.bottom() - next_box.top() < part_box.height())) 00119 next_part = next_block_part; 00120 } 00121 } while (!part_it_.empty() && next_part != NULL); 00122 if (!text_block) { 00123 TO_BLOCK* to_block = ColPartition::MakeBlock(bleft, tright, 00124 &block_parts, used_parts); 00125 if (to_block != NULL) { 00126 TO_BLOCK_IT to_block_it(&to_blocks_); 00127 to_block_it.add_to_end(to_block); 00128 BLOCK_IT block_it(&completed_blocks_); 00129 block_it.add_to_end(to_block->block); 00130 } 00131 } else { 00132 // Further sub-divide text blocks where linespacing changes. 00133 ColPartition::LineSpacingBlocks(bleft, tright, resolution, &block_parts, 00134 used_parts, 00135 &completed_blocks_, &to_blocks_); 00136 } 00137 } 00138 part_it_.set_to_list(&part_set_); 00139 latest_part_ = NULL; 00140 ASSERT_HOST(completed_blocks_.length() == to_blocks_.length()); 00141 } 00142 00143 } // namespace tesseract.