Skip to content

Commit 3bea882

Browse files
author
Gin
committed
update tests
1 parent ccf9b55 commit 3bea882

File tree

4 files changed

+110
-38
lines changed

4 files changed

+110
-38
lines changed

SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,14 @@ std::string BoxPageInfoWatcher::info_str() const{
195195
return "Regular";
196196
}
197197

198-
BoxDexNummberDetector::BoxDexNummberDetector(Logger& logger) : m_logger(logger), m_dex_number_box{0.510, 0.203, 0.039, 0.031}, m_dex_type_box{0.472, 0.204, 0.018, 0.030}{}
198+
BoxDexNumberDetector::BoxDexNumberDetector(Logger& logger) : m_logger(logger), m_dex_number_box{0.510, 0.203, 0.039, 0.031}, m_dex_type_box{0.472, 0.204, 0.018, 0.030}{}
199199

200-
void BoxDexNummberDetector::make_overlays(VideoOverlaySet& items) const{
200+
void BoxDexNumberDetector::make_overlays(VideoOverlaySet& items) const{
201201
items.add(COLOR_GRAY, m_dex_number_box);
202202
items.add(COLOR_GRAY, m_dex_type_box);
203203
}
204204

205-
bool BoxDexNummberDetector::detect(const ImageViewRGB32& screen){
205+
bool BoxDexNumberDetector::detect(const ImageViewRGB32& screen){
206206
const size_t max_dex_number = std::max(LUMIOSE_DEX_SLUGS().size(), HYPERSPACE_DEX_SLUGS().size());
207207

208208
const int dex_number = OCR::read_number_waterfill(m_logger, extract_box_reference(screen, m_dex_number_box), 0xff808080, 0xffffffff, false);

SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,23 @@ enum class DexType{
126126
};
127127

128128

129-
class BoxDexNummberDetector : public StaticScreenDetector{
129+
class BoxDexNumberDetector : public StaticScreenDetector{
130130
public:
131-
BoxDexNummberDetector(Logger& logger);
131+
BoxDexNumberDetector(Logger& logger);
132132

133133
virtual void make_overlays(VideoOverlaySet& items) const override;
134134

135135
virtual bool detect(const ImageViewRGB32& screen) override;
136136

137+
// Return either DexType::LUMIOSE or DexType::HYPERSPACE.
137138
DexType dex_type() const { return m_dex_type; }
139+
// Return dex number (1-indexed).
138140
uint16_t dex_number() const { return m_dex_number; }
139141

140142

141-
// debugging value:
143+
// Debugging value, used to compute whether the pokemon origin symbol is Lumiose or Hyperspace.
142144
double dex_type_color_ratio() const { return m_dex_type_color_ratio; }
143-
// error reporting
145+
// Debugging value, if the detected dex number value is not a correct dex number, what number it is.
144146
int dex_number_when_error() const { return m_dex_number_when_error; }
145147

146148
private:

SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BoxSorter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void print_boxes_data(const std::vector<std::optional<CollectedPokemonInfo>>& bo
138138
env.console.log(ss.str());
139139
}
140140

141-
std::string create_overlay_info(const CollectedPokemonInfo& pokemon, const BoxDexNummberDetector& dex_number_detector){
141+
std::string create_overlay_info(const CollectedPokemonInfo& pokemon, const BoxDexNumberDetector& dex_number_detector){
142142
const std::string& display_name = get_pokemon_name(pokemon.name_slug).display_name();
143143

144144
std::string overlay_log = dex_number_detector.dex_type() == DexType::HYPERSPACE ? "H" : "L";
@@ -247,7 +247,7 @@ void BoxSorter::program(SingleSwitchProgramEnvironment& env, ProControllerContex
247247
BoxShinyDetector shiny_detector(COLOR_RED, &env.console.overlay());
248248
BoxAlphaDetector alpha_detector(COLOR_RED, &env.console.overlay());
249249
SomethingInBoxCellDetector non_empty_detector(COLOR_BLUE, &env.console.overlay());
250-
BoxDexNummberDetector dex_number_detector(env.console);
250+
BoxDexNumberDetector dex_number_detector(env.console);
251251

252252
box_detector.make_overlays(video_overlay_set);
253253
shiny_detector.make_overlays(video_overlay_set);

SerialPrograms/Source/Tests/PokemonLZA_Tests.cpp

Lines changed: 99 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "PokemonLZA_Tests.h"
88
#include "TestUtils.h"
9+
#include "Common/Cpp/Time.h"
910
#include "CommonFramework/Logging/Logger.h"
1011
#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h"
1112
#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
@@ -38,16 +39,6 @@ using namespace NintendoSwitch::PokemonLZA;
3839

3940

4041

41-
int test_pokemonZLA_NormalDialogBoxDetector(const ImageViewRGB32& image, bool target){
42-
auto& logger = global_logger_command_line();
43-
auto overlay = DummyVideoOverlay();
44-
const bool stop_on_detected = true;
45-
NormalDialogDetector detector(logger, overlay, stop_on_detected);
46-
bool result = detector.process_frame(image, current_time());
47-
TEST_RESULT_EQUAL(result, target);
48-
return 0;
49-
}
50-
5142
int test_pokemonLZA_FlatWhiteDialogDetector(const ImageViewRGB32& image, bool target){
5243
auto overlay = DummyVideoOverlay();
5344
FlatWhiteDialogDetector detector(COLOR_RED, &overlay);
@@ -175,44 +166,50 @@ int test_pokemonLZA_SelectionArrowDetector(const ImageViewRGB32& image, const st
175166
}
176167

177168
int test_pokemonLZA_BoxCellInfoDetector(const ImageViewRGB32& image, const std::vector<std::string>& words){
178-
// Expected filename format: <...>_<row>_<col>_<status>.png
179-
// Where status is one of: Empty, Shiny, Alpha, ShinyAlpha
169+
// Expected filename format: <...>_<row>_<col>_<status>_<dex_info>.png
170+
// Where status is one of: Empty, Shiny, Alpha, ShinyAlpha and can be followed by "Held"
171+
// Where dex_info is one of: "None", "L<number>" (Lumiose dex), or "H<number>" (Hyperspace dex)
180172
// Examples:
181-
// test_2_3_Empty.png -> row 2, col 3, empty cell
182-
// test_2_3_Regular.png -> row 2, col 3, non-shiny, non-alpha pokemon
183-
// test_2_3_Shiny.png -> row 2, col 3, shiny (non-alpha)
184-
// test_2_3_Alpha.png -> row 2, col 3, alpha (non-shiny)
185-
// test_2_3_ShinyAlpha.png -> row 2, col 3, shiny alpha
186-
187-
if (words.size() < 3){
188-
cerr << "Error: filename must have at least 3 words (row, col, status)." << endl;
173+
// test_2_3_Empty_None.png -> row 2, col 3, empty cell, no dex number
174+
// test_2_3_Regular_L25.png -> row 2, col 3, non-shiny, non-alpha pokemon, Lumiose dex #25
175+
// test_2_3_Shiny_H100.png -> row 2, col 3, shiny (non-alpha), Hyperspace dex #100
176+
// test_2_3_Alpha_L50.png -> row 2, col 3, alpha (non-shiny), Lumiose dex #50
177+
// test_2_3_ShinyAlphaHeld_H75.png -> row 2, col 3, shiny alpha and holding a pokemon, Hyperspace dex #75
178+
179+
if (words.size() < 4){
180+
cerr << "Error: filename must have at least 4 words (row, col, status, dex_info)." << endl;
189181
return 1;
190182
}
191183

192-
// Parse row from third-to-last word
184+
// Parse row from fourth-to-last word
193185
int expected_row;
194-
if (parse_int(words[words.size() - 3], expected_row) == false){
195-
cerr << "Error: third-to-last word in filename should be row number (0-5)." << endl;
186+
if (parse_int(words[words.size() - 4], expected_row) == false){
187+
cerr << "Error: fourth-to-last word in filename should be row number (0-5)." << endl;
196188
return 1;
197189
}
198190
if (expected_row < 0 || expected_row > 5){
199191
cerr << "Error: row must be between 0 and 5, got " << expected_row << "." << endl;
200192
return 1;
201193
}
202194

203-
// Parse col from second-to-last word
195+
// Parse col from third-to-last word
204196
int expected_col;
205-
if (parse_int(words[words.size() - 2], expected_col) == false){
206-
cerr << "Error: second-to-last word in filename should be col number (0-5)." << endl;
197+
if (parse_int(words[words.size() - 3], expected_col) == false){
198+
cerr << "Error: third-to-last word in filename should be col number (0-5)." << endl;
207199
return 1;
208200
}
209201
if (expected_col < 0 || expected_col > 5){
210202
cerr << "Error: col must be between 0 and 5, got " << expected_col << "." << endl;
211203
return 1;
212204
}
213205

214-
// Parse status from last word
215-
const std::string& status_word = words[words.size() - 1];
206+
// Parse status from second-to-last word
207+
std::string status_word = words[words.size() - 2];
208+
bool holding_pokemon = false;
209+
if (status_word.ends_with("Held")){
210+
holding_pokemon = true;
211+
status_word = status_word.substr(0, status_word.size() - 4);
212+
}
216213
bool expected_something_in_cell;
217214
bool expected_shiny;
218215
bool expected_alpha;
@@ -238,7 +235,31 @@ int test_pokemonLZA_BoxCellInfoDetector(const ImageViewRGB32& image, const std::
238235
expected_shiny = true;
239236
expected_alpha = true;
240237
} else {
241-
cerr << "Error: last word must be 'Empty', 'Shiny', 'Alpha', or 'ShinyAlpha', got '" << status_word << "'." << endl;
238+
cerr << "Error: second-to-last word must be 'Empty', 'Shiny', 'Alpha', or 'ShinyAlpha', got '" << status_word << "'." << endl;
239+
return 1;
240+
}
241+
242+
// Parse dex info from last word
243+
std::string dex_info_word = words[words.size() - 1];
244+
bool expect_dex_detection = false;
245+
DexType expected_dex_type = DexType::LUMIOSE;
246+
uint16_t expected_dex_number = 0;
247+
248+
if (dex_info_word == "None"){
249+
expect_dex_detection = false;
250+
} else if (dex_info_word.size() >= 2 && (dex_info_word[0] == 'L' || dex_info_word[0] == 'H')){
251+
expect_dex_detection = true;
252+
expected_dex_type = (dex_info_word[0] == 'L') ? DexType::LUMIOSE : DexType::HYPERSPACE;
253+
254+
std::string number_str = dex_info_word.substr(1);
255+
int dex_num_int;
256+
if (parse_int(number_str, dex_num_int) == false || dex_num_int <= 0){
257+
cerr << "Error: invalid dex number in '" << dex_info_word << "'. Expected format: L<number> or H<number>." << endl;
258+
return 1;
259+
}
260+
expected_dex_number = static_cast<uint16_t>(dex_num_int);
261+
} else {
262+
cerr << "Error: last word must be 'None', 'L<number>', or 'H<number>', got '" << dex_info_word << "'." << endl;
242263
return 1;
243264
}
244265

@@ -248,7 +269,31 @@ int test_pokemonLZA_BoxCellInfoDetector(const ImageViewRGB32& image, const std::
248269
// Test BoxDetector for row and col
249270
BoxDetector box_detector(COLOR_RED, &overlay);
250271
box_detector.set_debug_mode(true);
272+
box_detector.holding_pokemon(holding_pokemon);
273+
274+
// #define PROFILE_BOX_DETECTION
275+
#ifdef PROFILE_BOX_DETECTION
276+
// Profile the template matching performance
277+
const int num_iterations = 100;
278+
auto time_start = current_time();
279+
bool in_box_system = false;
280+
for (int i = 0; i < num_iterations; i++){
281+
in_box_system = box_detector.detect(image);
282+
}
283+
auto time_end = current_time();
284+
285+
const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(time_end - time_start).count();
286+
const double ms_total = ns / 1000000.0;
287+
const double ms_per_iteration = ms_total / num_iterations;
288+
289+
cout << "BoxDetector::detect() performance:" << endl;
290+
cout << " Total time for " << num_iterations << " iterations: " << ms_total << " ms" << endl;
291+
cout << " Average time per iteration: " << ms_per_iteration << " ms" << endl;
292+
cout << " Throughput: " << (1000.0 / ms_per_iteration) << " detections/second" << endl;
293+
#else
251294
bool in_box_system = box_detector.detect(image);
295+
#endif
296+
252297
if (!in_box_system){
253298
cerr << "Error: BoxDetector did not detect box system view." << endl;
254299
return 1;
@@ -278,6 +323,31 @@ int test_pokemonLZA_BoxCellInfoDetector(const ImageViewRGB32& image, const std::
278323
bool detected_alpha = alpha_detector.detect(image);
279324
TEST_RESULT_COMPONENT_EQUAL(detected_alpha, expected_alpha, "alpha");
280325

326+
// Test BoxDexNumberDetector
327+
if (expect_dex_detection){
328+
BoxDexNumberDetector dex_detector(global_logger_command_line());
329+
bool detected_dex = dex_detector.detect(image);
330+
331+
if (!detected_dex){
332+
cerr << "Error: BoxDexNumberDetector failed to detect dex number." << endl;
333+
return 1;
334+
}
335+
336+
DexType detected_dex_type = dex_detector.dex_type();
337+
uint16_t detected_dex_number = dex_detector.dex_number();
338+
339+
std::string expected_dex_type_str = (expected_dex_type == DexType::LUMIOSE) ? "Lumiose" : "Hyperspace";
340+
std::string detected_dex_type_str = (detected_dex_type == DexType::LUMIOSE) ? "Lumiose" : "Hyperspace";
341+
342+
if (detected_dex_type != expected_dex_type){
343+
cerr << "Error: dex type mismatch. Expected " << expected_dex_type_str
344+
<< " but detected " << detected_dex_type_str << "." << endl;
345+
return 1;
346+
}
347+
348+
TEST_RESULT_COMPONENT_EQUAL((int)detected_dex_number, (int)expected_dex_number, "dex_number");
349+
}
350+
281351
return 0;
282352
}
283353

0 commit comments

Comments
 (0)