Skip to content

Commit e27af69

Browse files
author
Gin
committed
Add alert eye symbol detector
1 parent 0b2e543 commit e27af69

File tree

5 files changed

+135
-16
lines changed

5 files changed

+135
-16
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Image icon processor that filters pixels by color range.
4+
Sets pixels within specified color bounds to black with alpha = 0.
5+
"""
6+
7+
import argparse
8+
from PIL import Image
9+
import sys
10+
11+
12+
def parse_color(color_str):
13+
"""Parse color string in format 'R,G,B' to tuple (R, G, B)."""
14+
try:
15+
parts = color_str.split(',')
16+
if len(parts) != 3:
17+
raise ValueError(f"Color must have 3 components, got {len(parts)}")
18+
19+
r, g, b = [int(x.strip()) for x in parts]
20+
21+
if not all(0 <= val <= 255 for val in [r, g, b]):
22+
raise ValueError("Color values must be between 0 and 255")
23+
24+
return (r, g, b)
25+
except Exception as e:
26+
raise ValueError(f"Invalid color format '{color_str}': {e}")
27+
28+
29+
def is_within_bounds(pixel, lower_bound, upper_bound):
30+
"""Check if pixel color is within the specified bounds."""
31+
r, g, b = pixel[:3] # Only check RGB, ignore alpha if present
32+
lr, lg, lb = lower_bound
33+
ur, ug, ub = upper_bound
34+
35+
return (lr <= r <= ur and
36+
lg <= g <= ug and
37+
lb <= b <= ub)
38+
39+
40+
def process_image(input_path, lower_color, upper_color, output_path):
41+
"""
42+
Process image by setting pixels within color bounds to black with alpha = 0.
43+
44+
Args:
45+
input_path: Path to input image
46+
lower_color: Lower bound color tuple (R, G, B)
47+
upper_color: Upper bound color tuple (R, G, B)
48+
output_path: Path to save processed image
49+
"""
50+
try:
51+
# Load image
52+
img = Image.open(input_path)
53+
54+
# Convert to RGBA if not already (to support alpha channel)
55+
if img.mode != 'RGBA':
56+
img = img.convert('RGBA')
57+
58+
# Get pixel data
59+
pixels = img.load()
60+
width, height = img.size
61+
62+
# Process each pixel
63+
count = 0
64+
for y in range(height):
65+
for x in range(width):
66+
pixel = pixels[x, y]
67+
if is_within_bounds(pixel, lower_color, upper_color):
68+
pixels[x, y] = (0, 0, 0, 0) # Black with alpha = 0
69+
count += 1
70+
71+
# Save processed image
72+
img.save(output_path, 'PNG')
73+
print(f"Processed image saved to {output_path}")
74+
print(f"Modified {count} pixels (out of {width * height} total)")
75+
76+
except FileNotFoundError:
77+
print(f"Error: Input file '{input_path}' not found", file=sys.stderr)
78+
sys.exit(1)
79+
except Exception as e:
80+
print(f"Error processing image: {e}", file=sys.stderr)
81+
sys.exit(1)
82+
83+
84+
def main():
85+
parser = argparse.ArgumentParser(
86+
description='Process image icon by filtering pixels within color bounds.',
87+
formatter_class=argparse.RawDescriptionHelpFormatter,
88+
epilog='''
89+
Examples:
90+
%(prog)s input.png "255,0,0" "255,100,100" -o output.png
91+
%(prog)s icon.png "0,0,0" "50,50,50"
92+
'''
93+
)
94+
95+
parser.add_argument('input', help='Path to input image')
96+
parser.add_argument('lower_color', help='Lower bound color in format "R,G,B"')
97+
parser.add_argument('upper_color', help='Upper bound color in format "R,G,B"')
98+
parser.add_argument('-o', '--output', default='output.png',
99+
help='Output path (default: output.png)')
100+
101+
args = parser.parse_args()
102+
103+
# Parse color values
104+
try:
105+
lower = parse_color(args.lower_color)
106+
upper = parse_color(args.upper_color)
107+
except ValueError as e:
108+
print(f"Error: {e}", file=sys.stderr)
109+
sys.exit(1)
110+
111+
# Process the image
112+
process_image(args.input, lower, upper, args.output)
113+
114+
115+
if __name__ == '__main__':
116+
main()

SerialPrograms/Source/Tests/PokemonLZA_Tests.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,17 @@
44
*
55
*/
66

7-
#include "Common/Compiler.h"
87
#include "PokemonLZA_Tests.h"
98
#include "TestUtils.h"
109
#include "CommonFramework/Logging/Logger.h"
11-
#include "CommonFramework/Language.h"
12-
#include "CommonFramework/ImageTools/ImageBoxes.h"
13-
#include "CommonFramework/Recording/StreamHistorySession.h"
14-
#include "NintendoSwitch/NintendoSwitch_ConsoleHandle.h"
1510
#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h"
1611
#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
1712
#include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h"
13+
#include "PokemonLZA/Inference/PokemonLZA_AlertEyeDetector.h"
1814
#include "PokemonLZA/Inference/PokemonLZA_MainMenuDetector.h"
1915
#include "PokemonLZA/Inference/Boxes/PokemonLZA_BoxDetection.h"
20-
#include "PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h"
21-
#include <QFileInfo>
22-
#include <QDir>
23-
#include <algorithm>
24-
#include <cmath>
16+
#include "PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h"
2517
#include <iostream>
26-
#include <iomanip>
27-
#include <sstream>
2818
#include <map>
2919
using std::cout;
3020
using std::cerr;
@@ -123,6 +113,14 @@ int test_pokemonLZA_MainMenuDetector(const ImageViewRGB32& image, bool target){
123113
return 0;
124114
}
125115

116+
int test_pokemonLZA_AlertEyeDetector(const ImageViewRGB32& image, bool target){
117+
auto overlay = DummyVideoOverlay();
118+
AlertEyeDetector detector(COLOR_RED, &overlay);
119+
bool result = detector.detect(image);
120+
TEST_RESULT_EQUAL(result, target);
121+
return 0;
122+
}
123+
126124
int test_pokemonLZA_SelectionArrowDetector(const ImageViewRGB32& image, const std::vector<std::string>& words){
127125
// two words: <situation> <True/False>
128126
if (words.size() < 2){

SerialPrograms/Source/Tests/PokemonLZA_Tests.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
int test_pokemonLZA_MainMenuDetector(const ImageViewRGB32& image, bool target);
3131

32+
int test_pokemonLZA_AlertEyeDetector(const ImageViewRGB32& image, bool target);
33+
3234
int test_pokemonLZA_SelectionArrowDetector(const ImageViewRGB32& image, const std::vector<std::string>& words);
3335

3436
int test_pokemonLZA_BoxCellInfoDetector(const ImageViewRGB32& image, const std::vector<std::string>& words);

SerialPrograms/Source/Tests/TestMap.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ const std::map<std::string, TestFunction> TEST_MAP = {
293293
{"PokemonLZA_BlueDialogDetector", std::bind(image_bool_detector_helper, test_pokemonLZA_BlueDialogDetector, _1)},
294294
{"PokemonLZA_ButtonDetector", std::bind(image_words_detector_helper, test_pokemonLZA_ButtonDetector, _1)},
295295
{"PokemonLZA_MainMenuDetector", std::bind(image_bool_detector_helper, test_pokemonLZA_MainMenuDetector, _1)},
296+
{"PokemonLZA_AlertEyeDetector", std::bind(image_bool_detector_helper, test_pokemonLZA_AlertEyeDetector, _1)},
296297
{"PokemonLZA_BoxCellInfoDetector", std::bind(image_words_detector_helper, test_pokemonLZA_BoxCellInfoDetector, _1)},
297298
{"PokemonLZA_SelectionArrowDetector", std::bind(image_words_detector_helper, test_pokemonLZA_SelectionArrowDetector, _1)},
298299
};

SerialPrograms/SourceFiles.cmake

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ file(GLOB LIBRARY_SOURCES
127127
../Common/Cpp/Options/KeyBindingOption.h
128128
../Common/Cpp/Options/MacAddressOption.cpp
129129
../Common/Cpp/Options/MacAddressOption.h
130-
../Common/Cpp/Options/RandomCodeOption.cpp
131-
../Common/Cpp/Options/RandomCodeOption.h
132130
../Common/Cpp/Options/PathOption.cpp
133131
../Common/Cpp/Options/PathOption.h
132+
../Common/Cpp/Options/RandomCodeOption.cpp
133+
../Common/Cpp/Options/RandomCodeOption.h
134134
../Common/Cpp/Options/SimpleIntegerOption.cpp
135135
../Common/Cpp/Options/SimpleIntegerOption.h
136136
../Common/Cpp/Options/StaticTableOption.cpp
@@ -216,10 +216,10 @@ file(GLOB LIBRARY_SOURCES
216216
../Common/Qt/Options/KeyBindingWidget.h
217217
../Common/Qt/Options/MacAddressWidget.cpp
218218
../Common/Qt/Options/MacAddressWidget.h
219-
../Common/Qt/Options/RandomCodeWidget.cpp
220-
../Common/Qt/Options/RandomCodeWidget.h
221219
../Common/Qt/Options/PathWidget.cpp
222220
../Common/Qt/Options/PathWidget.h
221+
../Common/Qt/Options/RandomCodeWidget.cpp
222+
../Common/Qt/Options/RandomCodeWidget.h
223223
../Common/Qt/Options/SimpleIntegerWidget.cpp
224224
../Common/Qt/Options/SimpleIntegerWidget.h
225225
../Common/Qt/Options/StaticTableWidget.cpp
@@ -1547,6 +1547,8 @@ file(GLOB LIBRARY_SOURCES
15471547
Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxDetection.h
15481548
Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.cpp
15491549
Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h
1550+
Source/PokemonLZA/Inference/PokemonLZA_AlertEyeDetector.cpp
1551+
Source/PokemonLZA/Inference/PokemonLZA_AlertEyeDetector.h
15501552
Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp
15511553
Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h
15521554
Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp

0 commit comments

Comments
 (0)