Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ namespace NintendoSwitch{
namespace PokemonBDSP{


const double STRIPE_TOP = 0.110;
const double STRIPE_TOP_BELOW_BANNER = 0.170;
const double STRIPE_BOTTOM = 0.598;

MenuDetector::MenuDetector(Color color)
static ImageFloatBox menu_stripe(size_t index, bool skip_new_banner){
double top = skip_new_banner ? STRIPE_TOP_BELOW_BANNER : STRIPE_TOP;
return ImageFloatBox(0.160 + 0.166 * (double)index, top, 0.015, STRIPE_BOTTOM - top);
}

MenuDetector::MenuDetector(Color color, bool skip_new_banner)
: m_color(color)
, m_line0(0.160 + 0.166 * 0, 0.110, 0.015, 0.488)
, m_line1(0.160 + 0.166 * 1, 0.110, 0.015, 0.488)
, m_line2(0.160 + 0.166 * 2, 0.110, 0.015, 0.488)
, m_line3(0.160 + 0.166 * 3, 0.110, 0.015, 0.488)
, m_line4(0.160 + 0.166 * 4, 0.110, 0.015, 0.488)
, m_line0(menu_stripe(0, skip_new_banner))
, m_line1(menu_stripe(1, skip_new_banner))
, m_line2(menu_stripe(2, skip_new_banner))
, m_line3(menu_stripe(3, skip_new_banner))
, m_line4(menu_stripe(4, skip_new_banner))
, m_cross(0.20, 0.15, 0.60, 0.37)
{}

Expand Down Expand Up @@ -63,8 +71,8 @@ bool MenuDetector::detect(const ImageViewRGB32& screen){
}


MenuWatcher::MenuWatcher(Color color)
: MenuDetector(color)
MenuWatcher::MenuWatcher(Color color, bool skip_new_banner)
: MenuDetector(color, skip_new_banner)
, VisualInferenceCallback("MenuWatcher")
{}
void MenuWatcher::make_overlays(VideoOverlaySet& items) const{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace PokemonBDSP{

class MenuDetector : public StaticScreenDetector{
public:
MenuDetector(Color color = COLOR_RED);
MenuDetector(Color color = COLOR_RED, bool skip_new_banner = false);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;
Expand All @@ -37,7 +37,7 @@ class MenuDetector : public StaticScreenDetector{

class MenuWatcher : public MenuDetector, public VisualInferenceCallback{
public:
MenuWatcher(Color color = COLOR_RED);
MenuWatcher(Color color = COLOR_RED, bool skip_new_banner = false);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool process_frame(const ImageViewRGB32& frame, WallClock timestamp) override;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* BDSP Summary Reader
*
* From: https://github.com/PokemonAutomation/
*
*/

#include <string>
#include "Common/Cpp/Logging/AbstractLogger.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/OCR/OCR_NumberReader.h"
#include "CommonTools/OCR/OCR_Routines.h"
#include "Pokemon/Inference/Pokemon_NatureReader.h"
#include "PokemonBDSP/Inference/BoxSystem/PokemonBDSP_BoxNatureDetector.h"
#include "PokemonBDSP_SummaryReader.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonBDSP{

using namespace Pokemon;


static const std::vector<OCR::TextColorRange>& MEMO_TEXT_FILTERS(){
static std::vector<OCR::TextColorRange> filters{
// Red.
{0xff600000, 0xffff8080},
{0xff800000, 0xffff6060},
// Black, as a fallback.
{0xff000000, 0xff606060},
{0xff000000, 0xff909090},
};
return filters;
}


const LanguageSet& summary_nature_languages(){
return NATURE_READER().languages();
}


SummaryReader::SummaryReader(Color color)
: m_color(color)
, m_box_nature (0.055, 0.190, 0.410, 0.062)
, m_box_gender (0.790, 0.094, 0.024, 0.040)
, m_box_hp (0.228, 0.168, 0.080, 0.054)
, m_box_attack (0.376, 0.288, 0.048, 0.052)
, m_box_defense(0.376, 0.436, 0.048, 0.052)
, m_box_spatk (0.112, 0.288, 0.048, 0.052)
, m_box_spdef (0.112, 0.436, 0.048, 0.052)
, m_box_speed (0.242, 0.543, 0.048, 0.052)
{}

void SummaryReader::make_memo_overlays(VideoOverlaySet& items) const{
items.add(m_color, m_box_nature, "nature");
items.add(m_color, m_box_gender, "gender");
}

void SummaryReader::make_skills_overlays(VideoOverlaySet& items) const{
items.add(m_color, m_box_gender, "gender");
items.add(m_color, m_box_hp, "hp");
items.add(m_color, m_box_attack, "atk");
items.add(m_color, m_box_defense, "def");
items.add(m_color, m_box_spatk, "spatk");
items.add(m_color, m_box_spdef, "spdef");
items.add(m_color, m_box_speed, "spe");
}


NatureCheckerValue SummaryReader::read_nature(
Logger& logger, Language language, const ImageViewRGB32& frame
) const{
if (language == Language::None){
return NatureCheckerValue::UnableToDetect;
}
ImageViewRGB32 line = extract_box_reference(frame, m_box_nature);
OCR::StringMatchResult result = NATURE_READER().read_substring(
logger, language, line, MEMO_TEXT_FILTERS()
);
result.clear_beyond_log10p(NatureReader::MAX_LOG10P);
if (result.results.size() != 1){
return NatureCheckerValue::UnableToDetect;
}
return NATURE_CHECKER_VALUE_STRINGS().get_enum(result.results.begin()->second.token);
}


BdspGender SummaryReader::read_gender(Logger& logger, const ImageViewRGB32& frame) const{
ImageViewRGB32 box = extract_box_reference(frame, m_box_gender);

size_t blue_pixels = 0;
size_t pink_pixels = 0;
for (size_t y = 0; y < box.height(); y++){
for (size_t x = 0; x < box.width(); x++){
uint32_t pixel = box.pixel(x, y);
uint32_t red = (pixel >> 16) & 0xff;
uint32_t green = (pixel >> 8) & 0xff;
uint32_t blue = pixel & 0xff;
if (blue > red + 40 && blue > green + 20){
blue_pixels++;
}else if (red > green + 40 && blue > green + 40){
pink_pixels++;
}
}
}
logger.log("Gender symbol: " + std::to_string(blue_pixels) + " blue pixels, "
+ std::to_string(pink_pixels) + " pink.");
if (blue_pixels == 0 && pink_pixels == 0){
return BdspGender::Genderless;
}
return blue_pixels > pink_pixels ? BdspGender::Male : BdspGender::Female;
}


int16_t SummaryReader::read_stat(
Logger& logger, const ImageViewRGB32& frame, const ImageFloatBox& box
) const{
ImageViewRGB32 image = extract_box_reference(frame, box);
int value = OCR::read_number_waterfill(logger, image, 0xff000000, 0xff808080);
if (value < 5 || value > 40){
return -1;
}
return (int16_t)value;
}


int16_t SummaryReader::read_hp_total(Logger& logger, const ImageViewRGB32& frame) const{
ImageViewRGB32 image = extract_box_reference(frame, m_box_hp);
int value = OCR::read_number_waterfill(logger, image, 0xff000000, 0xff808080);
if (value < 0){
return -1;
}
std::string digits = std::to_string(value);
if (digits.size() < 2){
// Only the current HP came through, or nothing did. Either way the total is
// not in there.
return -1;
}
int total = std::stoi(digits.substr(digits.size() - 2));
logger.log("HP read as \"" + digits + "\", taking " + std::to_string(total)
+ " as the total.");
if (total < 15 || total > 30){
return -1;
}
return (int16_t)total;
}


StatReads SummaryReader::read_stats(Logger& logger, const ImageViewRGB32& frame) const{
StatReads ret;
ret.hp = read_hp_total(logger, frame);
ret.attack = read_stat(logger, frame, m_box_attack);
ret.defense = read_stat(logger, frame, m_box_defense);
ret.spatk = read_stat(logger, frame, m_box_spatk);
ret.spdef = read_stat(logger, frame, m_box_spdef);
ret.speed = read_stat(logger, frame, m_box_speed);
return ret;
}


}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* BDSP Summary Reader
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonBDSP_SummaryReader_H
#define PokemonAutomation_PokemonBDSP_SummaryReader_H

#include <stdint.h>
#include "Common/Cpp/Color.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonFramework/Language.h"
#include "Pokemon/Pokemon_BdspRng.h"
#include "Pokemon/Pokemon_NatureChecker.h"
#include "Pokemon/Pokemon_StatsCalculation.h"

namespace PokemonAutomation{
class Logger;
class ImageViewRGB32;
class VideoOverlaySet;
namespace NintendoSwitch{
namespace PokemonBDSP{


const LanguageSet& summary_nature_languages();


class SummaryReader{
public:
SummaryReader(Color color = COLOR_RED);

void make_memo_overlays(VideoOverlaySet& items) const;
void make_skills_overlays(VideoOverlaySet& items) const;

Pokemon::NatureCheckerValue read_nature(
Logger& logger, Language language, const ImageViewRGB32& frame
) const;

Pokemon::BdspGender read_gender(Logger& logger, const ImageViewRGB32& frame) const;

Pokemon::StatReads read_stats(Logger& logger, const ImageViewRGB32& frame) const;

private:
int16_t read_stat(
Logger& logger, const ImageViewRGB32& frame, const ImageFloatBox& box
) const;

int16_t read_hp_total(Logger& logger, const ImageViewRGB32& frame) const;

Color m_color;
ImageFloatBox m_box_nature;
ImageFloatBox m_box_gender;
ImageFloatBox m_box_hp;
ImageFloatBox m_box_attack;
ImageFloatBox m_box_defense;
ImageFloatBox m_box_spatk;
ImageFloatBox m_box_spdef;
ImageFloatBox m_box_speed;
};


}
}
}
#endif
2 changes: 2 additions & 0 deletions SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

#include "Programs/TestPrograms/PokemonBDSP_ShinyEncounterTester.h"
#include "Programs/TestPrograms/PokemonBDSP_SoundListener.h"
#include "Programs/TestPrograms/PokemonBDSP_SummaryReaderTester.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
Expand Down Expand Up @@ -103,6 +104,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
ret.emplace_back("---- Developer Tools ----");
ret.emplace_back(make_single_switch_program<ShinyEncounterTester_Descriptor, ShinyEncounterTester>());
ret.emplace_back(make_single_switch_program<SoundListener_Descriptor, SoundListener>());
ret.emplace_back(make_single_switch_program<SummaryReaderTester_Descriptor, SummaryReaderTester>());
}

return ret;
Expand Down
Loading
Loading