Compare commits
No commits in common. "2801a3f4cd6561265280d11368edc0ab51d8f44f" and "f92a3f9a40cc334b0137823f78aa38dc818b6db6" have entirely different histories.
2801a3f4cd
...
f92a3f9a40
|
@ -1,2 +0,0 @@
|
||||||
__pycache__
|
|
||||||
venv
|
|
|
@ -1,6 +1,4 @@
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from prompt_toolkit import prompt
|
|
||||||
from prompt_toolkit.completion import WordCompleter
|
|
||||||
|
|
||||||
class MappedAction(Enum):
|
class MappedAction(Enum):
|
||||||
CUT_UNCONDITIONALLY = auto(),
|
CUT_UNCONDITIONALLY = auto(),
|
||||||
|
@ -13,7 +11,18 @@ class FinalAction(Enum):
|
||||||
CUT = auto(),
|
CUT = auto(),
|
||||||
NO_CUT = auto()
|
NO_CUT = auto()
|
||||||
|
|
||||||
class ComplicatedWiresModule:
|
class GlobalState:
|
||||||
|
def __init__(self, serial, parallel, batteries):
|
||||||
|
self.serial = serial
|
||||||
|
self.parallel = parallel
|
||||||
|
self.batteries = batteries
|
||||||
|
|
||||||
|
if int(self.serial[-1]) % 2 == 0:
|
||||||
|
self.serial_even = True
|
||||||
|
else:
|
||||||
|
self.serial_even = False
|
||||||
|
|
||||||
|
class ComplicatedWire:
|
||||||
def __init__(self, red, blue, star, led, state):
|
def __init__(self, red, blue, star, led, state):
|
||||||
self.red = red
|
self.red = red
|
||||||
self.blue = blue
|
self.blue = blue
|
||||||
|
@ -54,6 +63,7 @@ class ComplicatedWiresModule:
|
||||||
|
|
||||||
def resolveAction(self):
|
def resolveAction(self):
|
||||||
action = self.getAction()
|
action = self.getAction()
|
||||||
|
print(action)
|
||||||
|
|
||||||
if action == MappedAction.CUT_UNCONDITIONALLY:
|
if action == MappedAction.CUT_UNCONDITIONALLY:
|
||||||
return FinalAction.CUT
|
return FinalAction.CUT
|
||||||
|
@ -62,12 +72,12 @@ class ComplicatedWiresModule:
|
||||||
return FinalAction.NO_CUT
|
return FinalAction.NO_CUT
|
||||||
|
|
||||||
elif action == MappedAction.CUT_IF_DIGIT_EVEN:
|
elif action == MappedAction.CUT_IF_DIGIT_EVEN:
|
||||||
if self.state.serial.is_even:
|
if self.state.serial_even:
|
||||||
return FinalAction.CUT
|
return FinalAction.CUT
|
||||||
return FinalAction.NO_CUT
|
return FinalAction.NO_CUT
|
||||||
|
|
||||||
elif action == MappedAction.CUT_IF_PARALLEL:
|
elif action == MappedAction.CUT_IF_PARALLEL:
|
||||||
if 'Para' in self.state.ports:
|
if self.state.parallel:
|
||||||
return FinalAction.CUT
|
return FinalAction.CUT
|
||||||
return FinalAction.NO_CUT
|
return FinalAction.NO_CUT
|
||||||
|
|
||||||
|
@ -77,23 +87,22 @@ class ComplicatedWiresModule:
|
||||||
return FinalAction.NO_CUT
|
return FinalAction.NO_CUT
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def interactive(cls, state, cmdline):
|
def human_helper(cls):
|
||||||
completer = WordCompleter(['red', 'blue', 'star', 'led', 'quit', 'exit'])
|
serial = input("serial (string)? ")
|
||||||
|
parallel = cls.custom_bool(input("parallel (bool)? "))
|
||||||
|
batteries = int(input("number of batteries (int)? "))
|
||||||
|
|
||||||
# there are 6 wires in the complicated wires module
|
red = cls.custom_bool(input("is red (bool)? "))
|
||||||
while True:
|
blue = cls.custom_bool(input("is blue (bool)? "))
|
||||||
text = prompt('compwires> ', completer=completer, complete_while_typing=True)
|
star = cls.custom_bool(input("is star (bool)? "))
|
||||||
|
led = cls.custom_bool(input("is led (bool)? "))
|
||||||
|
|
||||||
if text == "quit":
|
print(red, blue, star, led)
|
||||||
return
|
|
||||||
|
|
||||||
elif text == "exit":
|
state = GlobalState(serial, parallel, batteries)
|
||||||
return
|
wire = cls(red, blue, star, led, state)
|
||||||
|
|
||||||
attr = [i in text for i in ['red', 'blue', 'star', 'led']]
|
print(wire.resolveAction())
|
||||||
|
|
||||||
try:
|
if __name__ == "__main__":
|
||||||
print("CUT" if cls(*attr, state).resolveAction() == FinalAction.CUT else "NO CUT")
|
ComplicatedWire.human_helper()
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
print("the state hasn't been completed. maybe fill out the serial?")
|
|
|
@ -1,6 +1,3 @@
|
||||||
from prompt_toolkit import prompt
|
|
||||||
from prompt_toolkit.completion import WordCompleter
|
|
||||||
|
|
||||||
class FoundCondition(Exception):
|
class FoundCondition(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -63,7 +60,7 @@ class PasswordModule:
|
||||||
default module execution location
|
default module execution location
|
||||||
|
|
||||||
(hint, default module execution location is where __name__ ==
|
(hint, default module execution location is where __name__ ==
|
||||||
"__main__")
|
"__main__"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
responses = []
|
responses = []
|
||||||
|
@ -74,16 +71,5 @@ class PasswordModule:
|
||||||
obj = cls(responses)
|
obj = cls(responses)
|
||||||
return obj.solve()
|
return obj.solve()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def interactive(cls, state, cmdline):
|
|
||||||
responses = []
|
|
||||||
for i in range(5):
|
|
||||||
print("Enter {}th column of letters:".format(str(i + 1)))
|
|
||||||
response = [*prompt('password> ')]
|
|
||||||
responses.append(response)
|
|
||||||
|
|
||||||
password = cls(responses)
|
|
||||||
print(password.solve())
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print(PasswordModule.human_helper())
|
print(PasswordModule.human_helper())
|
|
@ -1,5 +0,0 @@
|
||||||
prompt_toolkit
|
|
||||||
pyautogui
|
|
||||||
pywinctl
|
|
||||||
opencv-python
|
|
||||||
numpy
|
|
|
@ -1,44 +0,0 @@
|
||||||
from modules.wires import WiresModule
|
|
||||||
from modules.button import ButtonModule
|
|
||||||
from modules.comp_wires import ComplicatedWiresModule
|
|
||||||
from modules.password import PasswordModule
|
|
||||||
|
|
||||||
modules = {
|
|
||||||
'wires': WiresModule,
|
|
||||||
'button': ButtonModule,
|
|
||||||
'keypad': None,
|
|
||||||
'simon': None,
|
|
||||||
'first': None,
|
|
||||||
'memory': None,
|
|
||||||
'morse': None,
|
|
||||||
'compwires': ComplicatedWiresModule,
|
|
||||||
'seqwires': None,
|
|
||||||
'maze': None,
|
|
||||||
'password': PasswordModule,
|
|
||||||
'vent': None,
|
|
||||||
'discharge': None,
|
|
||||||
'knob': None,
|
|
||||||
}
|
|
||||||
|
|
||||||
indicators = [
|
|
||||||
'SND',
|
|
||||||
'CLR',
|
|
||||||
'CAR',
|
|
||||||
'IND',
|
|
||||||
'FRQ',
|
|
||||||
'SIG',
|
|
||||||
'NSA',
|
|
||||||
'MSA',
|
|
||||||
'TRN',
|
|
||||||
'BOB',
|
|
||||||
'FRK',
|
|
||||||
]
|
|
||||||
|
|
||||||
ports = [
|
|
||||||
'DVI',
|
|
||||||
'Para',
|
|
||||||
'PS2',
|
|
||||||
'RJ45',
|
|
||||||
'Serial',
|
|
||||||
'RCA',
|
|
||||||
]
|
|
|
@ -1,69 +0,0 @@
|
||||||
from enum import Enum, auto
|
|
||||||
from prompt_toolkit import prompt
|
|
||||||
from prompt_toolkit.completion import WordCompleter
|
|
||||||
|
|
||||||
class ButtonAction(Enum):
|
|
||||||
RELEASE = auto(),
|
|
||||||
HOLD = auto()
|
|
||||||
|
|
||||||
class ButtonModule:
|
|
||||||
def __init__(self, color, text, state):
|
|
||||||
self.color = color
|
|
||||||
self.text = text.lower()
|
|
||||||
self.state = state
|
|
||||||
|
|
||||||
def solve(self):
|
|
||||||
if self.color == "blue" and self.text == "abort":
|
|
||||||
return ButtonAction.HOLD
|
|
||||||
|
|
||||||
elif self.state.batteries > 1 and self.text == "detonate":
|
|
||||||
return ButtonAction.RELEASE
|
|
||||||
|
|
||||||
try:
|
|
||||||
if self.color == "white" and self.indicators["CAR"] == True:
|
|
||||||
return ButtonAction.HOLD
|
|
||||||
except KeyError: pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
if self.state.batteries > 2 and self.indicators["FRK"] == True:
|
|
||||||
return ButtonAction.RELEASE
|
|
||||||
except KeyError: pass
|
|
||||||
|
|
||||||
if self.color == "yellow":
|
|
||||||
return ButtonAction.HOLD
|
|
||||||
|
|
||||||
elif self.color == "red" and self.text == "hold":
|
|
||||||
return ButtonAction.RELEASE
|
|
||||||
|
|
||||||
return ButtonAction.HOLD
|
|
||||||
|
|
||||||
def hold(self, color):
|
|
||||||
if color == "blue":
|
|
||||||
return 4
|
|
||||||
elif color == "white":
|
|
||||||
return 1
|
|
||||||
elif color == "yellow":
|
|
||||||
return 5
|
|
||||||
|
|
||||||
return 1
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def interactive(cls, state, cmdline):
|
|
||||||
print("Please enter button color")
|
|
||||||
color = prompt('button> ')
|
|
||||||
print("Please enter button text")
|
|
||||||
text = prompt('button> ')
|
|
||||||
|
|
||||||
button = cls(color, text, state)
|
|
||||||
result = button.solve()
|
|
||||||
|
|
||||||
if result == ButtonAction.HOLD:
|
|
||||||
print("What is the held button color")
|
|
||||||
heldcolor = prompt('button> ')
|
|
||||||
|
|
||||||
print("Release until the timer has a {} in any position".format(
|
|
||||||
str(button.hold(heldcolor))
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
print("Release")
|
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
from prompt_toolkit import prompt
|
|
||||||
from prompt_toolkit.completion import WordCompleter
|
|
||||||
|
|
||||||
class WiresModule:
|
|
||||||
def __init__(self, wires, state):
|
|
||||||
self.state = state
|
|
||||||
self.wires = wires.split(' ')
|
|
||||||
self.len = len(self.wires)
|
|
||||||
|
|
||||||
def solve(self):
|
|
||||||
# prints the solved solution
|
|
||||||
|
|
||||||
if self.len == 3:
|
|
||||||
if not 'red' in self.wires:
|
|
||||||
return "second wire"
|
|
||||||
|
|
||||||
elif self.wires[-1] == "white":
|
|
||||||
return "last wire"
|
|
||||||
|
|
||||||
elif self.wires.count('blue') > 1:
|
|
||||||
return "last blue wire"
|
|
||||||
|
|
||||||
else:
|
|
||||||
return "last wire"
|
|
||||||
|
|
||||||
elif self.len == 4:
|
|
||||||
if self.wires.count('red') > 1 and self.state.serial.is_odd:
|
|
||||||
return "last red wire"
|
|
||||||
|
|
||||||
elif self.wires[-1] == 'yellow' and not 'red' in self.wires:
|
|
||||||
return "first wire"
|
|
||||||
|
|
||||||
elif self.wires.count('blue') == 1:
|
|
||||||
return "first wire"
|
|
||||||
|
|
||||||
elif self.wires.count('yellow') > 1:
|
|
||||||
return "last wire"
|
|
||||||
|
|
||||||
else:
|
|
||||||
return "second wire"
|
|
||||||
|
|
||||||
elif self.len == 5:
|
|
||||||
if self.wires[-1] == 'black' and self.state.serial.is_odd:
|
|
||||||
return "fourth wire"
|
|
||||||
|
|
||||||
elif self.wires.count('red') == 1 and self.wires.count('yellow') > 1:
|
|
||||||
return "first wire"
|
|
||||||
|
|
||||||
elif not 'black' in self.wires:
|
|
||||||
return "second wire"
|
|
||||||
|
|
||||||
else:
|
|
||||||
return "first wire"
|
|
||||||
|
|
||||||
elif self.len == 6:
|
|
||||||
if not 'yellow' in self.wires and self.state.serial.is_odd:
|
|
||||||
return "third wire"
|
|
||||||
|
|
||||||
elif self.wires.count('yellow') == 1 and self.wires.count('white') > 1:
|
|
||||||
return "fourth wire"
|
|
||||||
|
|
||||||
elif not 'red' in self.wires:
|
|
||||||
return "last wire"
|
|
||||||
|
|
||||||
else:
|
|
||||||
return "fourth wire"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def interactive(cls, state, cmdline):
|
|
||||||
completer = WordCompleter(['red', 'blue', 'yellow', 'white', 'black'])
|
|
||||||
|
|
||||||
print("Please enter wire colors from top to bottom.")
|
|
||||||
text = prompt('wires> ', completer=completer, complete_while_typing=True)
|
|
||||||
|
|
||||||
wires = WiresModule(text, state)
|
|
||||||
print("cut the {}".format(wires.solve()))
|
|
||||||
|
|
||||||
return
|
|
131
src/shell.py
131
src/shell.py
|
@ -1,131 +0,0 @@
|
||||||
from constants import modules, indicators, ports
|
|
||||||
|
|
||||||
from prompt_toolkit import PromptSession
|
|
||||||
from prompt_toolkit.completion import NestedCompleter
|
|
||||||
|
|
||||||
maincompleter = NestedCompleter.from_nested_dict({
|
|
||||||
'help': None,
|
|
||||||
'mark': None,
|
|
||||||
'serial': None,
|
|
||||||
'strike': None,
|
|
||||||
'batteries': None,
|
|
||||||
'eval': None,
|
|
||||||
'indicator': {*[indicator for indicator in indicators]},
|
|
||||||
'ports': {*[port for port in ports]},
|
|
||||||
'mod': {*["mod {}".format(module) for module in modules.keys()]},
|
|
||||||
})
|
|
||||||
|
|
||||||
class Serial:
|
|
||||||
def __init__(self, serial):
|
|
||||||
self.serial = serial.lower()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_even(self):
|
|
||||||
if int(self.serial[-1]) % 2 == 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_odd(self):
|
|
||||||
return not self.is_even
|
|
||||||
|
|
||||||
@property
|
|
||||||
def vowel(self):
|
|
||||||
for vowel in ['a', 'e', 'i', 'o', 'u']:
|
|
||||||
if vowel in self.serial:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def no_vowel(self):
|
|
||||||
return not self.vowel
|
|
||||||
|
|
||||||
@property
|
|
||||||
def text(self):
|
|
||||||
return self.serial
|
|
||||||
|
|
||||||
class GlobalBombState:
|
|
||||||
def __init__(self):
|
|
||||||
self.indicators = {}
|
|
||||||
self.ports = []
|
|
||||||
self._serial = None
|
|
||||||
self.batteries = 0
|
|
||||||
self.modulecount = 0
|
|
||||||
self.strikes = 0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def serial(self):
|
|
||||||
return self._serial
|
|
||||||
|
|
||||||
@serial.setter
|
|
||||||
def serial(self, serial):
|
|
||||||
self._serial = Serial(serial)
|
|
||||||
|
|
||||||
def update_toolbar(self):
|
|
||||||
return "help for help, ports: {}, ind: {}, batt: {}, serial: {}, strikes {}".format(
|
|
||||||
self.ports, self.indicators, str(self.batteries), self.serial.text if self.serial else "?", str(self.strikes)
|
|
||||||
)
|
|
||||||
|
|
||||||
session = PromptSession(completer=maincompleter)
|
|
||||||
state = GlobalBombState()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
userinput = session.prompt("ktane> ", bottom_toolbar=state.update_toolbar(), complete_while_typing=True)
|
|
||||||
splitted = userinput.split(' ')
|
|
||||||
tokens = len(splitted)
|
|
||||||
command = splitted[0]
|
|
||||||
|
|
||||||
if command == "mod":
|
|
||||||
if tokens == 1:
|
|
||||||
print(modules.keys())
|
|
||||||
elif tokens > 1:
|
|
||||||
if splitted[1].isnumeric():
|
|
||||||
state.modulecount = int(splitted[1])
|
|
||||||
print("module count set to {}".format(str(state.modulecount)))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
selectedmodule = modules[splitted[1]]
|
|
||||||
if selectedmodule:
|
|
||||||
selectedmodule.interactive(state, splitted[2:])
|
|
||||||
else:
|
|
||||||
print("this module doesn't exist!")
|
|
||||||
except IndexError:
|
|
||||||
print("you didn't specify a module")
|
|
||||||
|
|
||||||
elif command == "serial": # set the serial number
|
|
||||||
try:
|
|
||||||
state.serial = splitted[1]
|
|
||||||
print("serial number set to {}".format(state.serial.text))
|
|
||||||
except IndexError:
|
|
||||||
print("specify a serial number, perhaps?")
|
|
||||||
|
|
||||||
elif command == "batteries":
|
|
||||||
try:
|
|
||||||
state.batteries = int(splitted[1])
|
|
||||||
print("battery count set to {}".format(str(state.batteries)))
|
|
||||||
except IndexError:
|
|
||||||
print("specify a number of batteries, perhaps?")
|
|
||||||
|
|
||||||
elif command == "strike":
|
|
||||||
state.strikes += 1
|
|
||||||
print("strike given")
|
|
||||||
|
|
||||||
elif command == "ports":
|
|
||||||
try:
|
|
||||||
state.ports.append(splitted[1])
|
|
||||||
print("appeneded port {}".format(splitted[1]))
|
|
||||||
except IndexError:
|
|
||||||
print("specify a port type")
|
|
||||||
|
|
||||||
elif command == "indicator":
|
|
||||||
try:
|
|
||||||
state.indicators[splitted[1]] = True if splitted[2] == 't' else False
|
|
||||||
print("added indicator {} with state {}".format(
|
|
||||||
splitted[1], state.indicators[splitted[1]]
|
|
||||||
))
|
|
||||||
except IndexError: print("specify an indicator and a state")
|
|
||||||
|
|
||||||
elif command == "eval":
|
|
||||||
eval(' '.join(splitted[1:]))
|
|
|
@ -1,98 +0,0 @@
|
||||||
import pyautogui
|
|
||||||
import colorsys
|
|
||||||
import pywinctl
|
|
||||||
import numpy
|
|
||||||
import cv2 as cv
|
|
||||||
import struct
|
|
||||||
import matching
|
|
||||||
from prompt_toolkit import prompt
|
|
||||||
from prompt_toolkit.completion import WordCompleter
|
|
||||||
|
|
||||||
# get all windows
|
|
||||||
titles = pywinctl.getAllTitles()
|
|
||||||
title_completer = WordCompleter(titles)
|
|
||||||
|
|
||||||
try:
|
|
||||||
window = pywinctl.getWindowsWithTitle("Keep Talking and Nobody Explodes")[0]
|
|
||||||
except IndexError:
|
|
||||||
try:
|
|
||||||
text = prompt("Select window name> ", completer=title_completer)
|
|
||||||
window = pywinctl.getWindowsWithTitle(text)[0]
|
|
||||||
except IndexError:
|
|
||||||
print("invalid title")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
if not window.isVisible:
|
|
||||||
window.show()
|
|
||||||
|
|
||||||
frame = window.getClientFrame()
|
|
||||||
print(frame)
|
|
||||||
|
|
||||||
def get_image(left, top, right, bottom): # returns an opencv image
|
|
||||||
image = pyautogui.screenshot(region=(
|
|
||||||
left, top, right - left, bottom - top
|
|
||||||
))
|
|
||||||
|
|
||||||
numpy_array = numpy.array(image)
|
|
||||||
opencv_image = cv.cvtColor(numpy_array, cv.COLOR_RGB2BGR)
|
|
||||||
|
|
||||||
return opencv_image
|
|
||||||
|
|
||||||
rgb_colors_to_match = [
|
|
||||||
(220, 162, 129),
|
|
||||||
(220, 162, 129),
|
|
||||||
(145, 108, 89),
|
|
||||||
]
|
|
||||||
num_colors_in_range = 9
|
|
||||||
delta_h_value = 10
|
|
||||||
delta_s_value = 50
|
|
||||||
delta_v_value = 50
|
|
||||||
tolerence_value = 20
|
|
||||||
|
|
||||||
ranges = [
|
|
||||||
matching.generate_hex_range(i, num_colors_in_range, delta_h=delta_h_value, delta_s=delta_s_value, delta_v=delta_v_value)
|
|
||||||
for i in rgb_colors_to_match
|
|
||||||
]
|
|
||||||
|
|
||||||
def are_rectangles_close(rect1, rect2):
|
|
||||||
distance_threshold = 20
|
|
||||||
x1, y1, w1, h1 = rect1
|
|
||||||
x2, y2, w2, h2 = rect2
|
|
||||||
return abs(x2 - x1) < distance_threshold and abs(y2 - y1) < distance_threshold
|
|
||||||
|
|
||||||
while True:
|
|
||||||
image = get_image(frame.left, frame.top, frame.right, frame.bottom)
|
|
||||||
blank = numpy.zeros(image.shape, dtype='uint8')
|
|
||||||
|
|
||||||
combined = image
|
|
||||||
matched = matching.color_matching(image, ranges[0])
|
|
||||||
combined = matching.convert_masked_pixels_to_zero(combined, matched)
|
|
||||||
matched = matching.color_matching(image, ranges[1])
|
|
||||||
combined = matching.convert_masked_pixels_to_zero(combined, matched)
|
|
||||||
matched = matching.color_matching(image, ranges[2])
|
|
||||||
combined = matching.convert_masked_pixels_to_zero(combined, matched)
|
|
||||||
|
|
||||||
min_contour_length = 100
|
|
||||||
max_contour_length = 10000
|
|
||||||
|
|
||||||
|
|
||||||
bw = cv.cvtColor(combined, cv.COLOR_BGR2GRAY)
|
|
||||||
ret, thresh = cv.threshold(bw, 127, 255, cv.THRESH_BINARY)
|
|
||||||
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
|
|
||||||
filtered_contours = [cnt for cnt in contours if min_contour_length <= cv.arcLength(cnt, True) <= max_contour_length]
|
|
||||||
monster_contour = numpy.concatenate(filtered_contours)
|
|
||||||
hull = cv.convexHull(monster_contour)
|
|
||||||
bounding_quad = cv.minAreaRect(hull)
|
|
||||||
points = cv.boxPoints(bounding_quad).astype(int)
|
|
||||||
print(points)
|
|
||||||
|
|
||||||
cv.drawContours(combined, [points], 0, (0, 255, 0), 2)
|
|
||||||
|
|
||||||
cv.drawContours(combined, filtered_contours, -1, (0,255,255), 2)
|
|
||||||
|
|
||||||
cv.imshow('test', combined)
|
|
||||||
key = cv.waitKey(1)
|
|
||||||
if (key) == 113: # q key
|
|
||||||
break
|
|
||||||
|
|
||||||
cv.destroyAllWindows()
|
|
|
@ -1,59 +0,0 @@
|
||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
def rgb_to_hsv(rgb_color):
|
|
||||||
# Convert RGB color to HSV color space
|
|
||||||
hsv_color = cv2.cvtColor(np.uint8([[rgb_color]]), cv2.COLOR_RGB2HSV)[0][0]
|
|
||||||
return hsv_color
|
|
||||||
|
|
||||||
def generate_hex_range(rgb_color, num_colors, delta_h=10, delta_s=50, delta_v=50):
|
|
||||||
# Convert the RGB color to HSV color space
|
|
||||||
hsv_color = rgb_to_hsv(rgb_color)
|
|
||||||
|
|
||||||
# Define ranges in HSV color space
|
|
||||||
h_range = np.linspace(hsv_color[0] - delta_h, hsv_color[0] + delta_h, num_colors)
|
|
||||||
s_range = np.linspace(hsv_color[1] - delta_s, hsv_color[1] + delta_s, num_colors)
|
|
||||||
v_range = np.linspace(hsv_color[2] - delta_v, hsv_color[2] + delta_v, num_colors)
|
|
||||||
|
|
||||||
hex_range = []
|
|
||||||
|
|
||||||
# Generate colors in the HSV color space and convert them to BGR
|
|
||||||
for h_val in h_range:
|
|
||||||
for s_val in s_range:
|
|
||||||
for v_val in v_range:
|
|
||||||
hsv_color_modified = np.array([h_val, s_val, v_val])
|
|
||||||
bgr_color_modified = cv2.cvtColor(np.uint8([[hsv_color_modified]]), cv2.COLOR_HSV2BGR)[0][0]
|
|
||||||
hex_color = "#{:02x}{:02x}{:02x}".format(int(bgr_color_modified[2]),
|
|
||||||
int(bgr_color_modified[1]),
|
|
||||||
int(bgr_color_modified[0]))
|
|
||||||
hex_range.append(hex_color)
|
|
||||||
|
|
||||||
return hex_range
|
|
||||||
|
|
||||||
def color_matching(image, hex_range_colors, tolerance=20):
|
|
||||||
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
|
||||||
|
|
||||||
matched_pixels = np.zeros_like(hsv_image[:, :, 0], dtype=np.uint8)
|
|
||||||
|
|
||||||
for hex_color in hex_range_colors:
|
|
||||||
# Convert the hex color to RGB
|
|
||||||
rgb_color = tuple(int(hex_color[i:i + 2], 16) for i in (1, 3, 5))
|
|
||||||
# Convert the RGB color to HSV
|
|
||||||
hsv_color = rgb_to_hsv(rgb_color)
|
|
||||||
|
|
||||||
lower_bound = np.array([hsv_color[0] - tolerance, hsv_color[1] - tolerance, hsv_color[2] - tolerance])
|
|
||||||
upper_bound = np.array([hsv_color[0] + tolerance, hsv_color[1] + tolerance, hsv_color[2] + tolerance])
|
|
||||||
|
|
||||||
mask = cv2.inRange(hsv_image, lower_bound, upper_bound)
|
|
||||||
matched_pixels |= mask
|
|
||||||
|
|
||||||
return matched_pixels
|
|
||||||
|
|
||||||
def convert_masked_pixels_to_zero(image, mask):
|
|
||||||
# Create an all-white (ones) image with the same shape as the original image
|
|
||||||
white_image = np.ones_like(image) * 255
|
|
||||||
|
|
||||||
# Use the mask to set all masked pixels in the original image to zero
|
|
||||||
result_image = cv2.bitwise_and(image, white_image, mask=cv2.bitwise_not(mask))
|
|
||||||
|
|
||||||
return result_image
|
|
Loading…
Reference in New Issue