Skip to content

Commit 35d7858

Browse files
author
Gin
committed
add Home button B detector
1 parent ca88adf commit 35d7858

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/* Button Detector
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include "Kernels/Waterfill/Kernels_Waterfill_Types.h"
8+
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
9+
#include "CommonTools/Images/WaterfillUtilities.h"
10+
#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h"
11+
#include "PokemonHome_ButtonDetector.h"
12+
13+
//#include <iostream>
14+
//using std::cout;
15+
//using std::endl;
16+
17+
namespace PokemonAutomation{
18+
namespace NintendoSwitch{
19+
namespace PokemonHome{
20+
21+
22+
23+
class ButtonMatcher : public ImageMatch::WaterfillTemplateMatcher{
24+
public:
25+
// image template matcher for buttons
26+
// - min_width: candidate image min width if video stream is 4k
27+
// - min_height: candidate image min height if video stream is 4k
28+
ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd);
29+
30+
static const ButtonMatcher& B(){
31+
static ButtonMatcher matcher(ButtonType::ButtonB, 25, 25, 70);
32+
return matcher;
33+
}
34+
35+
36+
virtual bool check_image(Resolution input_resolution, const ImageViewRGB32& image) const override{
37+
size_t min_width = m_min_width * input_resolution.width / 1920;
38+
size_t min_height = m_min_height * input_resolution.height / 1080;
39+
// cout << "???? check_image() ???? min size " << min_width << " x " << min_height
40+
// << " got " << image.width() << " x " << image.height() << endl;
41+
return image.width() >= min_width && image.height() >= min_height;
42+
};
43+
44+
size_t m_min_width;
45+
size_t m_min_height;
46+
double m_max_rmsd;
47+
};
48+
49+
50+
51+
52+
53+
54+
55+
const char* template_path(ButtonType type){
56+
switch (type){
57+
case ButtonType::ButtonB:
58+
return "PokemonHome/Buttons/ButtonB.png";
59+
default:
60+
return "";
61+
}
62+
}
63+
64+
const char* button_name(ButtonType type){
65+
switch (type){
66+
case ButtonType::ButtonB:
67+
return "ButtonB";
68+
default:
69+
return "";
70+
}
71+
}
72+
73+
const ButtonMatcher& get_button_matcher(ButtonType type){
74+
switch (type){
75+
case ButtonType::ButtonB:
76+
return ButtonMatcher::B();
77+
default:
78+
throw std::runtime_error("No corresponding ButtonMatcher for ButtonType");
79+
}
80+
}
81+
82+
83+
84+
ButtonMatcher::ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd)
85+
: WaterfillTemplateMatcher(template_path(type), COLOR_BLACK, COLOR_WHITE, 100)
86+
, m_min_width(min_width)
87+
, m_min_height(min_height)
88+
, m_max_rmsd(max_rmsd)
89+
{}
90+
91+
92+
93+
ButtonDetector::ButtonDetector(
94+
Color color,
95+
ButtonType button_type,
96+
const ImageFloatBox& box,
97+
VideoOverlay* overlay
98+
)
99+
: m_color(color)
100+
, m_matcher(get_button_matcher(button_type))
101+
, m_box(box)
102+
, m_overlay(overlay)
103+
{
104+
105+
}
106+
void ButtonDetector::make_overlays(VideoOverlaySet& items) const{
107+
items.add(m_color, m_box);
108+
}
109+
bool ButtonDetector::detect(const ImageViewRGB32& screen){
110+
111+
const double screen_rel_size = (screen.height() / 1080.0);
112+
const double screen_rel_size_2 = screen_rel_size * screen_rel_size;
113+
114+
const double min_area_1080p = 500.0;
115+
const size_t min_area = size_t(screen_rel_size_2 * min_area_1080p);
116+
117+
const std::vector<std::pair<uint32_t, uint32_t>> FILTERS = {
118+
{0xff000000, 0xffe0e0e0},
119+
{0xff000000, 0xffd0d0d0},
120+
{0xff000000, 0xffc0c0c0},
121+
};
122+
123+
bool found = match_template_by_waterfill(
124+
screen.size(),
125+
extract_box_reference(screen, m_box),
126+
m_matcher,
127+
FILTERS,
128+
{min_area, SIZE_MAX},
129+
m_matcher.m_max_rmsd,
130+
[&](Kernels::Waterfill::WaterfillObject& object) -> bool {
131+
// cout << "width = " << object.width() << ", height = " << object.height() << endl;
132+
m_last_detected = translate_to_parent(screen, m_box, object);
133+
return true;
134+
}
135+
);
136+
137+
if (m_overlay){
138+
if (found){
139+
m_last_detected_box.emplace(*m_overlay, m_last_detected, COLOR_GREEN);
140+
}else{
141+
m_last_detected_box.reset();
142+
}
143+
}
144+
145+
return found;
146+
}
147+
148+
149+
150+
151+
152+
153+
154+
155+
156+
157+
158+
159+
160+
161+
162+
163+
164+
165+
166+
167+
}
168+
}
169+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* Button Detector
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_PokemonHome_ButtonDetector_H
8+
#define PokemonAutomation_PokemonHome_ButtonDetector_H
9+
10+
#include <optional>
11+
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
12+
#include "CommonTools/VisualDetector.h"
13+
#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h"
14+
15+
namespace PokemonAutomation{
16+
class Logger;
17+
namespace NintendoSwitch{
18+
namespace PokemonHome{
19+
20+
21+
enum class ButtonType{
22+
ButtonB,
23+
};
24+
25+
class ButtonMatcher;
26+
27+
28+
29+
30+
class ButtonDetector : public StaticScreenDetector{
31+
public:
32+
ButtonDetector(
33+
Color color,
34+
ButtonType button_type,
35+
const ImageFloatBox& box,
36+
VideoOverlay* overlay = nullptr
37+
);
38+
virtual void make_overlays(VideoOverlaySet& items) const override;
39+
virtual bool detect(const ImageViewRGB32& screen) override;
40+
41+
virtual void reset_state() override { m_last_detected_box.reset(); }
42+
43+
private:
44+
Color m_color;
45+
const ButtonMatcher& m_matcher;
46+
ImageFloatBox m_box;
47+
VideoOverlay* m_overlay;
48+
49+
ImageFloatBox m_last_detected;
50+
std::optional<OverlayBoxScope> m_last_detected_box;
51+
};
52+
class ButtonWatcher : public DetectorToFinder<ButtonDetector>{
53+
public:
54+
ButtonWatcher(
55+
Color color,
56+
ButtonType button_type,
57+
const ImageFloatBox& box,
58+
VideoOverlay* overlay = nullptr,
59+
std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250)
60+
)
61+
: DetectorToFinder("ButtonWatcher", hold_duration, color, button_type, box, overlay)
62+
{}
63+
};
64+
65+
66+
67+
68+
69+
}
70+
}
71+
}
72+
#endif

SerialPrograms/SourceFiles.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,8 @@ file(GLOB LIBRARY_SOURCES
13421342
Source/PokemonHome/Inference/PokemonHome_BallReader.h
13431343
Source/PokemonHome/Inference/PokemonHome_BoxGenderDetector.cpp
13441344
Source/PokemonHome/Inference/PokemonHome_BoxGenderDetector.h
1345+
Source/PokemonHome/Inference/PokemonHome_ButtonDetector.cpp
1346+
Source/PokemonHome/Inference/PokemonHome_ButtonDetector.h
13451347
Source/PokemonHome/PokemonHome_Panels.cpp
13461348
Source/PokemonHome/PokemonHome_Panels.h
13471349
Source/PokemonHome/PokemonHome_Settings.cpp

0 commit comments

Comments
 (0)