diff --git a/scripts/360monodepthexecution/masterscript-min.ps1 b/scripts/360monodepthexecution/masterscript-min.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..4fa3e86855804f0b593a5efcdaa2a5f034e4b90e
--- /dev/null
+++ b/scripts/360monodepthexecution/masterscript-min.ps1
@@ -0,0 +1,6 @@
+invoke-expression 'cmd /c start powershell -WindowStyle Minimized -Command { .\triggerinteractive.ps1}'
+sleep 10
+Start-Process powershell "-File .\dockercopy.ps1" -WindowStyle Minimized -Wait
+Start-Process powershell "-File .\executemonodepth.ps1" -WindowStyle Minimized -Wait
+Start-Process powershell "-File .\extractDepthMap.ps1" -WindowStyle Minimized -Wait
+Start-Process powershell "-File .\stopDockerContainer.ps1" -WindowStyle Minimized -Wait
\ No newline at end of file
diff --git a/scripts/Depth2Disparity/depth2disparity.py b/scripts/Depth2Disparity/depth2disparity.py
new file mode 100644
index 0000000000000000000000000000000000000000..08c6bb232fc2aa7c70b4564cb33b96cd495e9606
--- /dev/null
+++ b/scripts/Depth2Disparity/depth2disparity.py
@@ -0,0 +1,105 @@
+# takes 2 pixel coordinates and corresponding distance values - and a relative depth map
+# caculates relative to absolute function - if linear
+# applies function to relative depth map to get absolute depth map
+# then convert to disparity map using depth disparity formula
+
+
+import argparse
+import numpy as np
+import cv2
+
+def relative2abs(rel_depth_map, coord1, dist1, coord2, dist2):
+    # Get the relative depth values at the two points
+    rel_value1 = rel_depth_map[coord1[1], coord1[0]]  # (y, x)
+    rel_value2 = rel_depth_map[coord2[1], coord2[0]]
+
+    # Calculate the linear transformation: depth = a * rel_depth + b
+    a = (dist2 - dist1) / (rel_value2 - rel_value1)
+    b = dist1 - a * rel_value1
+
+    # Apply the transformation to the entire relative depth map
+    abs_depth_map = a * rel_depth_map + b
+    
+    # this should not be normalised, the values in the array should equate to literal distances
+    return abs_depth_map
+
+def depth2disparity(abs_depth_map, baseline=0.176, disp_scale=2.0, disp_offset=-120):
+    
+    # Get image dimensions
+    height, width = abs_depth_map.shape
+
+    # Calculate angular coordinates for each pixel
+    unit_w = 2.0 / width  # Longitude step size
+    unit_h = 1.0 / height  # Latitude step size
+    
+    # Initialize disparity map
+    disparity_map = np.zeros_like(abs_depth_map, dtype=np.float32)
+
+    for i in range(height):
+        theta_t = i * unit_h * np.pi  # Latitude angle for the row
+
+        for j in range(width):
+            # Longitude angle (not strictly needed for disparity calculation)
+            phi = j * unit_w * np.pi
+
+            # Retrieve the absolute depth (r_t) for this pixel
+            r_t = abs_depth_map[i, j]
+
+            # Avoid invalid or infinite depth values
+            if r_t <= 0:
+                disparity_map[i, j] = 0
+                continue
+
+            try:
+                # Compute denominator with stability checks
+                epsilon = 1e-8  # Small value to prevent division instability
+                tan_theta_t = np.tan(theta_t) if np.abs(np.cos(theta_t)) > epsilon else np.sign(np.sin(theta_t)) * np.inf
+
+                denominator = r_t * np.sin(theta_t) + r_t * np.cos(theta_t) * tan_theta_t
+                if denominator <= 0:
+                    disparity_map[i, j] = 0
+                    continue
+
+                # Calculate angular disparity (d)
+                angle_disp = np.arctan(baseline / denominator) - theta_t
+
+                # Convert angular disparity to pixel disparity
+                disparity_map[i, j] = (angle_disp / (unit_h * np.pi) - disp_offset) * disp_scale
+
+            except ZeroDivisionError:
+                disparity_map[i, j] = 0
+
+    return disparity_map
+
+if __name__ == "__main__":
+    # Set up argument parser
+    parser = argparse.ArgumentParser(description="Convert relative depth map to absolute depth map.")
+    parser.add_argument("rel_depth_map", type=str, help="Path to the relative depth map (image file).")
+    parser.add_argument("coord1", type=int, nargs=2, help="Pixel coordinates of the first point (x y).")
+    parser.add_argument("dist1", type=float, help="Absolute depth value at the first point.")
+    parser.add_argument("coord2", type=int, nargs=2, help="Pixel coordinates of the second point (x y).")
+    parser.add_argument("dist2", type=float, help="Absolute depth value at the second point.")
+
+    # Parse arguments
+    args = parser.parse_args()
+
+    # Load the relative depth map (dummy placeholder for now)
+    print(f"Loading relative depth map from: {args.rel_depth_map}")
+    rel_depth_map = cv2.imread(args.rel_depth_map, cv2.IMREAD_GRAYSCALE)  # Load as grayscale
+    if rel_depth_map is None:
+        raise FileNotFoundError(f"Unable to load file: {args.rel_depth_map}")
+    
+    # Normalise depth map
+    rel_depth_map = rel_depth_map / 255.0
+
+    # Convert relative to absolute depth
+    abs_depth_map = relative2abs(
+        rel_depth_map, tuple(args.coord1), args.dist1, tuple(args.coord2), args.dist2
+    )
+    
+    # Convert depth map to disparity map
+    disparity_map = depth2disparity(abs_depth_map)
+    
+    # save disparity map
+    #cv2.imwrite(f"{args.rel_depth_map}-disparity.png", disparity_map)
+    
\ No newline at end of file
diff --git a/scripts/debug_tool/GUI_debug.py b/scripts/debug_tool/GUI_debug.py
index 1ce869060e8f77cfaeba0c421f9912e24c4b7967..eecf781d7df6fe0e693429e60bfc8158f375dbca 100644
--- a/scripts/debug_tool/GUI_debug.py
+++ b/scripts/debug_tool/GUI_debug.py
@@ -9,6 +9,7 @@ from tabs.depth_tab import DepthTab
 from tabs.material_tab import MaterialTab
 from tabs.edge_net_tab import EdgeNetTab
 from utils.config_reader import ConfigReader
