void PageIterator::Orientation(tesseract::Orientation *orientation, tesseract::WritingDirection *writing_direction, tesseract::TextlineOrder *textline_order, float *deskew_angle) const { BLOCK* block = it_->block()->block; // Orientation FCOORD up_in_image(0.0, 1.0); up_in_image.unrotate(block->classify_rotation()); up_in_image.rotate(block->re_rotation()); if (up_in_image.x() == 0.0F) { if (up_in_image.y() > 0.0F) { *orientation = ORIENTATION_PAGE_UP; } else { *orientation = ORIENTATION_PAGE_DOWN; } } else if (up_in_image.x() > 0.0F) { *orientation = ORIENTATION_PAGE_RIGHT; } else { *orientation = ORIENTATION_PAGE_LEFT; } // Writing direction bool is_vertical_text = (block->classify_rotation().x() == 0.0); bool right_to_left = block->right_to_left(); *writing_direction = is_vertical_text ? WRITING_DIRECTION_TOP_TO_BOTTOM : (right_to_left ? WRITING_DIRECTION_RIGHT_TO_LEFT : WRITING_DIRECTION_LEFT_TO_RIGHT); // Textline Order bool is_mongolian = false; // TODO(eger): fix me *textline_order = is_vertical_text ? (is_mongolian ? TEXTLINE_ORDER_LEFT_TO_RIGHT : TEXTLINE_ORDER_RIGHT_TO_LEFT) : TEXTLINE_ORDER_TOP_TO_BOTTOM; // Deskew angle FCOORD skew = block->skew(); // true horizontal for textlines *deskew_angle = -skew.angle(); }
// Fits a line in the given direction to blobs that are close to the given // target_offset perpendicular displacement from the direction. The fit // error is allowed to be cheat_allowance worse than the existing fit, and // will still be used. // If cheat_allowance > 0, the new fit will be good and replace the current // fit if it has better fit (with cheat) OR its error is below // max_baseline_error_ and the old fit is marked bad. // Otherwise the new fit will only replace the old if it is really better, // or the old fit is marked bad and the new fit has sufficient points, as // well as being within the max_baseline_error_. void BaselineRow::FitConstrainedIfBetter(int debug, const FCOORD& direction, double cheat_allowance, double target_offset) { double halfrange = fit_halfrange_ * direction.length(); double min_dist = target_offset - halfrange; double max_dist = target_offset + halfrange; ICOORD line_pt; double new_error = fitter_.ConstrainedFit(direction, min_dist, max_dist, debug > 2, &line_pt); // Allow cheat_allowance off the new error new_error -= cheat_allowance; double old_angle = BaselineAngle(); double new_angle = direction.angle(); if (debug > 1) { tprintf("Constrained error = %g, original = %g", new_error, baseline_error_); tprintf(" angles = %g, %g, delta=%g vs threshold %g\n", old_angle, new_angle, new_angle - old_angle, kMaxSkewDeviation); } bool new_good_baseline = new_error <= max_baseline_error_ && (cheat_allowance > 0.0 || fitter_.SufficientPointsForIndependentFit()); // The new will replace the old if any are true: // 1. the new error is better // 2. the old is NOT good, but the new is // 3. there is a wild angular difference between them (assuming that the new // is a better guess at the angle.) if (new_error <= baseline_error_ || (!good_baseline_ && new_good_baseline) || fabs(new_angle - old_angle) > kMaxSkewDeviation) { baseline_error_ = new_error; baseline_pt1_ = line_pt; baseline_pt2_ = baseline_pt1_ + direction; good_baseline_ = new_good_baseline; if (debug > 1) { tprintf("Replacing with constrained baseline, good = %d\n", good_baseline_); } } else if (debug > 1) { tprintf("Keeping old baseline\n"); } }