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
41 changes: 20 additions & 21 deletions SerialPrograms/Source/Pokemon/Inference/Pokemon_TypeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,12 @@ namespace Pokemon {
using namespace Kernels;
using namespace Kernels::Waterfill;


class TypeSprite {
public:
TypeSprite(const std::string& slug, PokemonTypeGeneration generation)
TypeSprite(const std::string& slug, const std::string& resource_location)
: m_slug(slug)
{
ImageRGB32 sprite;
switch (generation)
{
case PokemonAutomation::Pokemon::PokemonTypeGeneration::GEN8:
sprite = ImageRGB32(RESOURCE_PATH() + "Pokemon/Types/Gen8/" + slug + ".png");
break;
case PokemonAutomation::Pokemon::PokemonTypeGeneration::GEN9:
sprite = ImageRGB32(RESOURCE_PATH() + "Pokemon/Types/Gen9/" + slug + ".png");
break;
default:
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid enum.");
}
ImageRGB32 sprite(RESOURCE_PATH() + resource_location);

sprite = filter_rgb32_range(
sprite,
Expand Down Expand Up @@ -85,7 +73,7 @@ struct Gen8TypeSpriteDatabase {
if (item.first == PokemonType::NONE){
continue;
}
m_type_map.emplace(item.first, TypeSprite(item.second, PokemonTypeGeneration::GEN8));
m_type_map.emplace(item.first, TypeSprite(item.second, "Pokemon/Types/Gen8/" + item.second + ".png"));
}
}
};
Expand All @@ -103,7 +91,7 @@ struct Gen9TypeSpriteDatabase {
if (item.first == PokemonType::NONE){
continue;
}
m_type_map.emplace(item.first, TypeSprite(item.second, PokemonTypeGeneration::GEN9));
m_type_map.emplace(item.first, TypeSprite(item.second, "Pokemon/Types/Gen9/" + item.second + ".png"));
}
}
};
Expand Down Expand Up @@ -132,26 +120,38 @@ size_t distance_sqr(const ImagePixelBox& a, const ImagePixelBox& b){
return dist_x * dist_x + dist_y * dist_y;
}