+from tabs.mbdnet_tab import MBDNetTab
 
 class ModuleDebugGUI(QMainWindow):
     def __init__(self):
@@ -43,6 +44,7 @@ class ModuleDebugGUI(QMainWindow):
         self.tabs.addTab(DepthTab(self.config_reader), "MonoDepth Estimation")
         self.tabs.addTab(MaterialTab(self.config_reader), "Material Recognition")
         self.tabs.addTab(EdgeNetTab(self.config_reader), "EdgeNet Execution")
+        self.tabs.addTab(MBDNetTab(self.config_reader), "MBDNet Execution")
 
 def main():
     app = QApplication(sys.argv)
diff --git a/scripts/debug_tool/tabs/depth_tab.py b/scripts/debug_tool/tabs/depth_tab.py
index 30da9e51ae17ff8b1b2e3a9cddced0aa26365fb0..caca369486d7ca1c9ee9cc4b2f32cda2cabf2f1a 100644
--- a/scripts/debug_tool/tabs/depth_tab.py
+++ b/scripts/debug_tool/tabs/depth_tab.py
@@ -60,7 +60,7 @@ class DepthTab(QWidget):
             ("Clean Data/Input Dir", self.clean_input_dir, 'left'),
             ("Remove rgb.png from dest path", self.remove_rgb, 'left'),
             ("Copy File", self.copy_file, 'left'),
-            ("Run Depth Est.", self.run_depth_estimation, 'left'),
+            ("Run Depth Est.", lambda: self.run_depth_estimation(), 'left'),
             ("Clear Status", lambda: self.status_text.clear(), 'right')
         ]
         layout.addLayout(create_button_layout(*buttons))
@@ -124,19 +124,28 @@ class DepthTab(QWidget):
         if not copy_file(self.depth_input_path, edge_rgb_path, self.update_status):
             QMessageBox.critical(self, "Error", "Failed to copy file to edgenet directory")
 
-    def run_depth_estimation(self):
+    def run_depth_estimation(self, debug=True):
         try:
             self.update_status("Running depth estimation...")
             
             # Change to mono depth directory and run script
             original_dir = os.getcwd()
             os.chdir(self.config_reader.directories['monoDepthDir'])
-            
-            success, output = run_command(
-                self,
-                "powershell.exe -File masterscript.ps1",
-                self.update_status
-            )
+            if debug:
+                # Run script in debug mode
+                success, output = run_command(
+                    self,
+                    "powershell.exe -File masterscript.ps1",
+                    self.update_status
+                )
+            else:
+                # Run minified script for production
+                self.update_status("Running minified script...")
+                success, output = run_command(
+                    self,
+                    "powershell.exe -File masterscript-min.ps1 -WindowStyle Minimized",
+                    self.update_status
+                )
             
             # Change back to original directory
             os.chdir(original_dir)
