Skip to content
Snippets Groups Projects
Commit 34d72aaf authored by mhby1g21's avatar mhby1g21
Browse files

refactored material tab (much more managable file size/lines now)

parent 2248f5aa
No related branches found
No related tags found
1 merge request!4GDP 4.2.10 - Adding Debug mode to GUI.py to run individual modules
......@@ -5,6 +5,7 @@ import os
from tabs.config_tab import ConfigTab
from tabs.shifter_tab import ShifterTab
from tabs.depth_tab import DepthTab
from tabs.material_tab import MaterialTab
from utils.config_reader import ConfigReader
class ModuleDebugGUI(QMainWindow):
......@@ -38,6 +39,7 @@ class ModuleDebugGUI(QMainWindow):
self.tabs.addTab(ConfigTab(self.config_reader), "Configuration")
self.tabs.addTab(ShifterTab(self.config_reader), "Image Shifter")
self.tabs.addTab(DepthTab(self.config_reader), "MonoDepth Estimation")
self.tabs.addTab(MaterialTab(self.config_reader), "Material Recognition")
def main():
app = QApplication(sys.argv)
......
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
# tabs/material_tab.py
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
QMessageBox, QTabWidget)
from PyQt6.QtCore import Qt
import os
from PIL import Image, ImageTk
import subprocess
import shutil
class MaterialTab:
def __init__(self, notebook, config_reader):
self.tab = ttk.Frame(notebook)
notebook.add(self.tab, text='Material Recognition')
from utils.qt_widgets import (create_group_with_text, create_button_layout,
create_info_group, create_preview_group,
create_status_label, create_preview_grid,
update_status_indicator, get_status_text)
from utils.file_handlers import select_file, clean_directory, run_command
from utils.image_handlers import (update_preview, update_face_previews,
clear_previews)
class MaterialTab(QWidget):
def __init__(self, config_reader):
super().__init__()
self.config_reader = config_reader
self.input_file_path = None
......@@ -17,346 +22,169 @@ class MaterialTab:
self.material_recog_dir = self.config_reader.directories['materialRecogDir']
self.checkpoint_file = self.config_reader.file_paths['checkpointFile']
self.cubemap_dir = os.path.join(self.material_recog_dir, "cubemap_faces")
self.material_output_dir = os.path.join(self.material_recog_dir, "output", "cubemap_faces")
self.setup_ui()
self.verify_checkpoint()
def setup_ui(self):
# Split into left and right frames
left_frame = ttk.Frame(self.tab)
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
right_frame = ttk.Frame(self.tab)
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
self.setup_control_panel(left_frame)
self.setup_preview_panel(right_frame)
def setup_control_panel(self, parent):
# Control section
control_frame = ttk.LabelFrame(parent, text="Controls", padding="5")
control_frame.pack(fill=tk.X, pady=5)
# Input file selection
input_frame = ttk.Frame(control_frame)
input_frame.pack(fill=tk.X, pady=5)
ttk.Label(input_frame, text="Input file:").pack(side=tk.LEFT, padx=5)
self.input_label = ttk.Label(input_frame, text="No file selected")
self.input_label.pack(side=tk.LEFT, padx=5)
# Checkpoint file verification
checkpoint_frame = ttk.Frame(control_frame)
checkpoint_frame.pack(fill=tk.X, pady=5)
ttk.Label(checkpoint_frame, text="Checkpoint file:").pack(side=tk.LEFT, padx=5)
self.checkpoint_label = ttk.Label(
checkpoint_frame,
text="✓ Found" if os.path.exists(self.checkpoint_file) else "✗ Missing",
foreground="green" if os.path.exists(self.checkpoint_file) else "red"
)
self.checkpoint_label.pack(side=tk.LEFT, padx=5)
main_layout = QHBoxLayout(self)
main_layout.setContentsMargins(10, 10, 10, 10)
# Left panel (controls)
left_layout = QVBoxLayout()
self.setup_control_panel(left_layout)
main_layout.addLayout(left_layout)
# Right panel (preview)
right_layout = QVBoxLayout()
self.setup_preview_panel(right_layout)
main_layout.addLayout(right_layout)
def setup_control_panel(self, layout):
# Info display
info_rows = [
("Input file:", "No file selected"),
("Checkpoint:", "✓ Found" if os.path.exists(self.checkpoint_file) else "✗ Missing")
]
info_group, self.info_labels = create_info_group("Controls", info_rows)
layout.addWidget(info_group)
# Progress indicators
self.progress_frame = ttk.LabelFrame(control_frame, text="Progress", padding="5")
self.progress_frame.pack(fill=tk.X, pady=5)
# Split progress
split_frame = ttk.Frame(self.progress_frame)
split_frame.pack(fill=tk.X, pady=2)
ttk.Label(split_frame, text="Split 360:").pack(side=tk.LEFT, padx=5)
self.split_status = ttk.Label(split_frame, text="Not started")
self.split_status.pack(side=tk.LEFT, padx=5)
# Material recognition progress
recog_frame = ttk.Frame(self.progress_frame)
recog_frame.pack(fill=tk.X, pady=2)
ttk.Label(recog_frame, text="Material Recognition:").pack(side=tk.LEFT, padx=5)
self.recog_status = ttk.Label(recog_frame, text="Not started")
self.recog_status.pack(side=tk.LEFT, padx=5)
# Combine progress
combine_frame = ttk.Frame(self.progress_frame)
combine_frame.pack(fill=tk.X, pady=2)
ttk.Label(combine_frame, text="Combine Output:").pack(side=tk.LEFT, padx=5)
self.combine_status = ttk.Label(combine_frame, text="Not started")
self.combine_status.pack(side=tk.LEFT, padx=5)
# Control buttons
button_frame = ttk.Frame(control_frame)
button_frame.pack(fill=tk.X, pady=5)
ttk.Button(
button_frame,
text="Clean Working Dir",
command=self.clean_working_dir
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Select Input",
command=self.select_input_file
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Run Split 360",
command=self.run_split_360
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Run Material Recognition",
command=self.run_material_recognition
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Run Combine",
command=self.run_combine
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Run All Steps",
command=self.run_all_steps
).pack(side=tk.LEFT, padx=5)
ttk.Button(
button_frame,
text="Clear Status",
command=self.clear_status
).pack(side=tk.RIGHT, padx=5)
# Status section
status_frame = ttk.LabelFrame(parent, text="Status", padding="5")
status_frame.pack(fill=tk.BOTH, expand=True, pady=5)
# Add scrollbar to status
status_scroll = ttk.Scrollbar(status_frame)
status_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.status_text = tk.Text(
status_frame,
height=10,
wrap=tk.WORD,
yscrollcommand=status_scroll.set
)
self.status_text.pack(fill=tk.BOTH, expand=True)
status_scroll.config(command=self.status_text.yview)
progress_group = QGroupBox("Progress")
progress_layout = QVBoxLayout(progress_group)
self.split_status = create_status_label("Split 360:", "Not started")
self.recognition_status = create_status_label("Material Recognition:", "Not started")
self.combine_status = create_status_label("Combine Output:", "Not started")
progress_layout.addLayout(self.split_status)
progress_layout.addLayout(self.recognition_status)
progress_layout.addLayout(self.combine_status)
layout.addWidget(progress_group)
# Buttons
buttons = [
("Clean Working Dir", self.clean_working_dir, 'left'),
("Select Input", self.select_input, 'left'),
("Run Split 360", self.run_split_360, 'left'),
("Run Recognition", self.run_material_recognition, 'left'),
("Run Combine", self.run_combine, 'left'),
("Run All Steps", self.run_all_steps, 'left'),
("Clear Status", lambda: self.status_text.clear(), 'right')
]
layout.addLayout(create_button_layout(*buttons))
# Status display
status_group, self.status_text = create_group_with_text("Status", 150)
layout.addWidget(status_group)
def setup_preview_panel(self, parent):
notebook = ttk.Notebook(parent)
notebook.pack(fill=tk.BOTH, expand=True)
def setup_preview_panel(self, layout):
preview_tabs = QTabWidget()
# Input/Output preview tab
io_frame = ttk.Frame(notebook)
notebook.add(io_frame, text='Input/Output')
io_tab = QWidget()
io_layout = QVBoxLayout(io_tab)
# Input preview
input_frame = ttk.LabelFrame(io_frame, text="Input Image")
input_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
input_group, self.input_preview = create_preview_group("Input Image")
output_group, self.output_preview = create_preview_group("Material Map")
self.input_preview = ttk.Label(input_frame)
self.input_preview.pack(padx=5, pady=5)
io_layout.addWidget(input_group)
io_layout.addWidget(output_group)
preview_tabs.addTab(io_tab, "Input/Output")
# Material map preview
output_frame = ttk.LabelFrame(io_frame, text="Material Map")
output_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# RGB faces preview tab
rgb_tab = QWidget()
rgb_layout = QVBoxLayout(rgb_tab)
self.output_preview = ttk.Label(output_frame)
self.output_preview.pack(padx=5, pady=5)
self.rgb_face_previews = {}
faces_layout = create_preview_grid(
['front', 'back', 'left', 'right', 'top', 'bottom'],
self.rgb_face_previews
)
rgb_layout.addLayout(faces_layout)
preview_tabs.addTab(rgb_tab, "RGB Cube Faces")
# RGB Cube faces preview tab
rgb_faces_frame = ttk.Frame(notebook)
notebook.add(rgb_faces_frame, text='RGB Cube Faces')
# Material faces preview tab
material_tab = QWidget()
material_layout = QVBoxLayout(material_tab)
# Create grid for RGB cube faces
self.rgb_face_previews = {}
face_names = ['front', 'back', 'left', 'right', 'top', 'bottom']
row = 0
col = 0
for face in face_names:
frame = ttk.LabelFrame(rgb_faces_frame, text=face)
frame.grid(row=row, column=col, padx=5, pady=5, sticky='nsew')
label = ttk.Label(frame)
label.pack(padx=5, pady=5)
self.rgb_face_previews[face] = label
col += 1
if col > 2: # 3 columns
col = 0
row += 1
# Configure grid weights for RGB faces
rgb_faces_frame.grid_columnconfigure(0, weight=1)
rgb_faces_frame.grid_columnconfigure(1, weight=1)
rgb_faces_frame.grid_columnconfigure(2, weight=1)
# Material Cube faces preview tab
material_faces_frame = ttk.Frame(notebook)
notebook.add(material_faces_frame, text='Material Cube Faces')
# Create grid for material cube faces
self.material_face_previews = {}
row = 0
col = 0
face_names = ['frontrgb', 'backrgb', 'leftrgb', 'rightrgb', 'toprgb', 'bottomrgb']
for face in face_names:
frame = ttk.LabelFrame(material_faces_frame, text=face)
frame.grid(row=row, column=col, padx=5, pady=5, sticky='nsew')
label = ttk.Label(frame)
label.pack(padx=5, pady=5)
self.material_face_previews[face] = label
col += 1
if col > 2: # 3 columns
col = 0
row += 1
# Configure grid weights for material faces
material_faces_frame.grid_columnconfigure(0, weight=1)
material_faces_frame.grid_columnconfigure(1, weight=1)
material_faces_frame.grid_columnconfigure(2, weight=1)
material_faces_layout = create_preview_grid(
['front', 'back', 'left', 'right', 'top', 'bottom'],
self.material_face_previews
)
material_layout.addLayout(material_faces_layout)
preview_tabs.addTab(material_tab, "Material Cube Faces")
def clean_working_dir(self):
"""Clean all working directories"""
try:
directories_to_clean = [
# Main cubemap_faces directory
self.cubemap_dir,
# Output cubemap_faces directory for material maps
os.path.join(self.material_recog_dir, "output", "cubemap_faces"),
]
layout.addWidget(preview_tabs)
for directory in directories_to_clean:
if os.path.exists(directory):
self.update_status(f"Cleaning directory: {directory}")
shutil.rmtree(directory)
# Recreate directories
os.makedirs(directory, exist_ok=True)
self.update_status("All working directories cleaned")
# Reset status indicators
self.split_status.config(text="Not started")
self.recog_status.config(text="Not started")
self.combine_status.config(text="Not started")
# Clear all previews
self.clear_previews()
except Exception as e:
error_msg = f"Error cleaning directories: {str(e)}"
self.update_status(error_msg)
messagebox.showerror("Error", error_msg)
def clear_previews(self):
"""Clear all image previews"""
self.input_preview.configure(image='')
self.output_preview.configure(image='')
for face_preview in self.rgb_face_previews.values():
face_preview.configure(image='')
for face_preview in self.material_face_previews.values():
face_preview.configure(image='')
def select_input_file(self):
filepath = filedialog.askopenfilename(
filetypes=[("Image files", "*.png *.jpg *.jpeg")]
def select_input(self):
file_path = select_file(
self,
"Select Input Image",
"Images (*.png *.jpg *.jpeg)"
)
if filepath:
self.input_file_path = os.path.normpath(filepath)
self.input_label.config(text=os.path.basename(filepath))
self.update_status(f"Selected input file: {filepath}")
self.update_input_preview()
# Reset status indicators
self.split_status.config(text="Not started")
self.recog_status.config(text="Not started")
self.combine_status.config(text="Not started")
if file_path:
self.input_file_path = file_path
self.info_labels["Input file:"].setText(os.path.basename(file_path))
self.update_status(f"Selected input file: {file_path}")
update_preview(self.input_preview, file_path,
error_callback=self.update_status)
self.reset_status_indicators()
def clean_working_dir(self):
dirs_to_clean = [self.cubemap_dir, self.material_output_dir]
for directory in dirs_to_clean:
if not clean_directory(directory, self.update_status):
QMessageBox.critical(self, "Error", f"Failed to clean directory: {directory}")
return
clear_previews(
self.input_preview,
self.output_preview,
self.rgb_face_previews,
self.material_face_previews
)
self.reset_status_indicators()
def run_split_360(self):
if not self.input_file_path:
messagebox.showwarning("Warning", "Please select an input file first")
QMessageBox.warning(self, "Warning", "Please select an input file first")
return
try:
self.update_status("Running 360 image splitting...")
self.split_status.config(text="Running...", foreground="orange")
update_status_indicator(self.split_status, "Running")
# Change to material recognition directory
original_dir = os.getcwd()
os.chdir(self.material_recog_dir)
# Run split_img.py
cmd = f'''call "{self.config_reader.config["condaDir"]}\\condabin\\activate.bat" {self.config_reader.config["materialEnv"]} && python split_img.py "{self.input_file_path}" && call "{self.config_reader.config["condaDir"]}\\condabin\\deactivate.bat"'''
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
text=True
)
stdout, stderr = process.communicate()
success, _ = run_command(self, cmd, self.update_status)
# Change back to original directory
os.chdir(original_dir)
if process.returncode == 0:
self.update_status("Split 360 completed successfully")
self.split_status.config(text="✓ Complete", foreground="green")
self.update_face_previews()
if success:
update_status_indicator(self.split_status, "Complete")
self.update_face_previews('rgb')
else:
self.update_status(f"Split 360 failed:\n{stderr}")
self.split_status.config(text="✗ Failed", foreground="red")
raise Exception(stderr)
except Exception as e:
self.update_status(f"Error in split 360: {str(e)}")
self.split_status.config(text="✗ Failed", foreground="red")
messagebox.showerror("Error", f"Split 360 failed: {str(e)}")
def run_command(self, cmd, description):
"""Run a single command and return its output"""
self.update_status(f"Executing {description}:\n{cmd}")
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
text=True
)
stdout, stderr = process.communicate()
if process.returncode != 0:
self.update_status(f"Error in {description}:\n{stderr}")
raise Exception(f"{description} failed: {stderr}")
if stdout:
self.update_status(f"{description} output:\n{stdout}")
return process.returncode == 0
update_status_indicator(self.split_status, "Failed")
def run_material_recognition(self):
if not os.path.exists(self.cubemap_dir):
messagebox.showwarning("Warning", "Please run Split 360 first")
QMessageBox.warning(self, "Warning", "Please run Split 360 first")
return
try:
self.update_status("Running material recognition...")
self.recog_status.config(text="Running...", foreground="orange")
update_status_indicator(self.recognition_status, "Running")
# Save current directory
original_dir = os.getcwd()
# Change to material recognition directory
os.chdir(self.material_recog_dir)
# Combine conda activation and Python command into a single command using cmd /c
material_cmd = (
cmd = (
f'cmd /c ""{self.config_reader.config["condaDir"]}\\Scripts\\activate.bat" {self.config_reader.config["materialEnv"]} && '
f'python train_sota.py --data-root "./datasets" '
f'--batch-size 1 --tag dpglt --gpus 1 --num-nodes 1 '
......@@ -365,293 +193,79 @@ class MaterialTab:
f'--infer "{self.material_recog_dir}/cubemap_faces/"'
)
self.update_status(f"Executing command:\n{material_cmd}")
success, _ = run_command(self, cmd, self.update_status)
process = subprocess.Popen(
material_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
text=True
)
stdout, stderr = process.communicate()
if stdout:
self.update_status("\nOutput:\n" + stdout)
if stderr:
self.update_status("\nError output:\n" + stderr)
# Check error level
if process.returncode != 0:
self.update_status("Error: Material recognition failed. Please check the output above for more details.")
raise Exception(stderr if stderr else "Material recognition failed")
self.update_status("Material recognition completed successfully")
self.recog_status.config(text="✓ Complete", foreground="green")
except Exception as e:
self.update_status(f"Error in material recognition: {str(e)}")
self.recog_status.config(text="✗ Failed", foreground="red")
messagebox.showerror("Error", f"Material recognition failed: {str(e)}")
finally:
self.update_material_face_previews()
if original_dir:
os.chdir(original_dir)
def verify_input_directory(self):
"""Verify that the input directory has the correct files"""
required_files = ['front.png', 'back.png', 'left.png', 'right.png', 'top.png', 'bottom.png']
missing_files = []
for file in required_files:
if not os.path.exists(os.path.join(self.cubemap_dir, file)):
missing_files.append(file)
if missing_files:
self.update_status("Missing required files:")
for file in missing_files:
self.update_status(f"- {file}")
return False
self.update_status("All required input files present")
return True
def verify_working_directory(self):
"""Verify that we're in the correct directory with required files"""
required_paths = [
"./datasets",
self.checkpoint_file,
"train_sota.py"
]
missing_paths = []
for path in required_paths:
if not os.path.exists(path):
missing_paths.append(path)
if missing_paths:
self.update_status("Missing required paths:")
for path in missing_paths:
self.update_status(f"- {path}")
return False
self.update_status("All required paths present")
return True
# Add a method to verify conda environment
def verify_conda_env(self):
"""Verify that the conda environment exists"""
try:
cmd = f'call "{self.config_reader.config["condaDir"]}\\condabin\\conda.bat" env list'
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
text=True
)
stdout, stderr = process.communicate()
if process.returncode == 0:
env_name = self.config_reader.config["materialEnv"]
if env_name in stdout:
self.update_status(f"Found conda environment: {env_name}")
return True
else:
self.update_status(f"Conda environment not found: {env_name}")
return False
if success:
update_status_indicator(self.recognition_status, "Complete")
self.update_face_previews('material')
else:
self.update_status(f"Failed to list conda environments: {stderr}")
return False
except Exception as e:
self.update_status(f"Error checking conda environment: {str(e)}")
return False
update_status_indicator(self.recognition_status, "Failed")
def run_combine(self):
try:
self.update_status("Running combine step...")
self.combine_status.config(text="Running...", foreground="orange")
update_status_indicator(self.combine_status, "Running")
# Change to material recognition directory
original_dir = os.getcwd()
os.chdir(self.material_recog_dir)
# Run combine script
cmd = f'''call "{self.config_reader.config["condaDir"]}\\condabin\\activate.bat" {self.config_reader.config["materialEnv"]} && python combine_img.py && call "{self.config_reader.config["condaDir"]}\\condabin\\deactivate.bat"'''
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
text=True
)
stdout, stderr = process.communicate()
success, _ = run_command(self, cmd, self.update_status)
# Change back to original directory
os.chdir(original_dir)
if process.returncode == 0:
self.update_status("Combine step completed successfully")
self.combine_status.config(text="✓ Complete", foreground="green")
self.update_output_preview()
if success:
update_status_indicator(self.combine_status, "Complete")
output_path = os.path.join(
self.config_reader.directories['edgeNetDir'],
'Data', 'Input', 'material.png'
)
update_preview(self.output_preview, output_path,
error_callback=self.update_status)
else:
self.update_status(f"Combine step failed:\n{stderr}")
self.combine_status.config(text="✗ Failed", foreground="red")
raise Exception(stderr)
except Exception as e:
self.update_status(f"Error in combine step: {str(e)}")
self.combine_status.config(text="✗ Failed", foreground="red")
messagebox.showerror("Error", f"Combine step failed: {str(e)}")
update_status_indicator(self.combine_status, "Failed")
def run_all_steps(self):
"""Run all steps in sequence"""
if not self.input_file_path:
messagebox.showwarning("Warning", "Please select an input file first")
QMessageBox.warning(self, "Warning", "Please select an input file first")
return
try:
# Run all steps
self.run_split_360()
if self.split_status.cget("text") == "Complete":
if get_status_text(self.split_status) == "Complete":
self.run_material_recognition()
if self.recog_status.cget("text") == "Complete":
if get_status_text(self.recognition_status) == "Complete":
self.run_combine()
except Exception as e:
self.update_status(f"Error in pipeline: {str(e)}")
messagebox.showerror("Error", f"Pipeline failed: {str(e)}")
def update_status(self, message):
self.status_text.insert(tk.END, f"{message}\n")
self.status_text.see(tk.END)
def clear_status(self):
self.status_text.delete(1.0, tk.END)
def update_input_preview(self):
"""Update the input image preview"""
if self.input_file_path and os.path.exists(self.input_file_path):
try:
preview_size = (300, 150) # Adjust size as needed for 360 image
input_img = Image.open(self.input_file_path)
input_img.thumbnail(preview_size)
input_photo = ImageTk.PhotoImage(input_img)
self.input_preview.configure(image=input_photo)
self.input_preview.image = input_photo
except Exception as e:
self.update_status(f"Failed to load input preview: {str(e)}")
def update_rgb_face_previews(self):
"""Update the RGB cube face previews"""
preview_size = (150, 150)
face_names = {
'front': 'front',
'back': 'back',
'left': 'left',
'right': 'right',
'top': 'top',
'bottom': 'bottom'
}
for face, filename in face_names.items():
face_path = os.path.join(self.cubemap_dir, f"{filename}.png")
if os.path.exists(face_path):
try:
face_img = Image.open(face_path)
face_img.thumbnail(preview_size)
face_photo = ImageTk.PhotoImage(face_img)
self.rgb_face_previews[face].configure(image=face_photo)
self.rgb_face_previews[face].image = face_photo
except Exception as e:
self.update_status(f"Failed to load RGB {face} preview: {str(e)}")
def update_material_face_previews(self):
"""Update the material map cube face previews"""
preview_size = (150, 150)
material_dir = os.path.join(self.material_recog_dir, "output", "cubemap_faces")
face_names = {
'frontrgb': 'frontrgb',
'backrgb': 'backrgb',
'leftrgb': 'leftrgb',
'rightrgb': 'rightrgb',
'toprgb': 'toprgb',
'bottomrgb': 'bottomrgb'
}
for face, filename in face_names.items():
face_path = os.path.join(material_dir, f"{filename}.png")
if os.path.exists(face_path):
try:
face_img = Image.open(face_path)
face_img.thumbnail(preview_size)
face_photo = ImageTk.PhotoImage(face_img)
self.material_face_previews[face].configure(image=face_photo)
self.material_face_previews[face].image = face_photo
except Exception as e:
self.update_status(f"Failed to load material {face} preview: {str(e)}")
def update_face_previews(self):
"""Update both RGB and material cube face previews"""
self.update_rgb_face_previews()
self.update_material_face_previews()
"""Update the material map cube face previews"""
preview_size = (150, 150)
material_dir = os.path.join(self.material_recog_dir, "output", "cubemap_faces")
face_names = {
'front': 'front',
'back': 'back',
'left': 'left',
'right': 'right',
'top': 'top',
'bottom': 'bottom'
}
for face, filename in face_names.items():
face_path = os.path.join(material_dir, f"{filename}.png")
if os.path.exists(face_path):
try:
face_img = Image.open(face_path)
face_img.thumbnail(preview_size)
face_photo = ImageTk.PhotoImage(face_img)
self.material_face_previews[face].configure(image=face_photo)
self.material_face_previews[face].image = face_photo
except Exception as e:
self.update_status(f"Failed to load material {face} preview: {str(e)}")
def update_output_preview(self):
"""Update the material map preview"""
try:
# First check in EdgeNet Input directory
output_path = os.path.join(
self.config_reader.directories['edgeNetDir'],
'Data',
'Input',
'material.png'
self.status_text.append(message)
scrollbar = self.status_text.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
def reset_status_indicators(self):
for status in [self.split_status, self.recognition_status, self.combine_status]:
update_status_indicator(status, "Not started")
def update_face_previews(self, preview_type='rgb'):
if preview_type == 'rgb':
update_face_previews(
self.rgb_face_previews,
self.cubemap_dir,
'.png',
self.update_status
)
else:
update_face_previews(
self.material_face_previews,
self.material_output_dir,
'rgb.png',
self.update_status
)
if not os.path.exists(output_path):
self.update_status("Material map not found in expected location")
return
preview_size = (300, 150) # Adjust size for 360 image
output_img = Image.open(output_path)
output_img.thumbnail(preview_size)
output_photo = ImageTk.PhotoImage(output_img)
self.output_preview.configure(image=output_photo)
self.output_preview.image = output_photo
except Exception as e:
self.update_status(f"Failed to load material map preview: {str(e)}")
def verify_checkpoint(self):
"""Verify that the checkpoint file exists"""
if not os.path.exists(self.checkpoint_file):
self.update_status("Warning: Checkpoint file not found!")
self.checkpoint_label.config(text="✗ Missing", foreground="red")
return False
self.checkpoint_label.config(text="✓ Found", foreground="green")
return True
\ No newline at end of file
exists = os.path.exists(self.checkpoint_file)
self.info_labels["Checkpoint:"].setText("✓ Found" if exists else "✗ Missing")
self.info_labels["Checkpoint:"].setStyleSheet(
"color: green" if exists else "color: red")
return exists
\ No newline at end of file
......@@ -75,3 +75,31 @@ def update_preview(preview_label, image_path, max_size=300, error_callback=None)
preview_label.clear()
if error_callback:
error_callback(f"Image not found: {image_path}")
def update_face_previews(preview_dict, src_dir, suffix='', error_callback=None):
"""
Updates a dictionary of face preview labels with images from directory.
Args:
preview_dict: Dictionary of face preview labels
src_dir: Directory containing face images
suffix: Suffix for face image filenames
error_callback: Optional callback function for error handling
"""
for face, preview in preview_dict.items():
face_path = os.path.join(src_dir, face + suffix)
update_preview(preview, face_path, error_callback=error_callback)
def clear_previews(*preview_widgets):
"""
Clears multiple preview widgets.
Args:
preview_widgets: List of preview widgets to clear
"""
for widget in preview_widgets:
if isinstance(widget, dict):
for preview in widget.values():
preview.clear()
else:
widget.clear()
\ No newline at end of file
......@@ -100,3 +100,86 @@ def create_preview_group(title):
preview.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(preview)
return group, preview
def create_status_label(label_text, initial_status="Not started"):
"""
Creates a status indicator layout with label and status.
Args:
label_text: Text for the label
initial_status: Initial status text
Returns:
QHBoxLayout layout with label and status
"""
layout = QHBoxLayout()
label = QLabel(label_text)
status = QLabel(initial_status)
layout.addWidget(label)
layout.addWidget(status, stretch=1)
return layout
def create_preview_grid(face_names, preview_dict, cols=3):
"""
Creates a grid layout of preview groups for cubemap faces.
Args:
face_names: List of face names
preview_dict: Dictionary to store preview widgets
cols: Number of columns
Returns:
QVBoxLayout layout with preview groups in grids for cubemap faces
"""
grid = QVBoxLayout()
row_layout = QHBoxLayout()
count = 0
for face in face_names:
group, preview = create_preview_group(face)
preview_dict[face] = preview
row_layout.addWidget(group)
count += 1
if count % cols == 0:
grid.addLayout(row_layout)
row_layout = QHBoxLayout()
if count % cols != 0:
grid.addLayout(row_layout)
return grid
def update_status_indicator(status_layout, state):
"""
Updates a status indicator with new state and color.
Args:
status_layout: QHBoxLayout layout with label and status
state: New status text
"""
label = status_layout.itemAt(1).widget()
states = {
"Running": ("Running...", "orange"),
"Complete": ("✓ Complete", "green"),
"Failed": ("✗ Failed", "red"),
"Not started": ("Not started", "black")
}
if state in states:
text, color = states[state]
label.setText(text)
label.setStyleSheet(f"color: {color}")
else:
label.setText(state)
label.setStyleSheet("")
def get_status_text(status_layout):
"""
Gets the current status text without markers.
Args:
status_layout: QHBoxLayout layout with label and status
Returns:
str: Current status text
"""
text = status_layout.itemAt(1).widget().text()
return text.replace("", "").replace("", "")
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment