From cb00b83efb30efaebd1aecdbfd0444b5b5a6a74f Mon Sep 17 00:00:00 2001 From: mhby1g21 <mhby1g21@soton.ac.uk> Date: Tue, 29 Oct 2024 12:35:47 +0000 Subject: [PATCH] progress bar added, and output async for enhance, but not working for infer for some reason --- scripts/debug_tool/tabs/edge_net_tab.py | 254 +++++++++++++++++------- 1 file changed, 185 insertions(+), 69 deletions(-) diff --git a/scripts/debug_tool/tabs/edge_net_tab.py b/scripts/debug_tool/tabs/edge_net_tab.py index 8331e2e..754b68f 100644 --- a/scripts/debug_tool/tabs/edge_net_tab.py +++ b/scripts/debug_tool/tabs/edge_net_tab.py @@ -1,10 +1,12 @@ - import tkinter as tk from tkinter import ttk, messagebox, filedialog import os -from PIL import Image, ImageTk import subprocess import shutil +from PIL import Image, ImageTk +import threading +import queue +import time class EdgeNetTab: def __init__(self, notebook, config_reader): @@ -28,7 +30,19 @@ class EdgeNetTab: 'material.png': None } + # Add queue for process output + self.output_queue = queue.Queue() + + # Add processing flag + self.is_processing = False + + # Add progress variables + self.progress_var = tk.DoubleVar(value=0) + self.setup_ui() + + # Start output monitoring + self.monitor_output() def setup_ui(self): # Split into left and right frames @@ -189,7 +203,88 @@ class EdgeNetTab: ) self.status_text.pack(fill=tk.BOTH, expand=True) status_scroll.config(command=self.status_text.yview) + + # Add progress bar + progress_frame = ttk.LabelFrame(parent, text="Progress", padding="5") + progress_frame.pack(fill=tk.X, pady=5) + + self.progress_bar = ttk.Progressbar( + progress_frame, + mode='indeterminate', + variable=self.progress_var + ) + self.progress_bar.pack(fill=tk.X, padx=5, pady=5) + + # Add current operation label + self.operation_label = ttk.Label(progress_frame, text="") + self.operation_label.pack(pady=5) + + # Add cancel button (initially disabled) + self.cancel_button = ttk.Button( + progress_frame, + text="Cancel Operation", + command=self.cancel_operation, + state='disabled' + ) + self.cancel_button.pack(pady=5) + def run_process_with_output(self, cmd, description): + """Run a process and capture output in real-time""" + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True, + text=True, + bufsize=1, + universal_newlines=True + ) + + # Function to read output stream + def read_output(stream, queue): + for line in iter(stream.readline, ''): + queue.put(line) + stream.close() + + # Start output reader threads + stdout_thread = threading.Thread( + target=read_output, + args=(process.stdout, self.output_queue) + ) + stderr_thread = threading.Thread( + target=read_output, + args=(process.stderr, self.output_queue) + ) + + stdout_thread.daemon = True + stderr_thread.daemon = True + stdout_thread.start() + stderr_thread.start() + + # Wait for process to complete + return_code = process.wait() + + # Wait for output threads to finish + stdout_thread.join() + stderr_thread.join() + + return return_code + + def monitor_output(self): + """Monitor and display process output""" + try: + while True: + try: + line = self.output_queue.get_nowait() + self.update_status(line.strip()) + self.status_text.see(tk.END) + except queue.Empty: + break + finally: + # Schedule next check + if self.is_processing: + self.tab.after(100, self.monitor_output) + def setup_preview_panel(self, parent): preview_frame = ttk.LabelFrame(parent, text="Process Previews", padding="5") preview_frame.pack(fill=tk.BOTH, expand=True) @@ -342,94 +437,115 @@ class EdgeNetTab: return True def run_edge_net(self): + if self.is_processing: + messagebox.showwarning("Warning", "A process is already running!") + return + + # Start processing in a separate thread + thread = threading.Thread(target=self._run_edge_net_thread) + thread.daemon = True + thread.start() + + # Start progress bar + self.progress_bar.start(10) + self.is_processing = True + self.cancel_button.config(state='normal') + + # Start output monitoring + self.monitor_output() + + def _run_edge_net_thread(self): + """Run EdgeNet processing in a separate thread""" try: # Verify input files first + self.operation_label.config(text="Verifying input files...") if not self.verify_enhance360_inputs(): - # Try to copy manual inputs if verification failed self.update_status("Attempting to copy manual inputs...") self.copy_input_files() - # Verify again after copying if not self.verify_enhance360_inputs(): raise Exception("Missing required input files for enhance360.py") - - self.update_status("Running EdgeNet...") - self.edge_status.config(text="Running...", foreground="orange") - # Change to EdgeNet directory original_dir = os.getcwd() os.chdir(self.edge_net_dir) - # Run enhance360.py - self.update_status("Running enhance360.py...") - enhance_cmd = (f'wsl bash -c "source {self.config_reader.config["wslAnacondaDir"]}/activate' - f' {self.config_reader.config["edgeNetEnv"]} && ' - f'python enhance360.py Input depth_e.png rgb.png enhanced_depth_e.png"') - - self.update_status(f"Executing command:\n{enhance_cmd}") - - process = subprocess.Popen( - enhance_cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True, - text=True - ) - stdout, stderr = process.communicate() - - if stdout: - self.update_status("enhance360.py output:\n" + stdout) - if stderr: - self.update_status("enhance360.py error:\n" + stderr) - - if process.returncode != 0: - raise Exception(f"enhance360.py failed: {stderr}") + try: + # Run enhance360.py + self.operation_label.config(text="Running enhance360.py...") + enhance_cmd = (f'wsl bash -c "source {self.config_reader.config["wslAnacondaDir"]}/activate' + f' {self.config_reader.config["edgeNetEnv"]} && ' + f'python enhance360.py Input depth_e.png rgb.png enhanced_depth_e.png"') - # Verify files for infer360.py - if not self.verify_infer360_inputs(): - raise Exception("Missing required input files for infer360.py") + self.update_status(f"Executing command:\n{enhance_cmd}") - # Run infer360.py - self.update_status("Running infer360.py...") - include_top_flag = "--include_top y" if self.include_top.get() else "" - infer_cmd = (f'wsl bash -c "source {self.config_reader.config["wslAnacondaDir"]}/activate' - f' {self.config_reader.config["edgeNetEnv"]} && ' - f'python infer360.py Input enhanced_depth_e.png material.png rgb.png Input {include_top_flag}"') - - self.update_status(f"Executing command:\n{infer_cmd}") - - process = subprocess.Popen( - infer_cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True, - text=True - ) - stdout, stderr = process.communicate() - - if stdout: - self.update_status("infer360.py output:\n" + stdout) - if stderr: - self.update_status("infer360.py error:\n" + stderr) + if self.run_process_with_output(enhance_cmd, "enhance360.py") != 0: + raise Exception("enhance360.py failed") + + # Verify files for infer360.py + self.operation_label.config(text="Verifying infer360.py inputs...") + if not self.verify_infer360_inputs(): + raise Exception("Missing required input files for infer360.py") + + # Run infer360.py + self.operation_label.config(text="Running infer360.py...") + include_top_flag = "--include_top y" if self.include_top.get() else "" + infer_cmd = (f'wsl bash -c "source {self.config_reader.config["wslAnacondaDir"]}/activate' + f' {self.config_reader.config["edgeNetEnv"]} && ' + f'python infer360.py Input enhanced_depth_e.png material.png rgb.png Input {include_top_flag}"') + + self.update_status(f"Executing command:\n{infer_cmd}") + + if self.run_process_with_output(infer_cmd, "infer360.py") != 0: + raise Exception("infer360.py failed") + + finally: + os.chdir(original_dir) + # Deactivate WSL environment + subprocess.run('wsl bash -c "conda deactivate"', shell=True) - if process.returncode != 0: - raise Exception(f"infer360.py failed: {stderr}") + self.tab.after(0, self._process_complete, True) + except Exception as e: + self.tab.after(0, self._process_complete, False, str(e)) + + finally: + self.is_processing = False + + def _process_complete(self, success, error_message=None): + """Handle process completion in the main thread""" + self.progress_bar.stop() + self.cancel_button.config(state='disabled') + self.operation_label.config(text="") + + if success: self.update_status("EdgeNet processing completed successfully") self.edge_status.config(text="✓ Complete", foreground="green") self.update_depth_preview() - - except Exception as e: - self.update_status(f"Error in EdgeNet: {str(e)}") + else: + self.update_status(f"Error in EdgeNet: {error_message}") self.edge_status.config(text="✗ Failed", foreground="red") - messagebox.showerror("Error", f"EdgeNet failed: {str(e)}") - finally: - if original_dir: - os.chdir(original_dir) - - # Deactivate WSL environment - subprocess.run('wsl bash -c "conda deactivate"', shell=True) + messagebox.showerror("Error", f"EdgeNet failed: {error_message}") + def cancel_operation(self): + """Attempt to cancel the current operation""" + if not self.is_processing: + return + + if messagebox.askyesno("Confirm Cancel", "Are you sure you want to cancel the current operation?"): + self.update_status("Attempting to cancel operation...") + # TODO: Implement actual process cancellation + # This might require storing process handles and sending signals + self.is_processing = False + + def update_status(self, message): + """Thread-safe status update""" + self.tab.after(0, self._update_status_safe, message) + + def _update_status_safe(self, message): + """Update status text in the main thread""" + self.status_text.insert(tk.END, f"{message}\n") + self.status_text.see(tk.END) + def run_mesh_split(self): try: # Verify input files first -- GitLab