I’m trying to make windows program that keeps monitoring an area of choice on one of my monitors, I used deepseek to help me because I don’t no anything about programming, so it gave a code but sometime it trigger the alert and sometimes not. the idea is to look for the color when it appears it trigger the alert and then keeps monitoring for the same color again.
import cv2
import numpy as np
import pyautogui
import time
import tkinter as tk
from tkinter import Tk, Canvas, Button, messagebox, colorchooser, filedialog
import threading
import sys
import os
import pygame
from PIL import Image, ImageTk
import mss
# Initialize pygame for sound
pygame.mixer.init()
alert_sound = None
# Standard colors + custom color picker
STANDARD_COLORS = [
"#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF",
"#FFA500", "#A52A2A", "#800080", "#008000", "#000080", "#800000",
"#FF6347", "#FFD700", "#ADFF2F", "#FF4500", "#DA70D6", "#1E90FF"
]
class ColorDetectorApp:
def __init__(self):
self.root = tk.Tk()
self.root.title("Advanced Color Detector")
self.setup_ui()
self.monitor = None
self.monitor_region = None
self.target_color = (255, 255, 255)
self.is_monitoring = False
self.tolerance = 30
self.stop_monitoring = threading.Event()
self.sound_file = None
def setup_ui(self):
# Main frame
main_frame = tk.Frame(self.root, padx=10, pady=10)
main_frame.pack(fill=tk.BOTH, expand=True)
# Monitor selection
tk.Button(main_frame, text="1. Select Monitor", command=self.select_monitor).grid(row=0, column=0, sticky="ew", pady=5)
self.monitor_label = tk.Label(main_frame, text="No monitor selected")
self.monitor_label.grid(row=0, column=1, sticky="w")
# Area selection
tk.Button(main_frame, text="2. Select Area", command=self.select_area).grid(row=1, column=0, sticky="ew", pady=5)
self.area_label = tk.Label(main_frame, text="No area selected")
self.area_label.grid(row=1, column=1, sticky="w")
# Color selection frame
color_frame = tk.LabelFrame(main_frame, text="3. Select Color", padx=5, pady=5)
color_frame.grid(row=2, column=0, columnspan=2, sticky="ew", pady=5)
# Color palette
for i, color in enumerate(STANDARD_COLORS):
tk.Button(color_frame, bg=color, width=3, height=1,
command=lambda c=color: self.set_color(c)).grid(row=i//6, column=i%6, padx=2, pady=2)
# Custom color button
tk.Button(color_frame, text="Custom", command=self.choose_custom_color).grid(row=3, column=4, columnspan=2, sticky="ew")
# Color display
self.color_display = tk.Canvas(color_frame, width=30, height=30, bg="white")
self.color_display.grid(row=3, column=2, columnspan=2)
# Sound selection
tk.Button(main_frame, text="4. Select Alert Sound", command=self.select_sound).grid(row=3, column=0, sticky="ew", pady=5)
self.sound_label = tk.Label(main_frame, text="No sound selected")
self.sound_label.grid(row=3, column=1, sticky="w")
# Tolerance control
tk.Label(main_frame, text="Color Tolerance:").grid(row=4, column=0, sticky="e")
self.tolerance_slider = tk.Scale(main_frame, from_=0, to=100, orient=tk.HORIZONTAL)
self.tolerance_slider.set(30)
self.tolerance_slider.grid(row=4, column=1, sticky="ew")
# Monitor button
self.monitor_btn = tk.Button(main_frame, text="Start Monitoring", command=self.toggle_monitoring)
self.monitor_btn.grid(row=5, column=0, columnspan=2, pady=10)
# Preview area
self.preview_label = tk.Label(main_frame)
self.preview_label.grid(row=6, column=0, columnspan=2)
# Status bar
self.status_var = tk.StringVar(value="Ready")
tk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN).grid(row=7, column=0, columnspan=2, sticky="ew")
def select_monitor(self):
self.status_var.set("Select a monitor from the list")
selector = tk.Toplevel(self.root)
selector.title("Select Monitor")
selector.attributes("-topmost", True)
with mss.mss() as sct:
monitors = sct.monitors[1:] # Skip default monitor
for i, monitor in enumerate(monitors, 1):
frame = tk.Frame(selector)
frame.pack(pady=5)
# Capture monitor preview
with mss.mss() as sct:
screenshot = sct.grab(monitor)
img = Image.frombytes("RGB", screenshot.size, screenshot.rgb)
img.thumbnail((200, 150))
photo = ImageTk.PhotoImage(img)
label = tk.Label(frame, image=photo)
label.image = photo
label.pack(side=tk.LEFT)
tk.Button(frame, text=f"Monitor {i}",
command=lambda m=monitor: self.set_monitor(m, selector)).pack(side=tk.LEFT, padx=10)
selector.protocol("WM_DELETE_WINDOW", lambda: self.on_selector_close(selector))
def set_monitor(self, monitor, selector):
self.monitor = monitor
selector.destroy()
self.monitor_label.config(text=f"Selected: {monitor['width']}x{monitor['height']}")
self.status_var.set("Monitor selected")
def on_selector_close(self, selector):
selector.destroy()
self.status_var.set("Monitor selection cancelled")
def select_area(self):
if not self.monitor:
messagebox.showerror("Error", "Please select a monitor first")
return
self.status_var.set("Click and drag to select area")
self.root.withdraw()
selector = tk.Toplevel()
selector.attributes("-fullscreen", True)
selector.attributes("-alpha", 0.3)
selector.attributes("-topmost", True)
canvas = tk.Canvas(selector)
canvas.pack(fill=tk.BOTH, expand=True)
# Display monitor preview
with mss.mss() as sct:
screenshot = sct.grab(self.monitor)
img = Image.frombytes("RGB", screenshot.size, screenshot.rgb)
img = img.resize((self.root.winfo_screenwidth(), self.root.winfo_screenheight()))
self.bg_img = ImageTk.PhotoImage(img)
canvas.create_image(0, 0, anchor=tk.NW, image=self.bg_img)
# Selection variables
self.selection_start = None
self.selection_rect = None
def on_press(event):
self.selection_start = (event.x, event.y)
def on_drag(event):
if self.selection_start:
if self.selection_rect:
canvas.delete(self.selection_rect)
x1, y1 = self.selection_start
x2, y2 = event.x, event.y
self.selection_rect = canvas.create_rectangle(
x1, y1, x2, y2, outline="red", width=2
)
def on_release(event):
if self.selection_start:
x1, y1 = self.selection_start
x2, y2 = event.x, event.y
# Convert to absolute coordinates
left = min(x1, x2) + self.monitor["left"]
top = min(y1, y2) + self.monitor["top"]
width = abs(x2 - x1)
height = abs(y2 - y1)
self.monitor_region = {
"left": left,
"top": top,
"width": width,
"height": height
}
selector.destroy()
self.root.deiconify()
self.area_label.config(text=f"Selected: {width}x{height} at ({left},{top})")
self.status_var.set("Area selected")
self.update_preview()
canvas.bind("<Button-1>", on_press)
canvas.bind("<B1-Motion>", on_drag)
canvas.bind("<ButtonRelease-1>", on_release)
selector.protocol("WM_DELETE_WINDOW", lambda: self.on_area_selector_close(selector))
def on_area_selector_close(self, selector):
selector.destroy()
self.root.deiconify()
self.status_var.set("Area selection cancelled")
def set_color(self, hex_color):
rgb = tuple(int(hex_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
self.target_color = rgb
self.color_display.config(bg=hex_color)
self.status_var.set(f"Color selected: RGB{rgb}")
def choose_custom_color(self):
color = colorchooser.askcolor(title="Choose Color")
if color[0]:
rgb = tuple(int(c) for c in color[0])
self.target_color = rgb
hex_color = color[1]
self.color_display.config(bg=hex_color)
self.status_var.set(f"Color selected: RGB{rgb}")
def select_sound(self):
file_path = filedialog.askopenfilename(
title="Select Alert Sound",
filetypes=[("Sound Files", "*.wav *.mp3 *.ogg"), ("All Files", "*.*")]
)
if file_path:
try:
global alert_sound
alert_sound = pygame.mixer.Sound(file_path)
self.sound_label.config(text=os.path.basename(file_path))
self.status_var.set("Sound selected")
except:
messagebox.showerror("Error", "Could not load sound file")
def update_preview(self):
if self.monitor_region:
with mss.mss() as sct:
screenshot = sct.grab(self.monitor_region)
img = Image.frombytes("RGB", screenshot.size, screenshot.rgb)
img.thumbnail((400, 300))
photo = ImageTk.PhotoImage(img)
self.preview_label.config(image=photo)
self.preview_label.image = photo
def toggle_monitoring(self):
if not all([self.monitor, self.monitor_region, self.target_color]):
messagebox.showerror("Error", "Please complete all steps first")
return
self.is_monitoring = not self.is_monitoring
if self.is_monitoring:
self.stop_monitoring.clear()
self.monitor_btn.config(text="Stop Monitoring")
self.status_var.set("Monitoring...")
threading.Thread(target=self.monitor_color, daemon=True).start()
else:
self.stop_monitoring.set()
self.monitor_btn.config(text="Start Monitoring")
self.status_var.set("Monitoring stopped")
def monitor_color(self):
while not self.stop_monitoring.is_set():
start_time = time.time()
try:
with mss.mss() as sct:
screenshot = sct.grab(self.monitor_region)
img = np.array(screenshot, dtype=np.uint8)
# Convert target color to BGR (OpenCV format) and ensure proper shape
target_bgr = np.array([self.target_color[2], self.target_color[1], self.target_color[0]], dtype=np.uint8)
# Calculate bounds with tolerance (safe from overflow)
tolerance = np.clip(self.tolerance_slider.get(), 0, 255)
lower = np.clip(target_bgr - tolerance, 0, 255)
upper = np.clip(target_bgr + tolerance, 0, 255)
# Reshape to proper dimensions for OpenCV
lower = lower.reshape(1, 1, 3)
upper = upper.reshape(1, 1, 3)
# Create mask and check for matches
mask = cv2.inRange(img, lower, upper)
if cv2.countNonZero(mask) > 0:
self.root.after(0, self.color_detected)
break
# Calculate time to wait for 1 second interval
elapsed = time.time() - start_time
wait_time = max(0, 1.0 - elapsed)
time.sleep(wait_time)
except Exception as e:
print(f"Monitoring error: {e}")
self.root.after(0, lambda: self.status_var.set(f"Error: {str(e)}"))
break
def color_detected(self):
if not self.is_monitoring:
return
self.is_monitoring = False
self.stop_monitoring.set()
self.monitor_btn.config(text="Start Monitoring")
self.status_var.set("Color detected!")
if alert_sound:
alert_sound.play()
messagebox.showinfo("Color Detected", "The target color was found in the selected area!")
# Flash the preview
self.preview_label.config(bg="red")
self.root.after(200, lambda: self.preview_label.config(bg="SystemButtonFace"))
if __name__ == "__main__":
app = ColorDetectorApp()
app.root.mainloop()