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-
5142int 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
177168int 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