diff --git a/scripts/debug_tool/tabs/mbdnet_tab.py b/scripts/debug_tool/tabs/mbdnet_tab.py
new file mode 100644
index 0000000000000000000000000000000000000000..165d59d067595a3ad70d4a746471c2c86bcf9219
--- /dev/null
+++ b/scripts/debug_tool/tabs/mbdnet_tab.py
@@ -0,0 +1,511 @@
+from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, 
+                           QPushButton, QCheckBox, QProgressBar, QTextEdit,
+                           QMessageBox, QFileDialog)
+from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer
+from PyQt6.QtGui import QPixmap
+import os
+import threading
+import queue
+import time
+import sys
+
+from utils.file_handlers import (select_file, run_command, clean_directory, 
+                               copy_file)
+from utils.image_handlers import update_preview, clear_previews
+from utils.qt_widgets import (create_group_with_text, create_button_layout,
+                            create_preview_group, create_status_label,
+                            update_status_indicator, show_confirmation_dialog)
+
+class ProcessThread(QThread):
+    finished = pyqtSignal(bool, str)
+    progress = pyqtSignal(str)
+    
+    def __init__(self, func, *args, **kwargs):
+        super().__init__()
+        self.func = func
+        self.args = args
+        self.kwargs = kwargs
+        self.running = True
+        
+    def run(self):
+        try:
+            if self.running:
+                result = self.func(*self.args, **self.kwargs)
+                self.finished.emit(True, "")
+        except Exception as e:
+            self.finished.emit(False, str(e))
+            
+    def stop(self):
+        self.running = False
+        self.wait()
+
+class MBDNetTab(QWidget):
+    def __init__(self, config_reader):
+        super().__init__()
+        self.config_reader = config_reader
+        self.setup_paths()
+        self.init_variables()
+        self.init_ui()
+        self.connect_signals()
+        self.current_thread = None
+        
+    def closeEvent(self, event):
+        """Handle widget close event"""
+        if self.current_thread and self.current_thread.isRunning():
+            self.current_thread.stop()
+            self.current_thread.wait()
+        event.accept()
+        
+    def setup_paths(self):
+        """Initialize directory and file paths"""
+        self.edge_net_dir = self.config_reader.directories['edgeNetDir']
+        self.output_dir = self.config_reader.directories['outputDir'] 
+        self.input_dir = os.path.join(self.edge_net_dir, "Data", "Input")
+        self.scripts_dir = self.config_reader.directories['scriptDir']
+        
+    def init_variables(self):
+        """Initialize class variables"""
+        self.is_processing = False
+        self.manual_inputs = {
+            'depth_e.png': None,
+            'rgb.png': None,
+        }
+        self.output_queue = queue.Queue()
+        
+    def init_ui(self):
+        """Initialize user interface"""
+        layout = QVBoxLayout()
+        
+        # Split into left and right sections
+        hlayout = QHBoxLayout()
+        left_panel = self.create_left_panel()
+        right_panel = self.create_right_panel()
+        
+        hlayout.addWidget(left_panel)
+        hlayout.addWidget(right_panel)
+        layout.addLayout(hlayout)
+        
+        # Initialize progress bar to stopped state
+        self.progress_bar.setMaximum(100)
+        self.progress_bar.setValue(0)
+        
+        self.setLayout(layout)
+        
+    def create_left_panel(self):
+        """Create left control panel"""
+        widget = QWidget()
+        layout = QVBoxLayout()
+        
+        # Input files section
+        files_group = self.create_input_files_group()
+        layout.addWidget(files_group)
+        
+        # Status section
+        self.status_group, self.status_text = create_group_with_text("Status",300)
+        layout.addWidget(self.status_group)
+        
+        # Progress section
+        progress_group = self.create_progress_group()
+        layout.addWidget(progress_group)
+        
+        # Control buttons
+        button_layout = self.create_control_buttons()
+        layout.addLayout(button_layout)
+        
+        widget.setLayout(layout)
+        return widget
+        
+    def create_input_files_group(self):
+        """Create input files selection group"""
+        group = QWidget()
+        layout = QVBoxLayout()
+        
+        # File selection buttons
+        for file_type in self.manual_inputs.keys():
+            row = QHBoxLayout()
+            row.addWidget(QLabel(f"{file_type}:"))
+            label = QLabel("Using default")
+            setattr(self, f"{file_type.split('.')[0]}_label", label)
+            row.addWidget(label)
+            
+            btn = QPushButton("Select")
+            btn.clicked.connect(lambda checked, ft=file_type: self.select_input_file(ft))
+            row.addWidget(btn)
+            
+            layout.addLayout(row)
+            
+        # Reset button
+        reset_btn = QPushButton("Reset to Default Inputs")
+        reset_btn.clicked.connect(self.reset_inputs)
+        layout.addWidget(reset_btn)
+        
+        group.setLayout(layout)
+        return group
+        
+    def create_progress_group(self):
+        """Create progress indicators group"""
+        group = QWidget()
+        layout = QVBoxLayout()
+        
+        # Status indicators
+        self.MBDNet_status = create_status_label("MBDNet:")
+        self.split_status = create_status_label("Mesh Split:")
+        self.flip_status = create_status_label("Blender Flip:")
+        
+        layout.addLayout(self.MBDNet_status)
+        layout.addLayout(self.split_status)
+        layout.addLayout(self.flip_status)
+        
+        # Progress bar
+        self.progress_bar = QProgressBar()
+        layout.addWidget(self.progress_bar)
+        
+        # Operation label
+        self.operation_label = QLabel()
+        layout.addWidget(self.operation_label)
+        
+        group.setLayout(layout)
+        return group
+        
+    def create_right_panel(self):
+        """Create right preview panel"""
+        widget = QWidget()
+        layout = QVBoxLayout()
+        
+        # Preview groups
+        depth_group, self.depth_preview = create_preview_group("Enhanced Depth")
+        mesh_group, self.mesh_preview = create_preview_group("Generated Mesh")
+        
+        layout.addWidget(depth_group)
+        layout.addWidget(mesh_group)
+        
+        widget.setLayout(layout)
+        return widget
+        
+    def create_control_buttons(self):
+        """Create control buttons layout"""
+        return create_button_layout(
+            ("Run MBDNet", self.run_mbdnet, 'left'),
+            ("Run Mesh Split", self.run_mesh_split, 'left'),
+            ("Run Blender Flip", self.run_blender_flip, 'left'),
+            ("Run All Steps", self.run_all_steps, 'left'),
+            ("Clean Output", self.clean_output_directory, 'right'),
+            ("Clean All", self.clean_all_files, 'right')
+        )
+        
+    def connect_signals(self):
+        """Connect signals and slots"""
+        # Add any additional signal connections here
+        pass
+        
+    def select_input_file(self, file_type):
+        """Handle input file selection"""
+        file_path = select_file(self, "Select Input File", "Image Files (*.png)", initial_dir=self.input_dir)
+        if file_path:
+            self.manual_inputs[file_type] = file_path
+            label = getattr(self, f"{file_type.split('.')[0]}_label")
+            label.setText(os.path.basename(file_path))
+            self.update_status(f"Selected {file_type}: {file_path}")
+            
+    def reset_inputs(self):
+        """Reset input selections to default"""
+        self.manual_inputs = {k: None for k in self.manual_inputs}
+        for file_type in self.manual_inputs:
+            label = getattr(self, f"{file_type.split('.')[0]}_label")
+            label.setText("Using default")
+        self.update_status("Reset all inputs to default")
+        
+    def run_mbdnet(self):
+        """Run MBDNet processing"""
+        if self.is_processing:
+            QMessageBox.warning(self, "Warning", "A process is already running!")
+            return
+            
+        self.is_processing = True
+        self.progress_bar.setMaximum(0)
+        
+        self.current_thread = ProcessThread(self._run_mbdnet_process)
+        self.current_thread.finished.connect(self.on_mbdnet_complete)
+        self.current_thread.progress.connect(self.update_status)
+        self.current_thread.start()
+        
+    def clean_output_directory(self, silent=False):
+        if silent or show_confirmation_dialog(self, "Confirm Clean", "Clean output directory?"):
+            if clean_directory(self.output_dir, self.update_status):
+                self.update_status("Output directory cleaned")
+                update_status_indicator(self.split_status, "Not started")
+                update_status_indicator(self.flip_status, "Not started")
+                clear_previews(self.mesh_preview)
+
+    def clean_all_files(self):
+        if show_confirmation_dialog(self, "Confirm Clean", "Clean all files?"):
+            directories = [self.input_dir, self.output_dir]
+            for directory in directories:
+                clean_directory(directory, self.update_status)
+            
+            # remove monodepth image copied in 360monodepth if exists
+            if os.path.exists(os.path.join(self.config_reader.directories['monoDepthDir'], 'rgb.jpg')):
+                monodepth_image = os.path.join(self.config_reader.directories['monoDepthDir'], 'rgb.jpg')
+                os.remove(monodepth_image)
+            # remove shifted image from shifter if exists
+            if os.path.exists(os.path.join(self.config_reader.directories['scriptDir'], 'shifted_t.png')):
+                shifted_image = os.path.join(self.config_reader.directories['scriptDir'], 'shifted_t.png')
+                os.remove(shifted_image)
+            
+            update_status_indicator(self.MBDNet_status, "Not started")
+            update_status_indicator(self.split_status, "Not started")
+            update_status_indicator(self.flip_status, "Not started")
+            clear_previews(self.depth_preview, self.mesh_preview)
+
+    def update_status(self, message):
+        """Update status text"""
+        self.status_text.append(message)
+        
+    def verify_inputs(self):
+        """Verify input files exist"""
+        required_files = {
+            'depth_e.png': self.get_input_path('depth_e.png'),
+            'rgb.png': self.get_input_path('rgb.png')
+        }
+        
+        missing = [f for f, p in required_files.items() if not os.path.exists(p)]
+        if missing:
+            self.update_status("Missing required files: " + ", ".join(missing))
+            return False
+        return True
+        
+    def get_input_path(self, file_type):
+        """Get path for input file"""
+        return self.manual_inputs.get(file_type) or os.path.join(self.input_dir, file_type)
+        
+    def _run_mbdnet_process(self):
+        """Run MBDNet processing"""
+        # Change to EdgeNet directory
+        os.chdir(self.edge_net_dir)
+        try:
+            if not self.verify_inputs():
+                self.copy_input_files()
+                if not self.verify_inputs():
+                    raise Exception("Missing required input files")
+            #self.clean_output_directory(self.output_dir, True)
+            # copy rgb.png to shifted_t.png and enhanced_depth_e.png to shifted_disparity.png
+            os.rename(os.path.join(self.input_dir, 'rgb.png'), os.path.join(self.input_dir, 'shifted_t.png'))
+            os.rename(os.path.join(self.input_dir, 'depth_e.png'), os.path.join(self.input_dir, 'shifted_disparity.png'))
+            # Run scene_completion.py
+            os.chdir(self.scripts_dir)
+            infer_cmd = self._build_mbdnet_command()
+            print("Final command: ", infer_cmd)
+            return run_command(self, infer_cmd, self.update_status)[0]
+            
+        except Exception as e:
+            self.update_status(f"Error: {str(e)}")
+            return False
+            
+    def _build_enhance_command(self):
+        """Build enhance360.py command"""
+        return (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"')
+                
+    def _build_mbdnet_command(self):
+        """Build scene_completion.py command"""
+        shifted_disparity = os.path.join(self.input_dir, 'shifted_disparity.png')
+        shifted_t = os.path.join(self.input_dir, 'shifted_t.png')
+        
+        command = (f'python scene_completion.py {shifted_disparity} {shifted_t} ')
+        
+        # Log final command
+        self.update_status(f"Final command: {command}")
+        
+        return command
+                
+    def on_mbdnet_complete(self, success, error_message):
+        """Handle MBDNet completion"""
+        self.is_processing = False
+        self.progress_bar.setMaximum(100)
+        
+        if success:
+            print("MBDNet process completed successfully")
+            update_status_indicator(self.MBDNet_status, "Complete")
+            try:
+                os.rename(os.path.join(self.input_dir, 'shifted_t.png'), os.path.join(self.input_dir, 'rgb.png'))
+                os.rename(os.path.join(self.input_dir, 'shifted_disparity.png'), os.path.join(self.input_dir, 'depth_e.png'))
+                os.rename(os.path.join(self.output_dir, 'scene_completed_prediction.mtl'), os.path.join(self.output_dir, 'Input_prediction_mesh.mtl'))
+                os.rename(os.path.join(self.output_dir, 'scene_completed_prediction.obj'), os.path.join(self.output_dir, 'Input_prediction_mesh.obj'))
+            except Exception as e:
+                print(f"Error renaming files: {str(e)}")
+                self.update_status(f"Error renaming files: {str(e)}")
+                self.update_status("Please make sure you are connected to the University Network/Gloabl Protect")
+
+            self.update_depth_preview()
+        else:
+            print("MBDNet process failed")
+            update_status_indicator(self.MBDNet_status, "Failed")
+            QMessageBox.critical(self, "Error", f"MBDNet failed: {error_message}")
+            
+    def update_depth_preview(self):
+        """Update depth preview image"""
+        depth_path = os.path.join(self.input_dir, "shifted_disparity.png")
+        update_preview(self.depth_preview, depth_path, 300)
+
+    def run_mesh_split(self):
+        if self.is_processing:
+            QMessageBox.warning(self, "Warning", "A process is already running!")
+            return
+            
+        self.is_processing = True
+        self.progress_bar.setMaximum(0)
+        
+        self.current_thread = ProcessThread(self._run_mesh_split_process)
+        self.current_thread.finished.connect(self.on_mesh_split_complete)
+        self.current_thread.progress.connect(self.update_status)
+        self.current_thread.start()
+
+    def _run_mesh_split_process(self):
+        """Execute mesh splitting process"""
+        # Change to EdgeNet directory
+        os.chdir(self.edge_net_dir)
+        try:
+            if not os.path.exists(os.path.join(self.output_dir, "Input_prediction_mesh.obj")):
+                raise Exception("Missing Input_prediction_mesh.obj file")
+            print("Running mesh split")   
+            cmd = (f'call "{self.config_reader.config["condaDir"]}\\Scripts\\activate.bat" '
+                  f'{self.config_reader.config["materialEnv"]} && '
+                  f'python replace.py')
+            print("Command: ", cmd)    
+            return run_command(self, cmd, self.update_status)[0]
+            
+        except Exception as e:
+            self.update_status(f"Error: {str(e)}")
+            return False
+
+    def on_mesh_split_complete(self, success, error_message):
+        """Handle mesh split completion"""
+        self.is_processing = False
+        self.progress_bar.setMaximum(100)
+        
+        if success:
+            update_status_indicator(self.split_status, "Complete")
+            self.update_mesh_preview()
+        else:
+            update_status_indicator(self.split_status, "Failed")
+            QMessageBox.critical(self, "Error", f"Mesh splitting failed: {error_message}")
+
+    def run_blender_flip(self):
+        if self.is_processing:
+            QMessageBox.warning(self, "Warning", "A process is already running!")
+            return
+            
+        self.is_processing = True
+        self.progress_bar.setMaximum(0)
+        
+        self.current_thread = ProcessThread(self._run_blender_flip_process)
+        self.current_thread.finished.connect(self.on_blender_flip_complete)
+        self.current_thread.progress.connect(self.update_status)
+        self.current_thread.start()
+
+    def _run_blender_flip_process(self):
+        """Execute Blender flip process"""
+        # Change to scripts directory
+        os.chdir(self.config_reader.directories['scriptDir'])
+        try:
+            mesh_path = os.path.join(self.output_dir, "Input_prediction_mesh.obj")
+            if not os.path.exists(mesh_path):
+                raise Exception("Missing Input_prediction_mesh.obj file")
+                
+            cmd = (f'call "{self.config_reader.config["condaDir"]}\\Scripts\\activate.bat" '
+                  f'{self.config_reader.config["unityEnv"]} && '
+                  f'python blenderFlip.py "{mesh_path}"')
+                  
+            return run_command(self, cmd, self.update_status)[0]
+            
+        except Exception as e:
+            self.update_status(f"Error: {str(e)}")
+            return False
+
+    def on_blender_flip_complete(self, success, error_message):
+        """Handle Blender flip completion"""
+        self.is_processing = False
+        self.progress_bar.setMaximum(100)
+        
+        if success:
+            update_status_indicator(self.flip_status, "Complete")
+            self.update_mesh_preview()
+        else:
+            update_status_indicator(self.flip_status, "Failed")
+            QMessageBox.critical(self, "Error", f"Blender flip failed: {error_message}")
+
+    def run_all_steps(self):
+        if self.is_processing:
+            QMessageBox.warning(self, "Warning", "A process is already running!")
+            return
+
+        self.is_processing = True
+        self.progress_bar.setMaximum(0)  # Set to indeterminate mode
+
+        self.current_thread = ProcessThread(self._run_all_steps_process)
+        self.current_thread.finished.connect(self.on_all_steps_complete)
+        self.current_thread.progress.connect(self.update_status)
+        self.current_thread.start()
+
+    def _run_all_steps_process(self):
+        """Execute complete pipeline process"""
+        try:
+            self.update_status("Starting complete pipeline processing...")
+            
+            # Run EdgeNet
+            self.update_status("Running EdgeNet...")
+            update_status_indicator(self.MBDNet_status, "Running")
+            if not self._run_mbdnet_process():
+                raise Exception("EdgeNet processing failed")
+                
+            # Run Mesh Split
+            self.update_status("Running Mesh Split...")
+            update_status_indicator(self.split_status, "Running")
+            if not self._run_mesh_split_process():
+                raise Exception("Mesh splitting failed")
+                
+            # Run Blender Flip
+            self.update_status("Running Blender Flip...")
+            update_status_indicator(self.flip_status, "Running")
+            if not self._run_blender_flip_process():
+                raise Exception("Blender flip failed")
+                
+            return True
+            
+        except Exception as e:
+            self.update_status(f"Pipeline error: {str(e)}")
+            return False
+
+    def on_all_steps_complete(self, success, error_message):
+        """Handle complete pipeline completion"""
+        self.is_processing = False
+        self.progress_bar.setMaximum(100)
+        self.progress_bar.setValue(0)
+
+        if success:
+            self.update_status("Complete pipeline processing finished successfully!")
+            update_status_indicator(self.MBDNet_status, "Complete")
+            update_status_indicator(self.split_status, "Complete") 
+            update_status_indicator(self.flip_status, "Complete")
+            QMessageBox.information(self, "Success", 
+                                  "All processing steps completed successfully!")
+        else:
+            self.update_status(f"Pipeline failed: {error_message}")
+            QMessageBox.critical(self, "Error", f"Pipeline failed: {error_message}")
+
+    def update_mesh_preview(self):
+        """Update mesh preview image"""
+        # Implement mesh preview rendering
+        # This could involve taking a screenshot of the mesh
+        # or loading a pre-rendered preview image
+        pass
+
+    def copy_input_files(self):
+        """Copy manual input files to input directory"""
+        os.makedirs(self.input_dir, exist_ok=True)
+        
+        for file_type, path in self.manual_inputs.items():
+            if path:
+                dest = os.path.join(self.input_dir, file_type)
+                copy_file(path, dest, self.update_status)
diff --git a/scripts/debug_tool/tabs/shifter_tab.py b/scripts/debug_tool/tabs/shifter_tab.py
index d532b5d8784654212562dd14723ce6a0724ab98e..7add01bacc19e53f996f0eb1c9b7eee4194ef7c0 100644
--- a/scripts/debug_tool/tabs/shifter_tab.py
+++ b/scripts/debug_tool/tabs/shifter_tab.py
@@ -104,18 +104,38 @@ class ShifterTab(QWidget):
         scrollbar.setValue(scrollbar.maximum())
 
     def run_shifter(self):
+        """GUI version of shifter - calls the thread-safe version"""
         if not self.input_file_path:
             QMessageBox.warning(self, "Warning", "Please select an input file first")
-            return
+            return False
         
         self.update_status("\nRunning image shifter...")
-        success, _ = run_command(
-            self, 
-            self.cmd_text.toPlainText(),
-            self.update_status
-        )
+        success, _ = self.run_shifter_process(self.update_status)
         
         if success and os.path.exists(self.shifted_image_path):
             self.update_status(f"Shifted image saved to: {self.shifted_image_path}")
             update_preview(self.output_preview, self.shifted_image_path, 
-                         error_callback=self.update_status)
\ No newline at end of file
+                         error_callback=self.update_status)
+        return success
+    
+    def run_shifter_process(self, status_callback=None):
+        """Thread-safe version of shifter that doesn't use GUI components"""
+        try:
+            if not self.input_file_path:
+                raise ValueError("No input file selected")
+
+            # Construct command without using GUI components
+            conda_dir = self.config_reader.config["condaDir"]
+            material_env = self.config_reader.config["materialEnv"]
+            shifter_script = os.path.join(self.config_reader.directories['scriptDir'], "shifter.py")
+            
+            command = f'"{conda_dir}\\condabin\\activate.bat" {material_env} && ' \
+                     f'python "{shifter_script}" "{self.input_file_path}" "{self.shifted_image_path}"'
+            
+            # Run the command
+            return run_command(None, command, status_callback)
+            
+        except Exception as e:
+            if status_callback:
+                status_callback(f"Error in shifter process: {str(e)}")
+            return False, str(e)
\ No newline at end of file
diff --git a/scripts/scene_completion.py b/scripts/scene_completion.py
index fdb3fcc0b99b87e3d7cf5ca9f6ef062b89e1c075..6baef21f331197d3d88ea8cebfb0e564d8e4e9ff 100644
--- a/scripts/scene_completion.py
+++ b/scripts/scene_completion.py
@@ -4,11 +4,15 @@ from scp import SCPClient
 import os
 import subprocess
 import time
