Skip to content
Snippets Groups Projects
Commit 35fd82cd authored by mhz1g21's avatar mhz1g21
Browse files

Merge branch 'GDP_4.5.1-ImplementDisparity' into 'master'

Gdp 4.5.1 implement disparity

See merge request !19
parents fab33b04 9b0facef
No related branches found
No related tags found
1 merge request!19Gdp 4.5.1 implement disparity
# 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
# 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
import os
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("TkAgg") # Use TkAgg for GUI rendering
import warnings
warnings.filterwarnings( "ignore")
class Depth2Disparity:
def __init__(self, baseline=0.176, disp_scale=2.0, disp_offset=-120):
"""
Initialize the Depth2Disparity class with correct parameters.
Parameters:
baseline (float): Baseline distance between the stereo cameras (in meters).
disp_scale (float): Scaling factor for disparity values.
disp_offset (float): Offset added to the disparity values.
"""
self.baseline = baseline
self.disp_scale = disp_scale
self.disp_offset = disp_offset
def execute(self, rel_depth_path, coord1, dist1, coord2, dist2):
# Load the relative depth map
print(f"Loading relative depth map from: {rel_depth_path}")
rel_depth_map = cv2.imread(rel_depth_path, cv2.IMREAD_GRAYSCALE) # Load as grayscale
if rel_depth_map is None:
raise FileNotFoundError(f"Unable to load file: {rel_depth_path}")
# Convert relative to absolute depth
print("Converting relative to absolute ...")
abs_depth_map = self._relative2abs(rel_depth_map, coord1, dist1, coord2, dist2)
# Normalize depth map for saving
abs_depth_map_normalized = (abs_depth_map - abs_depth_map.min()) / (abs_depth_map.max() - abs_depth_map.min())
abs_depth_map_normalized *= 255
abs_depth_map_normalized = abs_depth_map_normalized.astype(np.uint8)
# store absolute dpet map for debugging
abs_depth_path = os.path.join(os.path.dirname(rel_depth_path), "abs_depth.png")
cv2.imwrite(abs_depth_path, abs_depth_map_normalized)
print(f"Absolute depth map saved to: {abs_depth_path}\n")
# Convert depth map to disparity map
print("Converting abs depth to disparity ...")
disparity_map, disparity_map_normalized = self._depth2disparity(abs_depth_map)
# Determine the output path for the disparity map
disparity_dir = os.path.dirname(rel_depth_path)
disparity_base = "disp_map.png"#"depth_e.png"
disparity_path = os.path.join(disparity_dir, disparity_base)
## Check if an existing disparity map needs to be renamed
if os.path.exists(disparity_path):
old_depth_path = os.path.join(disparity_dir, "depth_e_old.png")
print(f"Renaming monodepth map to: {old_depth_path}")
# if pre-existing 'old depth map' exists, remove it
if os.path.exists(old_depth_path):
os.remove(old_depth_path)
os.rename(disparity_path, old_depth_path)
# Save the new disparity map
print(f"Saving new disparity map to: {disparity_path}")
cv2.imwrite(disparity_path, disparity_map_normalized)
# Debug message for GUI or logs
print("Complete")
# add typing to this method defintion
def _relative2abs(self, rel_depth_map, coord1: tuple, dist1: float, coord2: tuple, dist2: float):
# Normalize depth map
print("Normalizing depth map...")
#rel_depth_map = rel_depth_map.astype(np.float32) / 255.0
rel_depth_map = (rel_depth_map - rel_depth_map.min()) / (rel_depth_map.max() - rel_depth_map.min())
#plt.imshow(rel_depth_map, cmap='gray')
#plt.colorbar()
#plt.show()
# Get the relative depth values at the two points
rel_value1 = float(rel_depth_map[coord1[1], coord1[0]]) # (y, x)
rel_value2 = float(rel_depth_map[coord2[1], coord2[0]])
print(f"rel1: {rel_value1}, rel2: {rel_value2}, dist1: {dist1}, dist2: {dist2}")
# Calculate the linear transformation: depth = a * rel_depth + b
a = (dist2 - dist1) / (rel_value2 - rel_value1)
print("Calculated a: ", a)
b = dist1 - a * rel_value1
print("Calculated b: ", b)
#print("\tApplying transformation to entire depth map")
# Apply the transformation to the entire relative depth map
abs_depth_map = a * rel_depth_map + b
print("Applied transformation to entire depth map")
#abs_depth_map = np.maximum(abs_depth_map, 0.01)
plt.imshow(abs_depth_map, cmap='gray')
plt.colorbar()
plt.show()
# this should not be normalised, the values in the array should equate to literal distances
return abs_depth_map
def _depth2disparity(self, abs_depth_map):
height, width = abs_depth_map.shape
unit_h = 1.0 / height
disparity_map = np.zeros_like(abs_depth_map, dtype=np.float32)
for i in range(height):
theta_t = i * unit_h * np.pi
for j in range(width):
r_t = max(abs_depth_map[i, j], 0.01) # Clamp small depths
if r_t <= 0:
disparity_map[i, j] = 0
continue
try:
tan_theta_t = np.tan(theta_t) if np.abs(np.cos(theta_t)) > 1e-6 else np.sign(np.sin(theta_t)) * np.inf
denominator = max(r_t * np.sin(theta_t) + r_t * np.cos(theta_t) * tan_theta_t, 1e-6)
angle_disp = np.arctan(self.baseline / denominator) - theta_t
pixel_disp = (angle_disp / (unit_h * np.pi) - self.disp_offset) * self.disp_scale
disparity_map[i, j] = pixel_disp
except ZeroDivisionError:
disparity_map[i, j] = 0
# Normalize for visualization
disparity_map_normalized = (disparity_map - disparity_map.min()) / (disparity_map.max() - disparity_map.min())
disparity_map_normalized *= 255
disparity_map_normalized = disparity_map_normalized.astype(np.uint8)
plt.imshow(disparity_map, cmap='gray')
plt.colorbar()
plt.show()
return disparity_map, disparity_map_normalized
#def __depth2disparity(self, abs_depth_map):
# """
# Convert absolute depth map to disparity map for 360-degree images.
# Parameters:
# abs_depth_map (numpy.ndarray): Absolute depth map with pixel values as distances in meters.
# Returns:
# disparity_map (numpy.ndarray): Disparity map with values representing disparity.
# disparity_map_normalized (numpy.ndarray): Normalized disparity map for visualization.
# """
# # Define parameters for the conversion
# height, width = abs_depth_map.shape
#
# # Latitude grid (θ_l)
# epsilon = 1e-6
# latitudes = np.linspace(-np.pi / 2, np.pi / 2, height)
# latitudes_grid = np.tile(latitudes[:, np.newaxis], (1, width))
# # Clamp extreme latitudes to avoid instability
# latitudes_grid = np.clip(latitudes_grid, -np.pi/2 + epsilon, np.pi/2 - epsilon)
# plt.imshow(latitudes_grid, cmap="jet")
# plt.colorbar()
# plt.title("Latitude Grid")
# plt.show()
# self.baseline = 0.176
#
#
# # Calculate angular disparity Δθ(x, y)
# # Δθ(x, y) = arctan(B / (r_t * sin(θ_l) + r_t * cos(θ_l) * tan(θ_l))) - θ_l
# epsilon = 1e-6 # Small value to prevent instability
# denominator = (
# abs_depth_map * np.sin(latitudes_grid) +
# abs_depth_map * np.cos(latitudes_grid) * np.tan(latitudes_grid) +
# epsilon
# )
# angular_disparity = np.arctan(self.baseline / denominator) - latitudes_grid
#
# self.disp_scale = 10
# self.disp_offset = np.median(angular_disparity)
#
# # Normalize the disparity map for saving
# pixel_angle_scale = 1 # Assume scale factor is 1 if not provided (can be adjusted if needed)
# disparity_map = (angular_disparity / pixel_angle_scale - self.disp_offset) * self.disp_scale
# # Normalize for visualization
# disparity_map_normalized = (disparity_map - disparity_map.min()) / (disparity_map.max() - disparity_map.min())
# disparity_map_normalized *= 255
# disparity_map_normalized = disparity_map_normalized.astype(np.uint8)
# # Debugging visualization
# plt.imshow(disparity_map, cmap="jet")
# plt.colorbar()
# plt.title("Disparity Map (Debugging)")
# plt.show()
# return disparity_map, disparity_map_normalized
\ No newline at end of file
......@@ -49,7 +49,7 @@ def load_and_resize_image(image_path, max_size=800):
new_size = (int(width * ratio), int(height * ratio))
img = cv2.resize(img, new_size, interpolation=cv2.INTER_AREA)
return img
return img, ratio
except Exception as e:
raise Exception(f"Error loading image: {str(e)}")
......@@ -65,7 +65,7 @@ def update_preview(preview_label, image_path, max_size=300, error_callback=None)
"""
if image_path and os.path.exists(image_path):
try:
img = load_and_resize_image(image_path, max_size)
img, ratio = load_and_resize_image(image_path, max_size)
pixmap = convert_cv_to_pixmap(img)
preview_label.setPixmap(pixmap)
except Exception as e:
......
......@@ -19,17 +19,22 @@ from debug_tool.tabs.material_tab import MaterialTab
from debug_tool.tabs.edge_net_tab import EdgeNetTab
from debug_tool.tabs.mbdnet_tab import MBDNetTab
from Depth2Disparity.depth_to_disparity import Depth2Disparity
class PipelineWorker(QThread):
progress = pyqtSignal(str)
finished = pyqtSignal(bool, str)
def __init__(self, tab_instance, edgenet_flag=True,input_depth_flag=False, depth_map_path=None):
super().__init__()
self.tab = tab_instance
self.tab = tab_instance
self.distance_points = self.tab.distance_points # added distance points to class for disparity calculation
self.ratio = self.tab.ratio # image scale ratio for reversal
self.edgenet_flag = edgenet_flag
self.input_depth_flag = input_depth_flag
self.depth_file_path = depth_map_path
def run(self):
try:
self.run_pipeline()
......@@ -100,6 +105,26 @@ class PipelineWorker(QThread):
self.progress.emit("Running depth estimation...")
self.tab.depth.run_depth_estimation(False)
print("Completed depth_estimation") # Debug print
def run_depth_to_disparity(self):
print("\nStarting depth2disparity")
self.progress.emit("Converting mono-depthmap to disparity map...")
# execute function to convert depth to disparity
real_depth_path = self.tab.depth.depth_output_path # depthmap path
coord1 = int(self.distance_points[0][0] / self.ratio), int(self.distance_points[0][1] / self.ratio) # x,y coordinates of point 1
dist1 = float(self.distance_points[0][2]) # distance from camera to point 1
coord2 = int(self.distance_points[1][0] / self.ratio), int(self.distance_points[1][1] / self.ratio) # x,y coordinates of point 2
dist2 = float(self.distance_points[1][2]) # distance from camera to point 2
print(f"{coord1}, {dist1}, {coord2}, {dist2}. Ratio: {self.ratio}")
convert_d2d = Depth2Disparity()
print("Executing...")
convert_d2d.execute(real_depth_path, coord1, dist1, coord2, dist2)
#print("Saved disparity map to output directory: " + real_depth_path)
self.progress.emit("Completed Disparity Map Conversion")
def run_material_recognition(self):
print("Starting material_recognition")
......@@ -179,6 +204,7 @@ class PipelineWorker(QThread):
self.copy_depth_map()
else:
self.run_depth_estimation()
#self.run_depth_to_disparity()
self.run_material_recognition()
if self.edgenet_flag:
self.run_edge_net()
......@@ -186,7 +212,7 @@ class PipelineWorker(QThread):
else:
self.run_mbdnet()
self.progress.emit("Pipeline completed!")
9
class SimpleTab(QWidget):
def __init__(self, config_reader):
super().__init__()
......@@ -584,7 +610,7 @@ class SimpleTab(QWidget):
update_preview(self.input_preview, file_path,
error_callback=self.update_status)
update_preview(self.distance_preview,file_path,max_size=1500)
pixmap = load_and_resize_image(file_path, 1500)
pixmap, self.ratio = load_and_resize_image(file_path, 1500)
pixmap = convert_cv_to_pixmap(pixmap)
self.distance_preview.setFixedSize(pixmap.size())
self.image_distance_group.show()
......@@ -662,6 +688,9 @@ class SimpleTab(QWidget):
self.progress_bar.show()
self.run_pipeline_btn.setEnabled(False)
# Get the distance points
self.distance_points = self.distance_preview.get_points()
self.pipeline_thread = PipelineWorker(
self,
edgenet_flag=self.ssc_model_combo.currentText() == "EdgeNet360",
......@@ -680,10 +709,6 @@ class SimpleTab(QWidget):
#TODO: Add model selection for EdgeNet or MDBNet
# Set the SSC model
self.selected_model = self.ssc_model_combo.currentText()
#TODO: Add distance points to the pipeline for depth estimation
# Get the distance points
self.distance_points = self.distance_preview.get_points()
# Start the pipeline
self.pipeline_thread.start()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment