DMZ_INTERNAL void gather_character_rects(GroupedRects &group, const GroupedRects &sub_group) { group.sum += sub_group.sum; if (sub_group.character_rects.size() == 0) { group.character_rects.push_back(CharacterRect(sub_group.top, sub_group.left, sub_group.sum)); } else { group.character_rects.insert(group.character_rects.end(), sub_group.character_rects.begin(), sub_group.character_rects.end()); } }
// FOR CYTHON USE ONLY GroupedRects cythonGroupedRects_to_GroupedRects(CythonGroupedRects *cython_group) { GroupedRects group; group.top = cython_group->top; group.left = cython_group->left; group.width = cython_group->width; group.height = cython_group->height; group.character_width = cython_group->character_width; group.pattern = (ExpiryPattern) cython_group->pattern; group.scores = cythonScores_to_ExpiryGroupScores(cython_group->scores); group.recently_seen_count = cython_group->recently_seen_count; group.total_seen_count = cython_group->total_seen_count; for (int character_index = 0; character_index < cython_group->number_of_character_rects; character_index++) { CythonCharacterRect cython_rect = cython_group->character_rects[character_index]; CharacterRect rect = CharacterRect(cython_rect.top, cython_rect.left, 0); group.character_rects.push_back(rect); } return group; }
DMZ_INTERNAL void regrid_group(IplImage *sobel_image, GroupedRects &group) { // Choose grid-spacing (and starting column) to minimize the sum of pixel-values covered by the grid lines, // while maximizing the sum of pixel-values within the grid squares. // I.e., minimize the ratio of the former to the latter. #define MIN_GRID_SPACING 11 #define MAX_GRID_SPACING 15 int best_grid_spacing = 0; int best_starting_col_offset = 0; float best_ratio = MAXFLOAT; int bounds_left = MAX(group.left - 2 * kSmallCharacterWidth, 0); int bounds_right = MIN(group.left + group.width + 2 * kSmallCharacterWidth, kCreditCardTargetWidth); int bounds_width = bounds_right - bounds_left; int minimum_allowable_number_of_grid_lines = (int)(floorf(float(bounds_width) / float(MIN_GRID_SPACING))); long group_sum = 0; long col_sums[bounds_width]; for (int col = bounds_left; col < bounds_right; col++) { long col_sum = 0; for (int row = group.top; row < group.top + group.height; row++) { col_sum += CV_IMAGE_ELEM(sobel_image, short, row, col); } col_sums[col - bounds_left] = col_sum; group_sum += col_sum; } for (int grid_spacing = MIN_GRID_SPACING; grid_spacing <= MAX_GRID_SPACING; grid_spacing++) { for (int starting_col_offset = 0; starting_col_offset < grid_spacing; starting_col_offset++) { float grid_line_sum = 0.0; int number_of_grid_lines = 0; int grid_line_offset = starting_col_offset; while (grid_line_offset < bounds_width) { number_of_grid_lines += 1; grid_line_sum += col_sums[grid_line_offset]; grid_line_offset += grid_spacing; } float average_grid_line_sum = grid_line_sum / float(number_of_grid_lines); grid_line_sum = average_grid_line_sum * minimum_allowable_number_of_grid_lines; float ratio = grid_line_sum / (group_sum - grid_line_sum); if (ratio < best_ratio) { best_ratio = ratio; best_grid_spacing = grid_spacing; best_starting_col_offset = starting_col_offset; } } } CharacterRectList regridded_rects; int grid_line_offset = best_starting_col_offset; while (grid_line_offset + 1 < bounds_width) { long sum = 0; for (int col = grid_line_offset + 1; col < MIN(grid_line_offset + best_grid_spacing, bounds_width); col++) { sum += col_sums[col]; } regridded_rects.push_back(CharacterRect(group.top, bounds_left + grid_line_offset + 1, sum)); grid_line_offset += best_grid_spacing; } group.character_rects = regridded_rects; group.character_width = best_grid_spacing - 1; group.left = group.character_rects[0].left; group.width = (group.character_rects.end() - 1)->left + group.character_width - group.left; strip_group_white_space(group); }