+import sys
 
 load_dotenv()
 hostname = os.getenv("HOSTNAME")
-username = os.getenv("USERNAME")
+#username = os.getenv("USERNAME")
 password = os.getenv("PASSWORD")
+# hostname = "soton.ac.uk"
+username = "kproject"
+# password = "i7-13700H"
 
 def send_files(shifted_disparity_path, shifted_t_path):
     # sends two files needed to iridis
@@ -110,7 +114,15 @@ def get_completed_scene(shifted_disparity_path, shifted_t_path):
             print(output)
 
         remote_file_path = "/mainfs/ECShome/kproject/mona/MDBNet360_GDP/output/scene_completed_prediction.obj"
-        local_file_path = "edgenet-360/Data/Input/scene_completed_prediction.obj"  
+        current_dir = os.getcwd()
+        parent_dir = os.path.dirname(current_dir)
+        local_file_folder = os.path.join(parent_dir, "edgenet-360/Output")
+        local_file_path = os.path.join(local_file_folder,"scene_completed_prediction.obj")  
+        with SCPClient(client.get_transport()) as scp:
+            scp.get(remote_file_path, local_file_path)  # Download file
+
+        remote_file_path = "/mainfs/ECShome/kproject/mona/MDBNet360_GDP/output/scene_completed_prediction.mtl"
+        local_file_path = os.path.join(local_file_folder,"scene_completed_prediction.mtl") 
         with SCPClient(client.get_transport()) as scp:
             scp.get(remote_file_path, local_file_path)  # Download file
 
