|
|
|
@@ -14,11 +14,17 @@ import time
|
|
|
|
import math
|
|
|
|
import math
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
import json
|
|
|
|
import json
|
|
|
|
|
|
|
|
import platform
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
from tkmacosx import Button
|
|
|
|
|
|
|
|
except ImportError:
|
|
|
|
|
|
|
|
Button = tk.Button
|
|
|
|
# ===========================
|
|
|
|
# ===========================
|
|
|
|
# CONFIGURACIÓN
|
|
|
|
# CONFIGURACIÓN
|
|
|
|
# ===========================
|
|
|
|
# ===========================
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
|
|
|
|
|
|
# Modelos
|
|
|
|
# Modelos
|
|
|
|
MODEL_PERSON_PATH = os.path.join(BASE_DIR, 'models', 'yolov8n.pt') # Revertido a Nano por velocidad
|
|
|
|
MODEL_PERSON_PATH = os.path.join(BASE_DIR, 'models', 'yolov8n.pt') # Revertido a Nano por velocidad
|
|
|
|
@@ -45,6 +51,15 @@ BG_COLOR = "#282c34"
|
|
|
|
TEXT_COLOR = "#abb2bf"
|
|
|
|
TEXT_COLOR = "#abb2bf"
|
|
|
|
ACCENT_COLOR = "#61afef"
|
|
|
|
ACCENT_COLOR = "#61afef"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Cross-platform video backend
|
|
|
|
|
|
|
|
V_BACKEND = cv2.CAP_ANY
|
|
|
|
|
|
|
|
if platform.system() == "Windows":
|
|
|
|
|
|
|
|
V_BACKEND = cv2.CAP_DSHOW
|
|
|
|
|
|
|
|
elif platform.system() == "Darwin": # macOS
|
|
|
|
|
|
|
|
V_BACKEND = cv2.CAP_AVFOUNDATION
|
|
|
|
|
|
|
|
elif platform.system() == "Linux":
|
|
|
|
|
|
|
|
V_BACKEND = cv2.CAP_V4L2
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================
|
|
|
|
# ===========================
|
|
|
|
# CLASES DE UTILIDAD
|
|
|
|
# CLASES DE UTILIDAD
|
|
|
|
# ===========================
|
|
|
|
# ===========================
|
|
|
|
@@ -519,43 +534,43 @@ class App:
|
|
|
|
self.controls_frame = tk.Frame(window, bg=BG_COLOR)
|
|
|
|
self.controls_frame = tk.Frame(window, bg=BG_COLOR)
|
|
|
|
self.controls_frame.pack(fill="x", padx=10, pady=10)
|
|
|
|
self.controls_frame.pack(fill="x", padx=10, pady=10)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_draw = tk.Button(self.controls_frame, text="Dibujar Línea", command=self.start_drawing, bg=ACCENT_COLOR, fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_draw = Button(self.controls_frame, text="Dibujar Línea", command=self.start_drawing, bg=ACCENT_COLOR, fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_draw.pack(side="left", padx=5)
|
|
|
|
self.btn_draw.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_reset_line = tk.Button(self.controls_frame, text="Borrar Línea", command=self.reset_line, bg="#e06c75", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_reset_line = Button(self.controls_frame, text="Borrar Línea", command=self.reset_line, bg="#e06c75", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_reset_line.pack(side="left", padx=5)
|
|
|
|
self.btn_reset_line.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_settings = tk.Button(self.controls_frame, text="Ajustes Cámara", command=self.open_settings_window, bg="#e5c07b", fg="black", font=("Helvetica", 10))
|
|
|
|
self.btn_settings = Button(self.controls_frame, text="Ajustes Cámara", command=self.open_settings_window, bg="#e5c07b", fg="black", font=("Helvetica", 10))
|
|
|
|
self.btn_settings.pack(side="left", padx=5)
|
|
|
|
self.btn_settings.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_720p = tk.Button(self.controls_frame, text="720p", command=lambda: self.change_resolution(1280, 720), bg="#61afef", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_720p = Button(self.controls_frame, text="720p", command=lambda: self.change_resolution(1280, 720), bg="#61afef", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_720p.pack(side="left", padx=5)
|
|
|
|
self.btn_720p.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_1080p = tk.Button(self.controls_frame, text="1080p", command=lambda: self.change_resolution(1920, 1080), bg="#61afef", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_1080p = Button(self.controls_frame, text="1080p", command=lambda: self.change_resolution(1920, 1080), bg="#61afef", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_1080p.pack(side="left", padx=5)
|
|
|
|
self.btn_1080p.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_correct = tk.Button(self.controls_frame, text="Corregir Contador", command=self.open_correction_dialog, bg="#d19a66", fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_correct = Button(self.controls_frame, text="Corregir Contador", command=self.open_correction_dialog, bg="#d19a66", fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_correct.pack(side="left", padx=5)
|
|
|
|
self.btn_correct.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_calib = tk.Button(self.controls_frame, text="Calibrar 3D", command=self.toggle_calibration, bg="#98c379", fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_calib = Button(self.controls_frame, text="Calibrar 3D", command=self.toggle_calibration, bg="#98c379", fg="white", font=("Helvetica", 10, "bold"))
|
|
|
|
self.btn_calib.pack(side="left", padx=5)
|
|
|
|
self.btn_calib.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
# Estado
|
|
|
|
# Estado
|
|
|
|
|
|
|
|
|
|
|
|
self.calibration = PerspectiveCalibration() # Nueva clase de calibración
|
|
|
|
self.calibration = PerspectiveCalibration() # Nueva clase de calibración
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_roi = tk.Button(self.controls_frame, text="Reforzar Zona", command=self.start_roi_selection, bg="#c678dd", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_roi = Button(self.controls_frame, text="Reforzar Zona", command=self.start_roi_selection, bg="#c678dd", fg="white", font=("Helvetica", 10))
|
|
|
|
self.btn_roi.pack(side="left", padx=5)
|
|
|
|
self.btn_roi.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.btn_graph = tk.Button(self.controls_frame, text="Generar Gráfico", command=generate_graph, bg="#98c379", fg="black", font=("Helvetica", 10))
|
|
|
|
self.btn_graph = Button(self.controls_frame, text="Generar Gráfico", command=generate_graph, bg="#98c379", fg="black", font=("Helvetica", 10))
|
|
|
|
self.btn_graph.pack(side="left", padx=5)
|
|
|
|
self.btn_graph.pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
self.log_text = scrolledtext.ScrolledText(window, height=8, bg="#21252b", fg="white", font=("Consolas", 9))
|
|
|
|
self.log_text = scrolledtext.ScrolledText(window, height=8, bg="#21252b", fg="white", font=("Courier", 9) if platform.system() != "Windows" else ("Consolas", 9))
|
|
|
|
self.log_text.pack(fill="x", padx=10, pady=5)
|
|
|
|
self.log_text.pack(fill="x", padx=10, pady=5)
|
|
|
|
|
|
|
|
|
|
|
|
# Logic
|
|
|
|
# Logic
|
|
|
|
# Usamos CAP_DSHOW en Windows para compatibilidad "Universal" (Mejor acceso a ajustes)
|
|
|
|
# Usamos el backend apropiado según el sistema operativo
|
|
|
|
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
|
|
|
|
self.cap = cv2.VideoCapture(0, V_BACKEND)
|
|
|
|
# Configurar 1080p por defecto
|
|
|
|
# Configurar 1080p por defecto
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
|
|
|
|
@@ -830,8 +845,8 @@ class App:
|
|
|
|
if self.cap.isOpened():
|
|
|
|
if self.cap.isOpened():
|
|
|
|
self.cap.release()
|
|
|
|
self.cap.release()
|
|
|
|
|
|
|
|
|
|
|
|
# Reabrir con DirectShow para mantener compatibilidad universal
|
|
|
|
# Reabrir con el backend apropiado
|
|
|
|
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
|
|
|
|
self.cap = cv2.VideoCapture(0, V_BACKEND)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
|
|
|
|
|
|
|
|
|
|
|
@@ -869,22 +884,22 @@ class App:
|
|
|
|
tk.Label(self.calib_window, text="Mover Malla", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
tk.Label(self.calib_window, text="Mover Malla", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
frm_move = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_move = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_move.pack()
|
|
|
|
frm_move.pack()
|
|
|
|
tk.Button(frm_move, text="↑", command=lambda: self.calibration.move_grid(0, -10)).grid(row=0, column=1)
|
|
|
|
Button(frm_move, text="↑", command=lambda: self.calibration.move_grid(0, -10)).grid(row=0, column=1)
|
|
|
|
tk.Button(frm_move, text="←", command=lambda: self.calibration.move_grid(-10, 0)).grid(row=1, column=0)
|
|
|
|
Button(frm_move, text="←", command=lambda: self.calibration.move_grid(-10, 0)).grid(row=1, column=0)
|
|
|
|
tk.Button(frm_move, text="↓", command=lambda: self.calibration.move_grid(0, 10)).grid(row=1, column=1)
|
|
|
|
Button(frm_move, text="↓", command=lambda: self.calibration.move_grid(0, 10)).grid(row=1, column=1)
|
|
|
|
tk.Button(frm_move, text="→", command=lambda: self.calibration.move_grid(10, 0)).grid(row=1, column=2)
|
|
|
|
Button(frm_move, text="→", command=lambda: self.calibration.move_grid(10, 0)).grid(row=1, column=2)
|
|
|
|
|
|
|
|
|
|
|
|
tk.Label(self.calib_window, text="Rotar", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
tk.Label(self.calib_window, text="Rotar", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
frm_rot = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_rot = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_rot.pack()
|
|
|
|
frm_rot.pack()
|
|
|
|
tk.Button(frm_rot, text="↺ -5°", command=lambda: self.calibration.rotate_grid(-5)).pack(side="left", padx=5)
|
|
|
|
Button(frm_rot, text="↺ -5°", command=lambda: self.calibration.rotate_grid(-5)).pack(side="left", padx=5)
|
|
|
|
tk.Button(frm_rot, text="↻ +5°", command=lambda: self.calibration.rotate_grid(5)).pack(side="left", padx=5)
|
|
|
|
Button(frm_rot, text="↻ +5°", command=lambda: self.calibration.rotate_grid(5)).pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
tk.Label(self.calib_window, text="Escalar", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
tk.Label(self.calib_window, text="Escalar", bg=BG_COLOR, fg="white").pack(pady=5)
|
|
|
|
frm_scale = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_scale = tk.Frame(self.calib_window, bg=BG_COLOR)
|
|
|
|
frm_scale.pack()
|
|
|
|
frm_scale.pack()
|
|
|
|
tk.Button(frm_scale, text="-", command=lambda: self.calibration.scale_grid(0.9)).pack(side="left", padx=5)
|
|
|
|
Button(frm_scale, text="-", command=lambda: self.calibration.scale_grid(0.9)).pack(side="left", padx=5)
|
|
|
|
tk.Button(frm_scale, text="+", command=lambda: self.calibration.scale_grid(1.1)).pack(side="left", padx=5)
|
|
|
|
Button(frm_scale, text="+", command=lambda: self.calibration.scale_grid(1.1)).pack(side="left", padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
tk.Label(self.calib_window, text="Altura Referencia (m)", bg=BG_COLOR, fg="white").pack(pady=10)
|
|
|
|
tk.Label(self.calib_window, text="Altura Referencia (m)", bg=BG_COLOR, fg="white").pack(pady=10)
|
|
|
|
# Aquí iría el control de altura, por ahora solo visual
|
|
|
|
# Aquí iría el control de altura, por ahora solo visual
|
|
|
|
@@ -919,8 +934,8 @@ class App:
|
|
|
|
log_to_excel("Reset", "Manual", 0, self.log_text)
|
|
|
|
log_to_excel("Reset", "Manual", 0, self.log_text)
|
|
|
|
win.destroy()
|
|
|
|
win.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
tk.Button(win, text="Aplicar", command=apply, bg=ACCENT_COLOR, fg="white").pack(pady=5)
|
|
|
|
Button(win, text="Aplicar", command=apply, bg=ACCENT_COLOR, fg="white").pack(pady=5)
|
|
|
|
tk.Button(win, text="Resetear Contadores a 0", command=reset_all, bg="#e06c75", fg="white").pack(pady=20)
|
|
|
|
Button(win, text="Resetear Contadores a 0", command=reset_all, bg="#e06c75", fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
|
|
def get_img_coords(self, event):
|
|
|
|
def get_img_coords(self, event):
|
|
|
|
if self.current_frame_size is None: return 0, 0
|
|
|
|
if self.current_frame_size is None: return 0, 0
|
|
|
|
@@ -1012,7 +1027,7 @@ class App:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
if self.cap.isOpened():
|
|
|
|
if self.cap.isOpened():
|
|
|
|
self.cap.release()
|
|
|
|
self.cap.release()
|
|
|
|
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
|
|
|
|
self.cap = cv2.VideoCapture(0, V_BACKEND)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
|
|
|
|
except:
|
|
|
|
except:
|