std::pair<double, PokemonType> match_type_symbol(const ImageViewRGB32& image, PokemonTypeGeneration generation){
bool image_validation(const ImageViewRGB32& image){
size_t width = image.width();
size_t height = image.height();
if (width * height < 100){
return { 1.0, PokemonType::NONE };
return false;
}
if (width > 2 * height){
return { 1.0, PokemonType::NONE };
return false;
}
if (height > 2 * width){
return { 1.0, PokemonType::NONE };
return false;
}
ImageStats stats = image_stats(image);
if (stats.stddev.sum() < 50){
// if (print){
// cout << "stats.stddev.sum() = " << stats.stddev.sum() << endl;
// }
return false;
}

return true;
}

std::pair<double, PokemonType> match_type_symbol(const ImageViewRGB32& image, PokemonTypeGeneration generation){

if (!image_validation(image)){
return { 1.0, PokemonType::NONE };
}

size_t width = image.width();
size_t height = image.height();

double aspect_ratio = (double)width / height;

// static int c = 0;
Expand Down Expand Up @@ -309,7 +309,6 @@ void find_type_symbol_candidates(
// cout << "candidates = " << candidates.size() << endl;
}


std::multimap<double, std::pair<PokemonType, ImagePixelBox>> find_type_symbols(
const ImageViewPlanar32& original_screen,
const ImageViewRGB32& image,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ enum class SortingRuleType
Alpha,
Ball_Slug,
Gender,
Type
Type,
Tera_Type,
};

struct SortingRule
Expand Down
28 changes: 18 additions & 10 deletions SerialPrograms/Source/Pokemon/Pokemon_CollectedPokemonInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ bool operator==(const CollectedPokemonInfo& lhs, const CollectedPokemonInfo& rhs
lhs.ball_slug == rhs.ball_slug &&
lhs.gender == rhs.gender &&
lhs.ot_id == rhs.ot_id &&
lhs.primaryType == rhs.primaryType &&
lhs.secondaryType == rhs.secondaryType;
lhs.primary_type == rhs.primary_type &&
lhs.secondary_type == rhs.secondary_type &&
lhs.tera_type == rhs.tera_type;
}


Expand Down Expand Up @@ -75,11 +76,16 @@ bool operator<(const std::optional<CollectedPokemonInfo>& lhs, const std::option
}
break;
case SortingRuleType::Type:
if (lhs->primaryType != rhs->primaryType){
return (lhs->primaryType < rhs->primaryType) != preference.reverse;
if (lhs->primary_type != rhs->primary_type){
return (lhs->primary_type < rhs->primary_type) != preference.reverse;
}
if (lhs->secondaryType != rhs->secondaryType){
return (lhs->secondaryType < rhs->secondaryType) != preference.reverse;
if (lhs->secondary_type != rhs->secondary_type){
return (lhs->secondary_type < rhs->secondary_type) != preference.reverse;
}
break;
case SortingRuleType::Tera_Type:
if (lhs->tera_type != rhs->tera_type){
return (lhs->tera_type < rhs->tera_type) != preference.reverse;
}
break;
default:
Expand All @@ -103,8 +109,9 @@ std::ostream& operator<<(std::ostream& os, const std::optional<CollectedPokemonI
os << "ball:" << pokemon->ball_slug << " ";
os << "gender:" << gender_to_string(pokemon->gender) << " ";
os << "ot_id:" << pokemon->ot_id << " ";
os << "primaryType:" << POKEMON_TYPE_SLUGS().get_string(pokemon->primaryType) << " ";
os << "secondaryType:" << POKEMON_TYPE_SLUGS().get_string(pokemon->secondaryType) << " ";
os << "primaryType:" << POKEMON_TYPE_SLUGS().get_string(pokemon->primary_type) << " ";
os << "secondaryType:" << POKEMON_TYPE_SLUGS().get_string(pokemon->secondary_type) << " ";
os << "teraType:" << POKEMON_TERA_TYPE_SLUGS().get_string(pokemon->tera_type) << " ";
os << ")";
}else{
os << "(empty)";
Expand Down Expand Up @@ -155,8 +162,9 @@ void save_boxes_data_to_json(const std::vector<std::optional<CollectedPokemonInf
pokemon["ball"] = current_pokemon->ball_slug;
pokemon["gender"] = gender_to_string(current_pokemon->gender);
pokemon["ot_id"] = current_pokemon->ot_id;
pokemon["primaryType"] = POKEMON_TYPE_SLUGS().get_string(current_pokemon->primaryType);
pokemon["secondaryType"] = POKEMON_TYPE_SLUGS().get_string(current_pokemon->secondaryType);
pokemon["primary_type"] = POKEMON_TYPE_SLUGS().get_string(current_pokemon->primary_type);
pokemon["secondary_type"] = POKEMON_TYPE_SLUGS().get_string(current_pokemon->secondary_type);
pokemon["tera_type"] = POKEMON_TERA_TYPE_SLUGS().get_string(current_pokemon->tera_type);
}
pokemon_data.push_back(std::move(pokemon));
}
Expand Down
5 changes: 3 additions & 2 deletions SerialPrograms/Source/Pokemon/Pokemon_CollectedPokemonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ struct CollectedPokemonInfo{
std::string ball_slug = "";
StatsHuntGenderFilter gender = StatsHuntGenderFilter::Genderless;
uint32_t ot_id = 0; // original trainer ID
PokemonType primaryType = PokemonType::NONE;
PokemonType secondaryType = PokemonType::NONE;
PokemonType primary_type = PokemonType::NONE;
PokemonType secondary_type = PokemonType::NONE;
PokemonTeraType tera_type = PokemonTeraType::NONE;
};

bool operator==(const CollectedPokemonInfo& lhs, const CollectedPokemonInfo& rhs);
Expand Down
26 changes: 25 additions & 1 deletion SerialPrograms/Source/Pokemon/Pokemon_Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@
namespace PokemonAutomation{
namespace Pokemon{


const EnumStringMap<PokemonTeraType>& POKEMON_TERA_TYPE_SLUGS(){
static EnumStringMap<PokemonTeraType> database{
{PokemonTeraType::BUG, "bug"},
{PokemonTeraType::DARK, "dark"},
{PokemonTeraType::DRAGON, "dragon"},
{PokemonTeraType::ELECTRIC, "electric"},
{PokemonTeraType::FAIRY, "fairy"},
{PokemonTeraType::FIGHTING, "fighting"},
{PokemonTeraType::FIRE, "fire"},
{PokemonTeraType::FLYING, "flying"},
{PokemonTeraType::GHOST, "ghost"},
{PokemonTeraType::GRASS, "grass"},
{PokemonTeraType::GROUND, "ground"},
{PokemonTeraType::ICE, "ice"},
{PokemonTeraType::NONE, "none"},
{PokemonTeraType::NORMAL, "normal"},
{PokemonTeraType::POISON, "poison"},
{PokemonTeraType::PSYCHIC, "psychic"},
{PokemonTeraType::ROCK, "rock"},
{PokemonTeraType::STEEL, "steel"},
{PokemonTeraType::STELLAR, "stellar"},
{PokemonTeraType::WATER, "water"}
};
return database;
}

const EnumStringMap<PokemonType>& POKEMON_TYPE_SLUGS(){
static EnumStringMap<PokemonType> database{
Expand Down
24 changes: 24 additions & 0 deletions SerialPrograms/Source/Pokemon/Pokemon_Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ enum class MoveCategory{
UNKNOWN,
};

enum class PokemonTeraType{
BUG,
DARK,
DRAGON,
ELECTRIC,
FAIRY,
FIGHTING,
FIRE,
FLYING,
GHOST,
GRASS,
GROUND,
ICE,
NONE,
NORMAL,
POISON,
PSYCHIC,
ROCK,
STEEL,
STELLAR,
WATER
};
const EnumStringMap<PokemonTeraType>& POKEMON_TERA_TYPE_SLUGS();

enum class PokemonType{
NONE,
NORMAL,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* Gigantamax Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "Kernels/Waterfill/Kernels_Waterfill_Types.h"
#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h"
#include "CommonTools/Images/WaterfillUtilities.h"
#include "PokemonHome_GigantamaxDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonHome{


class GigantamaxMatcher : public ImageMatch::WaterfillTemplateMatcher{
public:
GigantamaxMatcher()
: WaterfillTemplateMatcher(
"PokemonHome/Home_Gigantamax.png",
Color(196, 32, 88), Color(255, 220, 235),
100
)
{
m_aspect_ratio_lower = 0.9;
m_aspect_ratio_upper = 1.1;
m_area_ratio_lower = 0.85;
m_area_ratio_upper = 1.1;
}

static const GigantamaxMatcher& instance(){
static GigantamaxMatcher matcher;
return matcher;
}
};


GigantamaxDetector::GigantamaxDetector(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box
)
: m_color(color)
, m_overlay(overlay)
, m_box(box)
{}
void GigantamaxDetector::make_overlays(VideoOverlaySet& items) const{
items.add(m_color, m_box);
}
bool GigantamaxDetector::detect(const ImageViewRGB32& screen){
const double screen_rel_size = (screen.height() / 1080.0);
const double screen_rel_size_2 = screen_rel_size * screen_rel_size;

const double min_area_1080p = 400;
const double rmsd_threshold = 80;
const size_t min_area = size_t(screen_rel_size_2 * min_area_1080p);

const std::vector<std::pair<uint32_t, uint32_t>> FILTERS = {
{0xffc42058, 0xffffdceb},
};

const bool found = match_template_by_waterfill(
screen.size(),
extract_box_reference(screen, m_box),
GigantamaxMatcher::instance(),
FILTERS,
{min_area, SIZE_MAX},
rmsd_threshold,
[&](Kernels::Waterfill::WaterfillObject& object) -> bool {
m_last_detected = translate_to_parent(screen, m_box, object);
return true;
}
);

if (m_overlay){
if (found){
m_last_detected_box.emplace(*m_overlay, m_last_detected, COLOR_GREEN);
}else{
m_last_detected_box.reset();
}
}

return found;
}


}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Gigantamax Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonHome_GigantamaxDetector_H
#define PokemonAutomation_PokemonHome_GigantamaxDetector_H

#include <optional>
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/VisualDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonHome{


class GigantamaxDetector : public StaticScreenDetector{
public:
GigantamaxDetector(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box
);

const ImageFloatBox& last_detected() const{ return m_last_detected; }

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;

private:
const Color m_color;
VideoOverlay* m_overlay;
const ImageFloatBox m_box;

ImageFloatBox m_last_detected;
std::optional<OverlayBoxScope> m_last_detected_box;
};
class GigantamaxWatcher : public DetectorToFinder<GigantamaxDetector>{
public:
GigantamaxWatcher(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box,
std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250)
)
: DetectorToFinder("GigantamaxWatcher", hold_duration, color, overlay, box)
{}
};


}
}
}
#endif
Loading