Skip to content

Commit 81d38ec

Browse files
committed
update read_number_waterfill(). de-prioritize reads with non-numeric characters
1 parent 9b5e413 commit 81d38ec

File tree

3 files changed

+70
-28
lines changed

3 files changed

+70
-28
lines changed

SerialPrograms/Source/CommonTools/OCR/OCR_NumberReader.cpp

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*
55
*/
66

7+
#include <algorithm>
78
#include <map>
89
#include "Common/Cpp/AbstractLogger.h"
910
#include "Common/Qt/StringToolsQt.h"
@@ -98,10 +99,28 @@ int read_number(Logger& logger, const ImageViewRGB32& image, Language language){
9899
return number;
99100
}
100101

102+
int read_number_waterfill(
103+
Logger& logger, const ImageViewRGB32& image,
104+
uint32_t rgb32_min, uint32_t rgb32_max,
105+
bool text_inside_range
106+
){
107+
std::string ocr_text = read_number_waterfill_no_normalization(logger, image, rgb32_min, rgb32_max, text_inside_range, UINT32_MAX, false);
101108

109+
std::string normalized = run_number_normalization(ocr_text);
102110

111+
if (normalized.empty()){
112+
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> Unable to read.", COLOR_RED);
113+
return -1;
114+
}
103115

104-
int read_number_waterfill(
116+
int number = std::atoi(normalized.c_str());
117+
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> " + std::to_string(number));
118+
119+
return number;
120+
}
121+
122+
123+
std::string read_number_waterfill_no_normalization(
105124
Logger& logger, const ImageViewRGB32& image,
106125
uint32_t rgb32_min, uint32_t rgb32_max,
107126
bool text_inside_range,
@@ -128,8 +147,8 @@ int read_number_waterfill(
128147
WaterfillObject object;
129148
while (map.size() < 16 && iter->find_next(object, true)){
130149
if (object.width() > width_max){
131-
logger.log("Skipped this filter: character exceeded max width.");
132-
return -1;
150+
logger.log("OCR fail: one of characters exceeded max width.", COLOR_RED);
151+
return "";
133152
}
134153
map.emplace(object.min_x, std::move(object));
135154
}
@@ -149,30 +168,27 @@ int read_number_waterfill(
149168
ocr_text += ocr[0];
150169
}else{
151170
if (check_empty_string){
152-
logger.log("Skipped this filter: empty string.");
153-
return -1;
171+
logger.log("OCR fail: one of characters read as empty string.", COLOR_RED);
172+
return "";
154173
}
155174
}
156175
}
157176

158-
std::string normalized = run_number_normalization(ocr_text);
177+
return ocr_text;
159178

160-
if (normalized.empty()){
161-
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> Unable to read.", COLOR_RED);
162-
return -1;
163-
}
164-
165-
int number = std::atoi(normalized.c_str());
166-
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> " + std::to_string(number));
179+
}
167180

168-
return number;
181+
bool is_digits(const std::string &str)
182+
{
183+
return std::all_of(str.begin(), str.end(), ::isdigit);
169184
}
170185

171-
int read_number_waterfill(
186+
int read_number_waterfill_multifilter(
172187
Logger& logger, const ImageViewRGB32& image,
173188
std::vector<std::pair<uint32_t, uint32_t>> filters,
174189
uint32_t width_max,
175-
bool text_inside_range
190+
bool text_inside_range,
191+
bool prioritize_numeric_only_results
176192
){
177193

178194

@@ -181,19 +197,32 @@ int read_number_waterfill(
181197

182198
uint32_t rgb32_min = filter.first;
183199
uint32_t rgb32_max = filter.second;
184-
int candidate = read_number_waterfill(logger, image, rgb32_min, rgb32_max, text_inside_range, width_max, true);
185-
if (candidate != -1){
200+
std::string ocr_text = read_number_waterfill_no_normalization(logger, image, rgb32_min, rgb32_max, text_inside_range, width_max, true);
201+
202+
std::string normalized = run_number_normalization(ocr_text);
203+
if (normalized.empty()){
204+
// logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> Unable to read.", COLOR_RED);
205+
continue;
206+
}
207+
208+
int candidate = std::atoi(normalized.c_str());
209+
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> " + std::to_string(candidate));
210+
211+
if (prioritize_numeric_only_results && is_digits(ocr_text)){
212+
candidates[candidate] += 2;
213+
}else{
186214
candidates[candidate]++;
187215
}
188216
}
189217

190218
if (candidates.empty()){
191-
logger.log("No valid OCR candidates. Unable to read number.");
219+
logger.log("No valid OCR candidates. Unable to read number.", COLOR_ORANGE);
192220
return -1;
193221
}
194222

195223
std::pair<int, uint8_t> best;
196224
for (const auto& item : candidates){
225+
logger.log("Candidate " + std::to_string(item.first) + ": " + std::to_string(item.second) + " votes");
197226
if (item.second > best.second){
198227
best = item;
199228
}

SerialPrograms/Source/CommonTools/OCR/OCR_NumberReader.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,38 @@ int read_number(Logger& logger, const ImageViewRGB32& image, Language language =
2727
// This version attempts to improve reliability by first isolating each number
2828
// via waterfill. Then it OCRs each number by itself and recombines them at the
2929
// end. This requires specifying the color range for the text.
30+
int read_number_waterfill(
31+
Logger& logger, const ImageViewRGB32& image,
32+
uint32_t rgb32_min, uint32_t rgb32_max,
33+
bool text_inside_range = true
34+
);
35+
36+
// run OCR on each individual character in the string of numbers.
37+
// return empty string if OCR fails
3038
//
3139
// text_inside_range: binary filter is applied to the image so that any pixels within the color range will be turned black, and everything else will be white
32-
// width_max: return -1 if any character's width is greater than width_max (likely means that two characters are touching, and so are treated as one large character)
33-
// check_empty_string: if set to true, return -1 (and stop evaluation) if any character returns an empty string from OCR
34-
int read_number_waterfill(
40+
// width_max: return empty string if any character's width is greater than width_max (likely means that two characters are touching, and so are treated as one large character)
41+
// check_empty_string: if set to true, return empty string (and stop evaluation) if any character returns an empty string from OCR
42+
std::string read_number_waterfill_no_normalization(
3543
Logger& logger, const ImageViewRGB32& image,
3644
uint32_t rgb32_min, uint32_t rgb32_max,
3745
bool text_inside_range = true,
3846
uint32_t width_max = UINT32_MAX,
3947
bool check_empty_string = false
4048
);
4149

42-
// Try OCR with all the given color filters.
43-
// Return the best majority candidate
44-
int read_number_waterfill(
50+
// Try OCR with all the given color filters. still running OCR on each individual character
51+
// Return the best majority candidate. return -1 if failed to read.
52+
//
53+
// prioritize_numeric_only_results:
54+
// - if true: if OCR reads only numeric characters, the candidate gets 2 votes. If OCR reads non-numeric characters, the candidate gets only 1 vote.
55+
// - if false: all reads only get 1 vote
56+
int read_number_waterfill_multifilter(
4557
Logger& logger, const ImageViewRGB32& image,
4658
std::vector<std::pair<uint32_t, uint32_t>> filters,
4759
uint32_t width_max,
48-
bool text_inside_range = true
60+
bool text_inside_range = true,
61+
bool prioritize_numeric_only_results = true
4962
);
5063

5164

SerialPrograms/Source/PokemonSV/Inference/ItemPrinter/PokemonSV_ItemPrinterMaterialDetector.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ int16_t ItemPrinterMaterialDetector::read_number(
115115
// {0xff000000, 0xff202020},
116116
// {0xff000000, 0xff101010},
117117
};
118-
number = (int16_t)OCR::read_number_waterfill(logger, cropped, filters, 24);
118+
number = (int16_t)OCR::read_number_waterfill_multifilter(logger, cropped, filters, 24);
119119
}else{
120120
const std::vector<std::pair<uint32_t, uint32_t>> filters = {
121121
{0xff808080, 0xffffffff},
@@ -129,7 +129,7 @@ int16_t ItemPrinterMaterialDetector::read_number(
129129
// {0xffe0e0e0, 0xffffffff},
130130
// {0xfff0f0f0, 0xffffffff},
131131
};
132-
number = (int16_t)OCR::read_number_waterfill(logger, cropped, filters, 24);
132+
number = (int16_t)OCR::read_number_waterfill_multifilter(logger, cropped, filters, 24);
133133
}
134134

135135
if (number < 1 || number > 999){

0 commit comments

Comments
 (0)