// Helper gets the image of a rectangle, using the block.re_rotation() if // needed to get to the image, and rotating the result back to horizontal // layout. (CJK characters will be on their left sides) The vertical text flag // is set in the returned ImageData if the text was originally vertical, which // can be used to invoke a different CJK recognition engine. The revised_box // is also returned to enable calculation of output bounding boxes. ImageData* Tesseract::GetRectImage(const TBOX& box, const BLOCK& block, int padding, TBOX* revised_box) const { TBOX wbox = box; wbox.pad(padding, padding); *revised_box = wbox; // Number of clockwise 90 degree rotations needed to get back to tesseract // coords from the clipped image. int num_rotations = 0; if (block.re_rotation().y() > 0.0f) num_rotations = 1; else if (block.re_rotation().x() < 0.0f) num_rotations = 2; else if (block.re_rotation().y() < 0.0f) num_rotations = 3; // Handle two cases automatically: 1 the box came from the block, 2 the box // came from a box file, and refers to the image, which the block may not. if (block.bounding_box().major_overlap(*revised_box)) revised_box->rotate(block.re_rotation()); // Now revised_box always refers to the image. // BestPix is never colormapped, but may be of any depth. Pix* pix = BestPix(); int width = pixGetWidth(pix); int height = pixGetHeight(pix); TBOX image_box(0, 0, width, height); // Clip to image bounds; *revised_box &= image_box; if (revised_box->null_box()) return NULL; Box* clip_box = boxCreate(revised_box->left(), height - revised_box->top(), revised_box->width(), revised_box->height()); Pix* box_pix = pixClipRectangle(pix, clip_box, NULL); if (box_pix == NULL) return NULL; boxDestroy(&clip_box); if (num_rotations > 0) { Pix* rot_pix = pixRotateOrth(box_pix, num_rotations); pixDestroy(&box_pix); box_pix = rot_pix; } // Convert sub-8-bit images to 8 bit. int depth = pixGetDepth(box_pix); if (depth < 8) { Pix* grey; grey = pixConvertTo8(box_pix, false); pixDestroy(&box_pix); box_pix = grey; } bool vertical_text = false; if (num_rotations > 0) { // Rotated the clipped revised box back to internal coordinates. FCOORD rotation(block.re_rotation().x(), -block.re_rotation().y()); revised_box->rotate(rotation); if (num_rotations != 2) vertical_text = true; } return new ImageData(vertical_text, box_pix); }
// Build the projection profile given the input_block containing lists of // blobs, a rotation to convert to image coords, // and a full-resolution nontext_map, marking out areas to avoid. // During construction, we have the following assumptions: // The rotation is a multiple of 90 degrees, ie no deskew yet. // The blobs have had their left and right rules set to also limit // the range of projection. void TextlineProjection::ConstructProjection(TO_BLOCK* input_block, const FCOORD& rotation, Pix* nontext_map) { pixDestroy(&pix_); TBOX image_box(0, 0, pixGetWidth(nontext_map), pixGetHeight(nontext_map)); x_origin_ = 0; y_origin_ = image_box.height(); int width = (image_box.width() + scale_factor_ - 1) / scale_factor_; int height = (image_box.height() + scale_factor_ - 1) / scale_factor_; pix_ = pixCreate(width, height, 8); ProjectBlobs(&input_block->blobs, rotation, image_box, nontext_map); ProjectBlobs(&input_block->large_blobs, rotation, image_box, nontext_map); Pix* final_pix = pixBlockconv(pix_, 1, 1); // Pix* final_pix = pixBlockconv(pix_, 2, 2); pixDestroy(&pix_); pix_ = final_pix; }