* Attempt to split off any high (or low) bits at the ends of the word with poor * certainty and recognize them separately. If the certainty gets much better * and other sanity checks pass, acccept. * * This superscript fix is meant to be called in the second pass of recognition * when we have tried once and already have a preliminary answer for word. * * @return Whether we modified the giv
| 99 | * @return Whether we modified the given word. |
| 100 | */ |
| 101 | bool Tesseract::SubAndSuperscriptFix(WERD_RES *word) { |
| 102 | if (word->tess_failed || word->word->flag(W_REP_CHAR) || |
| 103 | !word->best_choice) { |
| 104 | return false; |
| 105 | } |
| 106 | int num_leading, num_trailing; |
| 107 | ScriptPos sp_leading, sp_trailing; |
| 108 | float leading_certainty, trailing_certainty; |
| 109 | float avg_certainty, unlikely_threshold; |
| 110 | |
| 111 | // Calculate the number of whole suspicious characters at the edges. |
| 112 | GetSubAndSuperscriptCandidates( |
| 113 | word, &num_leading, &sp_leading, &leading_certainty, |
| 114 | &num_trailing, &sp_trailing, &trailing_certainty, |
| 115 | &avg_certainty, &unlikely_threshold); |
| 116 | |
| 117 | const char *leading_pos = sp_leading == SP_SUBSCRIPT ? "sub" : "super"; |
| 118 | const char *trailing_pos = sp_trailing == SP_SUBSCRIPT ? "sub" : "super"; |
| 119 | |
| 120 | int num_blobs = word->best_choice->length(); |
| 121 | |
| 122 | // Calculate the remainder (partial characters) at the edges. |
| 123 | // This accounts for us having classified the best version of |
| 124 | // a word as [speaker?'] when it was instead [speaker.^{21}] |
| 125 | // (that is we accidentally thought the 2 was attached to the period). |
| 126 | int num_remainder_leading = 0, num_remainder_trailing = 0; |
| 127 | if (num_leading + num_trailing < num_blobs && unlikely_threshold < 0.0) { |
| 128 | int super_y_bottom = |
| 129 | kBlnBaselineOffset + kBlnXHeight * superscript_min_y_bottom; |
| 130 | int sub_y_top = |
| 131 | kBlnBaselineOffset + kBlnXHeight * subscript_max_y_top; |
| 132 | int last_word_char = num_blobs - 1 - num_trailing; |
| 133 | float last_char_certainty = word->best_choice->certainty(last_word_char); |
| 134 | if (word->best_choice->unichar_id(last_word_char) != 0 && |
| 135 | last_char_certainty <= unlikely_threshold) { |
| 136 | ScriptPos rpos; |
| 137 | YOutlierPieces(word, last_word_char, super_y_bottom, sub_y_top, |
| 138 | NULL, NULL, &rpos, &num_remainder_trailing); |
| 139 | if (num_trailing > 0 && rpos != sp_trailing) num_remainder_trailing = 0; |
| 140 | if (num_remainder_trailing > 0 && |
| 141 | last_char_certainty < trailing_certainty) { |
| 142 | trailing_certainty = last_char_certainty; |
| 143 | } |
| 144 | } |
| 145 | bool another_blob_available = (num_remainder_trailing == 0) || |
| 146 | num_leading + num_trailing + 1 < num_blobs; |
| 147 | int first_char_certainty = word->best_choice->certainty(num_leading); |
| 148 | if (another_blob_available && |
| 149 | word->best_choice->unichar_id(num_leading) != 0 && |
| 150 | first_char_certainty <= unlikely_threshold) { |
| 151 | ScriptPos lpos; |
| 152 | YOutlierPieces(word, num_leading, super_y_bottom, sub_y_top, |
| 153 | &lpos, &num_remainder_leading, NULL, NULL); |
| 154 | if (num_leading > 0 && lpos != sp_leading) num_remainder_leading = 0; |
| 155 | if (num_remainder_leading > 0 && |
| 156 | first_char_certainty < leading_certainty) { |
| 157 | leading_certainty = first_char_certainty; |
| 158 | } |
nothing calls this directly
no test coverage detected