1414#include " CommonFramework/ProgramStats/StatsTracking.h"
1515#include " CommonFramework/VideoPipeline/VideoFeed.h"
1616#include " CommonFramework/VideoPipeline/VideoOverlayScopes.h"
17+ #include " CommonTools/ImageMatch/ImageCropper.h"
1718#include " CommonTools/Images/BinaryImage_FilterRgb32.h"
1819#include " CommonTools/OCR/OCR_NumberReader.h"
1920#include " CommonTools/Async/InferenceRoutines.h"
@@ -208,7 +209,7 @@ std::vector<std::pair<AuctionOffer, ImageFloatBox>> AuctionFarmer::check_offers(
208209 VideoSnapshot screen = env.console .video ().snapshot ();
209210 std::vector<ImagePixelBox> dialog_boxes = detect_dialog_boxes (screen);
210211 std::deque<OverlayBoxScope> bubbles_boxes;
211- std::deque<OverlayBoxScope> offer_boxes ;
212+ std::deque<OverlayBoxScope> offer_overlay_boxes ;
212213 std::vector<std::pair<AuctionOffer, ImageFloatBox>> offers;
213214
214215 if (dialog_boxes.empty ()){
@@ -217,57 +218,65 @@ std::vector<std::pair<AuctionOffer, ImageFloatBox>> AuctionFarmer::check_offers(
217218 }
218219
219220 // read dialog bubble
221+ ImageFloatBox top_offer_box (0.05 , 0.02 , 0.90 , 0.49 );
222+ ImageFloatBox bottom_offer_box (0.05 , 0.49 , 0.90 , 0.49 );
223+ std::vector<ImageFloatBox> offer_boxes = {top_offer_box};
224+ if (LANGUAGE == Language::Spanish || LANGUAGE == Language::ChineseTraditional) {
225+ offer_boxes.emplace_back (bottom_offer_box);
226+ }
227+
220228 for (ImagePixelBox dialog_box : dialog_boxes){
221- // std::cout << "dialog_box: ["
222- // << dialog_box.min_x << "," << dialog_box.min_y << "] - ["
223- // << dialog_box.max_x << "," << dialog_box.max_y << "]" << std::endl;
229+ for (ImageFloatBox offer_box : offer_boxes) {
230+ // std::cout << "dialog_box: ["
231+ // << dialog_box.min_x << "," << dialog_box.min_y << "] - ["
232+ // << dialog_box.max_x << "," << dialog_box.max_y << "]" << std::endl;
224233
225- ImageFloatBox dialog_float_box = pixelbox_to_floatbox (screen, dialog_box);
226- bubbles_boxes.emplace_back (env.console , dialog_float_box, COLOR_GREEN);
234+ ImageFloatBox dialog_float_box = pixelbox_to_floatbox (screen, dialog_box);
235+ bubbles_boxes.emplace_back (env.console , dialog_float_box, COLOR_GREEN);
227236
228237
229- // OverlayBoxScope dialog_overlay(env.console, dialog_box, COLOR_DARK_BLUE);
230- ImageFloatBox offer_box (0.05 , 0.02 , 0.90 , 0.49 );
231- ImageFloatBox translated_offer_box = translate_to_parent (
232- screen,
233- dialog_float_box,
234- floatbox_to_pixelbox (dialog_box.width (), dialog_box.height (), offer_box)
235- );
236- // std::cout << "translated_offer_box: ["
237- // << translated_offer_box.x << "," << translated_offer_box.y << "] - ["
238- // << translated_offer_box.width << "," << translated_offer_box.height << "]" << std::endl;
238+ // OverlayBoxScope dialog_overlay(env.console, dialog_box, COLOR_DARK_BLUE);
239+ ImageFloatBox translated_offer_box = translate_to_parent (
240+ screen,
241+ dialog_float_box,
242+ floatbox_to_pixelbox (dialog_box.width (), dialog_box.height (), offer_box)
243+ );
244+ // std::cout << "translated_offer_box: ["
245+ // << translated_offer_box.x << "," << translated_offer_box.y << "] - ["
246+ // << translated_offer_box.width << "," << translated_offer_box.height << "]" << std::endl;
239247
240- offer_boxes .emplace_back (env.console , translated_offer_box, COLOR_BLUE);
248+ offer_overlay_boxes .emplace_back (env.console , translated_offer_box, COLOR_BLUE);
241249
242- // OverlayBoxScope offer_overlay(env.console, translated_offer_box, COLOR_BLUE);
243-
244- ImageViewRGB32 dialog = extract_box_reference (screen, dialog_box);
245- ImageViewRGB32 offer_image = extract_box_reference (dialog, offer_box);
250+ // OverlayBoxScope offer_overlay(env.console, translated_offer_box, COLOR_BLUE);
246251
247- // std::cout << offer_image.width() << " x " << offer_image.height() << std::endl;
252+ ImageViewRGB32 dialog = extract_box_reference (screen, dialog_box);
253+ ImageViewRGB32 offer_image = extract_box_reference (dialog, offer_box);
248254
255+ // std::cout << offer_image.width() << " x " << offer_image.height() << std::endl;
249256
250- const double LOG10P_THRESHOLD = -1.5 ;
251- std::string best_item;
252- OCR::StringMatchResult result = AuctionItemNameReader::instance ().read_substring (
253- env.console , LANGUAGE,
254- offer_image,
255- OCR::BLACK_TEXT_FILTERS ()
256- );
257257
258- result.clear_beyond_log10p (LOG10P_THRESHOLD);
259- if (best_item.empty () && !result.results .empty ()){
260- auto iter = result.results .begin ();
261- if (iter->first < LOG10P_THRESHOLD){
262- best_item = iter->second .token ;
258+ const double LOG10P_THRESHOLD = -1.5 ;
259+ std::string best_item;
260+ OCR::StringMatchResult result = AuctionItemNameReader::instance ().read_substring (
261+ env.console , LANGUAGE,
262+ offer_image,
263+ OCR::BLACK_TEXT_FILTERS ()
264+ );
265+
266+ result.clear_beyond_log10p (LOG10P_THRESHOLD);
267+ if (best_item.empty () && !result.results .empty ()) {
268+ auto iter = result.results .begin ();
269+ if (iter->first < LOG10P_THRESHOLD) {
270+ best_item = iter->second .token ;
263271
264- AuctionOffer offer{ best_item };
265- std::pair<AuctionOffer, ImageFloatBox> pair (offer, dialog_float_box);
266- offers.emplace_back (pair);
272+ AuctionOffer offer{ best_item };
273+ std::pair<AuctionOffer, ImageFloatBox> pair (offer, dialog_float_box);
274+ offers.emplace_back (pair);
275+ }
267276 }
268277 }
269278 }
270- // context.wait_for(std::chrono::seconds(100));
279+ // context.wait_for(std::chrono::seconds(100));
271280 return offers;
272281}
273282
@@ -366,17 +375,82 @@ void AuctionFarmer::reset_position(SingleSwitchProgramEnvironment& env, ProContr
366375}
367376
368377
369- uint64_t read_next_bid (VideoStream& stream, ProControllerContext& context, bool high){
378+ uint64_t read_next_bid (VideoStream& stream, ProControllerContext& context, Language language, bool high){
379+ // How much to cut off from the bid text in order to not read currencies and exclamation marks as numbers.
380+ // Values are pixels for a 1920x1080 screen, negative values are padding
381+ static const std::map<Language, std::pair<int8_t , int8_t >> cutoffs = {
382+ { Language::English, {22 , 6 } },
383+ { Language::Japanese, {-5 , 54 } },
384+ { Language::Spanish, {6 , 32 } },
385+ { Language::French, {-5 , 45 } },
386+ { Language::German, {-5 , 22 } },
387+ { Language::Italian, {-5 , 35 } },
388+ { Language::Korean, {-5 , 42 } },
389+ { Language::ChineseSimplified, {22 , 7 } },
390+ { Language::ChineseTraditional, {22 ,7 } }
391+ };
392+
393+
394+ static const std::map<Language, float > high_x = {
395+ { Language::English, 0 .75f },
396+ { Language::Japanese, 0 .75f },
397+ { Language::Spanish, 0 .73f },
398+ { Language::French, 0 .68f },
399+ { Language::German, 0 .73f },
400+ { Language::Italian, 0 .75f },
401+ { Language::Korean, 0 .75f },
402+ { Language::ChineseSimplified, 0 .75f },
403+ { Language::ChineseTraditional, 0 .75f }
404+ };
405+
406+ static const std::map<Language, float > low_x = {
407+ { Language::English, 0 .75f },
408+ { Language::Japanese, 0 .75f },
409+ { Language::Spanish, 0 .75f },
410+ { Language::French, 0 .75f },
411+ { Language::German, 0 .73f },
412+ { Language::Italian, 0 .75f },
413+ { Language::Korean, 0 .75f },
414+ { Language::ChineseSimplified, 0 .75f },
415+ { Language::ChineseTraditional, 0 .75f }
416+ };
417+
370418 float box_y = high ? 0 .42f : 0 .493f ;
371- OverlayBoxScope box (stream.overlay (), { 0.73 , box_y, 0.17 , 0.048 });
419+ float box_x = high ? high_x.at (language) : low_x.at (language);
420+ float width = 0 .9f - box_x; // max_x is always the same for all languages
421+ OverlayBoxScope box (stream.overlay (), { box_x, box_y, width, 0.048 });
422+
372423 std::unordered_map<uint64_t , size_t > read_bids;
373424 size_t highest_read = 0 ;
374425 uint64_t read_value = 0 ;
375426
376427 // read next bid multiple times since the selection arrow sometimes blocks the first digit
377428 for (size_t i = 0 ; i < 10 ; i++){
378429 VideoSnapshot screen = stream.video ().snapshot ();
379- uint64_t read_bid = OCR::read_number (stream.logger (), extract_box_reference (screen, box));
430+ double screen_scale = (double )screen->width () / 1920.0 ;
431+ double vertical_padding = 5.0 ; // small amount of pixels so numbers do not touch the edge of the view when reading them
432+
433+ ImageViewRGB32 raw_bid_image = extract_box_reference (screen, box);
434+ ImagePixelBox bid_bounding_box = ImageMatch::enclosing_rectangle_with_pixel_filter (
435+ raw_bid_image,
436+ [](Color pixel) {
437+ return (uint32_t )pixel.red () + pixel.green () + pixel.blue () < 250 ;
438+ });
439+
440+ int32_t max_width = static_cast <int32_t >(raw_bid_image.width () - 1 );
441+ int32_t max_height = static_cast <int32_t >(raw_bid_image.height () - 1 );
442+ int32_t scaled_vertical_padding = static_cast <int32_t >(vertical_padding * screen_scale);
443+ int32_t left_cutoff = static_cast <int32_t >(cutoffs.at (language).first * screen_scale);
444+ int32_t right_cutoff = static_cast <int32_t >(cutoffs.at (language).second * screen_scale);
445+
446+ ImagePixelBox cut_bid_bounding_box (
447+ std::max (0 , std::min (max_width, static_cast <int32_t >(bid_bounding_box.min_x ) + left_cutoff)),
448+ std::max (0 , std::min (max_height, static_cast <int32_t >(bid_bounding_box.min_y ) - scaled_vertical_padding)),
449+ std::max (0 , std::min (max_width, static_cast <int32_t >(bid_bounding_box.max_x ) - right_cutoff)),
450+ std::max (0 , std::min (max_height, static_cast <int32_t >(bid_bounding_box.max_y ) + scaled_vertical_padding))
451+ );
452+
453+ uint64_t read_bid = OCR::read_number (stream.logger (), extract_box_reference (raw_bid_image, cut_bid_bounding_box));
380454
381455 if (read_bids.find (read_bid) == read_bids.end ()){
382456 read_bids[read_bid] = 0 ;
@@ -418,11 +492,11 @@ void AuctionFarmer::bid_on_item(SingleSwitchProgramEnvironment& env, ProControll
418492 pbf_press_button (context, BUTTON_A, 20 , TICKS_PER_SECOND);
419493 break ;
420494 case 1 :
421- current_bid = read_next_bid (env.console , context, true );
495+ current_bid = read_next_bid (env.console , context, LANGUAGE, true );
422496 pbf_press_button (context, BUTTON_A, 20 , TICKS_PER_SECOND);
423497 break ;
424498 case 2 :
425- current_bid = read_next_bid (env.console , context, false );
499+ current_bid = read_next_bid (env.console , context, LANGUAGE, false );
426500 pbf_press_button (context, BUTTON_A, 20 , TICKS_PER_SECOND);
427501 break ;
428502 case 3 :
0 commit comments