@@ -128,11 +140,11 @@ def get_completed_scene(shifted_disparity_path, shifted_t_path):
 
 if __name__ == "__main__":
     if len(sys.argv) != 3:
-        print("Usage: python shifter.py <shifted_disparity_path> <shifted_t_path>")
+        print("Usage: python scene_completion.py <shifted_disparity_path> <shifted_t_path>")
         sys.exit(1)
 
     shifted_disparity_path = sys.argv[1]
     shifted_t_path = sys.argv[2]
 
-    saved_path = get_completed_scene(shifted_disparity_path, shifted_t_path)
+    saved_path = get_completed_scene(shifted_disparity_path, shifted_t_path)[1]
     print(f"Shifted image saved as {saved_path}")
\ No newline at end of file
diff --git a/scripts/simple_tab.py b/scripts/simple_tab.py
index 0f383dfc7c88657a2a4ecfda208c382c1a3c1a98..867c06ab3385c05cd959f7f19be0288d913229b2 100644
--- a/scripts/simple_tab.py
+++ b/scripts/simple_tab.py
@@ -45,22 +45,46 @@ class PipelineWorker(QThread):
         self.progress.emit("Cleaning EdgeNet output directory...")
     
     def copy_file(self):
-        self.progress.emit("Copying input file to scripts/360monodepthexecution...")
+        # Determine which file to use as input
+        self.tab.depth.depth_input_path = self.tab.shifter.shifted_image_path if self.tab.should_shift_image else self.tab.input_path
+        
+        if self.tab.should_shift_image:
+            self.progress.emit("Copying shifted image to scripts/360monodepthexecution...")
+        else:
+            self.progress.emit("Copying input file to scripts/360monodepthexecution...")
+            
         self.tab.depth.copy_file()
         
     def shift_image(self):
         print("Starting shift_image")  # Debug print
