Skip to content

Commit db560e7

Browse files
committed
update read_number_waterfill()
1 parent 3972b8c commit db560e7

File tree

3 files changed

+85
-76
lines changed

3 files changed

+85
-76
lines changed

SerialPrograms/Source/CommonTools/OCR/OCR_NumberReader.cpp

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -102,97 +102,104 @@ int read_number(Logger& logger, const ImageViewRGB32& image, Language language){
102102

103103
int read_number_waterfill(
104104
Logger& logger, const ImageViewRGB32& image,
105-
uint32_t rgb32_min, uint32_t rgb32_max,
106-
bool text_inside_range
107-
){
108-
const std::vector<std::pair<uint32_t, uint32_t>> filters = {
109-
{rgb32_min, rgb32_max}
110-
};
111-
return read_number_waterfill(logger, image, filters, UINT32_MAX, text_inside_range);
112-
}
113-
114-
int read_number_waterfill(
115-
Logger& logger, const ImageViewRGB32& image,
116-
std::vector<std::pair<uint32_t, uint32_t>> filters,
105+
uint32_t rgb32_min, uint32_t rgb32_max,
106+
bool text_inside_range,
117107
uint32_t width_max,
118-
bool text_inside_range
108+
bool check_empty_string
119109
){
120110
using namespace Kernels::Waterfill;
121111

112+
// Direct OCR is unreliable. Instead, we will waterfill each character
113+
// to isolate them, then OCR them individually.
122114

115+
ImageRGB32 filtered = to_blackwhite_rgb32_range(image, rgb32_min, rgb32_max, text_inside_range);
123116

124-
for (std::pair<uint32_t, uint32_t> filter : filters){
117+
// static int c = 0;
118+
// int i = 0;
119+
// filtered.save("test-" + std::to_string(c++) + ".png");
125120

126-
uint32_t rgb32_min = filter.first;
127-
uint32_t rgb32_max = filter.second;
128-
129-
// Direct OCR is unreliable. Instead, we will waterfill each character
130-
// to isolate them, then OCR them individually.
131-
132-
ImageRGB32 filtered = to_blackwhite_rgb32_range(image, rgb32_min, rgb32_max, text_inside_range);
133-
134-
// static int c = 0;
135-
// int i = 0;
136-
// filtered.save("test-" + std::to_string(c++) + ".png");
137-
138-
PackedBinaryMatrix matrix = compress_rgb32_to_binary_range(filtered, 0xff000000, 0xff7f7f7f);
139-
140-
std::map<size_t, WaterfillObject> map;
141-
{
142-
std::unique_ptr<WaterfillSession> session = make_WaterfillSession(matrix);
143-
auto iter = session->make_iterator(20);
144-
WaterfillObject object;
145-
bool exceed_width_max = false;
146-
while (map.size() < 16 && iter->find_next(object, true)){
147-
if (object.width() > width_max){
148-
exceed_width_max = true;
149-
break;
150-
}
151-
map.emplace(object.min_x, std::move(object));
152-
}
153-
if (exceed_width_max){
154-
// try the next color filter
155-
continue;
121+
PackedBinaryMatrix matrix = compress_rgb32_to_binary_range(filtered, 0xff000000, 0xff7f7f7f);
122+
123+
std::map<size_t, WaterfillObject> map;
124+
{
125+
std::unique_ptr<WaterfillSession> session = make_WaterfillSession(matrix);
126+
auto iter = session->make_iterator(20);
127+
WaterfillObject object;
128+
while (map.size() < 16 && iter->find_next(object, true)){
129+
if (object.width() > width_max){
130+
logger.log("Skipped this filter: character exceeded max width.");
131+
return -1;
156132
}
133+
map.emplace(object.min_x, std::move(object));
157134
}
135+
}
158136

159-
std::string ocr_text;
160-
bool empty_char = false;
161-
for (const auto& item : map){
162-
const WaterfillObject& object = item.second;
163-
ImageRGB32 cropped = extract_box_reference(filtered, object).copy();
164-
PackedBinaryMatrix tmp(object.packed_matrix());
165-
filter_by_mask(tmp, cropped, Color(0xffffffff), true);
166-
ImageRGB32 padded = pad_image(cropped, cropped.width(), 0xffffffff);
167-
std::string ocr = OCR::ocr_read(Language::English, padded);
168-
// padded.save("test-cropped" + std::to_string(c) + "-" + std::to_string(i++) + ".png");
169-
// std::cout << ocr[0] << std::endl;
170-
if (!ocr.empty()){
171-
ocr_text += ocr[0];
172-
}else{
173-
empty_char = true;
174-
break;
137+
std::string ocr_text;
138+
for (const auto& item : map){
139+
const WaterfillObject& object = item.second;
140+
ImageRGB32 cropped = extract_box_reference(filtered, object).copy();
141+
PackedBinaryMatrix tmp(object.packed_matrix());
142+
filter_by_mask(tmp, cropped, Color(0xffffffff), true);
143+
ImageRGB32 padded = pad_image(cropped, cropped.width(), 0xffffffff);
144+
std::string ocr = OCR::ocr_read(Language::English, padded);
145+
// padded.save("test-cropped" + std::to_string(c) + "-" + std::to_string(i++) + ".png");
146+
// std::cout << ocr[0] << std::endl;
147+
if (!ocr.empty()){
148+
ocr_text += ocr[0];
149+
}else{
150+
if (check_empty_string){
151+
logger.log("Skipped this filter: empty string.");
152+
return -1;
175153
}
176154
}
177-
if (empty_char){
178-
// try the next color filter
179-
continue;
180-
}
155+
}
156+
157+
std::string normalized = run_number_normalization(ocr_text);
158+
159+
if (normalized.empty()){
160+
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> Unable to read.", COLOR_RED);
161+
return -1;
162+
}
163+
164+
int number = std::atoi(normalized.c_str());
165+
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> " + std::to_string(number));
166+
167+
return number;
168+
}
169+
170+
int read_number_waterfill(
171+
Logger& logger, const ImageViewRGB32& image,
172+
std::vector<std::pair<uint32_t, uint32_t>> filters,
173+
uint32_t width_max,
174+
bool text_inside_range
175+
){
176+
181177

182-
std::string normalized = run_number_normalization(ocr_text);
178+
std::map<int, uint8_t> candidates;
179+
for (std::pair<uint32_t, uint32_t> filter : filters){
183180

184-
if (normalized.empty()){
185-
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> Unable to read.", COLOR_RED);
186-
return -1;
181+
uint32_t rgb32_min = filter.first;
182+
uint32_t rgb32_max = filter.second;
183+
int candidate = read_number_waterfill(logger, image, rgb32_min, rgb32_max, text_inside_range, width_max, true);
184+
if (candidate != -1){
185+
candidates[candidate]++;
187186
}
187+
}
188188

189-
int number = std::atoi(normalized.c_str());
190-
logger.log("OCR Text: \"" + ocr_text + "\" -> \"" + normalized + "\" -> " + std::to_string(number));
189+
if (candidates.empty()){
190+
logger.log("Unable to read number.");
191+
return -1;
192+
}
191193

192-
return number;
194+
std::pair<int, uint8_t> best;
195+
for (const auto& item : candidates){
196+
if (item.second > best.second){
197+
best = item;
198+
}
193199
}
194200

195-
return -1;
201+
logger.log("Best candidate: --------------------------> " + std::to_string(best.first));
202+
return best.first;
196203
}
197204

198205

SerialPrograms/Source/CommonTools/OCR/OCR_NumberReader.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ int read_number(Logger& logger, const ImageViewRGB32& image, Language language =
3030
int read_number_waterfill(
3131
Logger& logger, const ImageViewRGB32& image,
3232
uint32_t rgb32_min, uint32_t rgb32_max,
33-
bool text_inside_range = true
33+
bool text_inside_range = true,
34+
uint32_t width_max = UINT32_MAX,
35+
bool check_empty_string = false
3436
);
3537

3638
// applies color filters on the text, until each individual waterfilled character/number is less than width_max. then apply OCR.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ int16_t ItemPrinterMaterialDetector::read_number(
119119
{0xffa0a0a0, 0xffffffff},
120120
{0xffb0b0b0, 0xffffffff},
121121
{0xffc0c0c0, 0xffffffff},
122-
{0xffd0d0d0, 0xffffffff},
123-
{0xffe0e0e0, 0xffffffff},
124-
{0xfff0f0f0, 0xffffffff},
122+
// {0xffd0d0d0, 0xffffffff},
123+
// {0xffe0e0e0, 0xffffffff},
124+
// {0xfff0f0f0, 0xffffffff},
125125
};
126126
number = (int16_t)OCR::read_number_waterfill(logger, cropped, filters, 24);
127127
}

0 commit comments

Comments
 (0)