* Adds sub-pixel resolution EdgeOffsets for the outline using only * a binary image source. * * Runs a sliding window of 5 edge steps over the outline, maintaining a count * of the number of steps in each of the 4 directions in the window, and a * sum of the x or y position of each step (as appropriate to its direction.) * Ignores single-count steps EXCEPT the sharp U-turn and smoothes out t
| 857 | * outline, without losing important detail. |
| 858 | */ |
| 859 | void C_OUTLINE::ComputeBinaryOffsets() { |
| 860 | delete [] offsets; |
| 861 | offsets = new EdgeOffset[stepcount]; |
| 862 | // Count of the number of steps in each direction in the sliding window. |
| 863 | int dir_counts[4]; |
| 864 | // Sum of the positions (y for a horizontal step, x for vertical) in each |
| 865 | // direction in the sliding window. |
| 866 | int pos_totals[4]; |
| 867 | memset(dir_counts, 0, sizeof(dir_counts)); |
| 868 | memset(pos_totals, 0, sizeof(pos_totals)); |
| 869 | ICOORD pos = start; |
| 870 | ICOORD tail_pos = pos; |
| 871 | // tail_pos is the trailing position, with the next point to be lost from |
| 872 | // the window. |
| 873 | tail_pos -= step(stepcount - 1); |
| 874 | tail_pos -= step(stepcount - 2); |
| 875 | // head_pos is the leading position, with the next point to be added to the |
| 876 | // window. |
| 877 | ICOORD head_pos = tail_pos; |
| 878 | // Set up the initial window with 4 points in [-2, 2) |
| 879 | for (int s = -2; s < 2; ++s) { |
| 880 | increment_step(s, 1, &head_pos, dir_counts, pos_totals); |
| 881 | } |
| 882 | for (int s = 0; s < stepcount; pos += step(s++)) { |
| 883 | // At step s, s in in the middle of [s-2, s+2]. |
| 884 | increment_step(s + 2, 1, &head_pos, dir_counts, pos_totals); |
| 885 | int dir_index = chain_code(s); |
| 886 | ICOORD step_vec = step(s); |
| 887 | int best_diff = 0; |
| 888 | int offset = 0; |
| 889 | // Use only steps that have a count of >=2 OR the strong U-turn with a |
| 890 | // single d and 2 at d-1 and 2 at d+1 (mod 4). |
| 891 | if (dir_counts[dir_index] >= 2 || (dir_counts[dir_index] == 1 && |
| 892 | dir_counts[Modulo(dir_index - 1, 4)] == 2 && |
| 893 | dir_counts[Modulo(dir_index + 1, 4)] == 2)) { |
| 894 | // Valid step direction. |
| 895 | best_diff = dir_counts[dir_index]; |
| 896 | int edge_pos = step_vec.x() == 0 ? pos.x() : pos.y(); |
| 897 | // The offset proposes that the actual step should be positioned at |
| 898 | // the mean position of the steps in the window of the same direction. |
| 899 | // See ASCII art above. |
| 900 | offset = pos_totals[dir_index] - best_diff * edge_pos; |
| 901 | } |
| 902 | offsets[s].offset_numerator = |
| 903 | static_cast<inT8>(ClipToRange(offset, -MAX_INT8, MAX_INT8)); |
| 904 | offsets[s].pixel_diff = static_cast<uinT8>(ClipToRange(best_diff, 0 , |
| 905 | MAX_UINT8)); |
| 906 | // The direction is just the vector from start to end of the window. |
| 907 | FCOORD direction(head_pos.x() - tail_pos.x(), head_pos.y() - tail_pos.y()); |
| 908 | offsets[s].direction = direction.to_direction(); |
| 909 | increment_step(s - 2, -1, &tail_pos, dir_counts, pos_totals); |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | /** |
| 914 | * Renders the outline to the given pix, with left and top being |
no test coverage detected