-        if not self.tab.shift_image_check.isChecked():
+        if not self.tab.should_shift_image:
             self.progress.emit("Skipping image shift...")
             return
-        self.progress.emit("Shifting input image...")
-        self.tab.shifter.run_shifter()
-        print("Completed shift_image")  # Debug print
+            
+        try:
+            self.progress.emit("Shifting input image...")
+            # Set input path for shifter
+            self.tab.shifter.input_file_path = self.tab.input_path
+            # Use the thread-safe version
+            success, output = self.tab.shifter.run_shifter_process(self.progress.emit)
+            
+            if not success:
+                raise RuntimeError(f"Image shifting failed: {output}")
+            
+            print("Completed shift_image")
+            
+            # Change material recognition input file path to shifted image
+            self.tab.material.input_file_path = self.tab.shifter.shifted_image_path
+            
+            return self.tab.shifter.shifted_image_path
+        except Exception as e:
+            print(f"Shift image failed: {str(e)}")
+            raise
         
     def run_depth_estimation(self):
         print("Starting depth_estimation")  # Debug print
         self.progress.emit("Running depth estimation...")
-        self.tab.depth.run_depth_estimation()
+        self.tab.depth.run_depth_estimation(False)
         print("Completed depth_estimation")  # Debug print
         
     def run_material_recognition(self):
@@ -107,7 +131,7 @@ class PipelineWorker(QThread):
         self.progress.emit("Running EdgeNet enhance360.py and infer360.py...")
 
         try:
-            self.tab.edge_net.include_top = self.tab.include_top_check.isChecked()
+            self.tab.edge_net.include_top = self.tab.should_include_top  # Use cached state
             self.tab.edge_net._run_edge_net_process()
             print("Completed edge_net")
         except Exception as e:
@@ -121,11 +145,12 @@ class PipelineWorker(QThread):
         self.tab.edge_net._run_blender_flip_process()
         self.progress.emit("Completed blender flip (blenderFlip.py)") 
         self.progress.emit("Post-processing completed!")
+        self.progress.emit("File saved in edgenet-360\Output")
     
     def run_pipeline(self):
         self.clean_temp_files()
-        self.copy_file()
         self.shift_image()
+        self.copy_file()
         self.run_depth_estimation()
         self.run_material_recognition()
         self.run_edge_net()
@@ -138,6 +163,10 @@ class SimpleTab(QWidget):
         self.config_reader = config_reader
         self.input_path = None
         self.pipeline_thread = None
+    
+        # Store states that will be used by worker thread
+        self.should_shift_image = False
+        self.should_include_top = False
         
         # Initialize module instances
         self.shifter = ShifterTab(self.config_reader)
@@ -342,7 +371,7 @@ class SimpleTab(QWidget):
         
         layout.addWidget(controls_group)
 
-        # Image Distance section
+        ## Image Distance section
         self.image_distance_group = QGroupBox("Image Distance")
         distance_layout = QVBoxLayout(self.image_distance_group)
         info_label = QLabel("Please select two point on the image and input the distance from the camera to that point.")
@@ -353,24 +382,24 @@ class SimpleTab(QWidget):
         self.points_info_label = QLabel()  # Label to display points and distances
         self.points_info_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignCenter)
         self.image_distance_group.setStyleSheet("""
-            QGroupBox {
-                font-weight: bold;
-                border: 2px solid grey;
-                border-radius: 20px;
-                margin-top: 10px;
-                background-color: #3e3e3e;
-                padding: 20px;
-            }
-            QGroupBox::title { 
-                margin: 10px;
-                background-color: transparent;
-                color: white;
-            }
-            QLabel {
-                margin: 5px;
-                background-color: #3e3e3e;
-                color: white;
-            }
+           QGroupBox {
+               font-weight: bold;
+               border: 2px solid grey;
+               border-radius: 20px;
+               margin-top: 10px;
+               background-color: #3e3e3e;
+               padding: 20px;
+           }
+           QGroupBox::title { 
+               margin: 10px;
+               background-color: transparent;
+               color: white;
+           }
+           QLabel {
+               margin: 5px;
+               background-color: #3e3e3e;
+               color: white;
+           }
         """)
         # Center the ClickableLabel within its parent layout
         distance_preview_layout = QHBoxLayout()
@@ -382,11 +411,11 @@ class SimpleTab(QWidget):
         self.distance_reset_btn.clicked.connect(self.distance_preview.clear_points)
         self.distance_reset_btn.setFixedSize(150, 40)
         self.distance_reset_btn.setStyleSheet("""
-            QPushButton {
-                margin: 5px;
-                padding: 5px;
-                border-radius: 10px;
-            }
+           QPushButton {
+               margin: 5px;
+               padding: 5px;
+               border-radius: 10px;
+           }
         """)
         distance_btn_layout = QHBoxLayout()
         distance_btn_layout.addStretch()
@@ -526,7 +555,7 @@ class SimpleTab(QWidget):
             self.update_status("Waiting for distance points...")
             self.info_labels["Status:"].setText("Waiting for distance points...")
             # Enable the run pipeline button
-            #self.run_pipeline_btn.setEnabled(True)
+            self.run_pipeline_btn.setEnabled(True)
             
             # Provide input path to all modules
             self.shifter.input_file_path = file_path
@@ -574,6 +603,10 @@ class SimpleTab(QWidget):
         if self.pipeline_thread and self.pipeline_thread.isRunning():
             QMessageBox.warning(self, "Warning", "Pipeline is already running")
             return
+        
+        # Cache checkbox states before starting thread
+        self.should_shift_image = self.shift_image_check.isChecked()
+        self.should_include_top = self.include_top_check.isChecked()
             
         # Show progress bar and update status
         self.progress_bar.show()
@@ -586,7 +619,8 @@ class SimpleTab(QWidget):
         self.pipeline_thread.finished.connect(self.pipeline_completed)
         
         # Disable controls while running
-        self.setEnabled(False)
+        #self.setEnabled(False)
+        self.disable_buttons_while_running()
         self.progress_bar.setEnabled(True)  # Keep progress bar enabled
         
         #TODO: Add model selection for EdgeNet or MDBNet
@@ -616,4 +650,13 @@ class SimpleTab(QWidget):
         self.info_labels["Status:"].setText(message.split("...")[-1] if "..." in message else message)
         # Scroll to bottom
         scrollbar = self.status_text.verticalScrollBar()
-        scrollbar.setValue(scrollbar.maximum())
\ No newline at end of file
+        scrollbar.setValue(scrollbar.maximum())
+
+    def disable_buttons_while_running(self):
+        self.select_btn.setEnabled(False)
+        self.run_pipeline_btn.setEnabled(False)
+        self.include_top_check.setEnabled(False)
+        self.shift_image_check.setEnabled(False)
+        self.ssc_model_combo.setEnabled(False)
+        self.distance_reset_btn.setEnabled(False)
+        self.distance_preview.setEnabled(False)
\ No newline at end of file