python-FRED / utils /camera.py
CMalone-Jupiter's picture
Upload folder using huggingface_hub
4490536 verified
import os
import numpy as np
import cv2
from PIL import Image
import open3d as o3d
from utils.utils import read_calib_file #, fill_projected_os1_rings
color_key = {
0: [0, 0, 128], # road
1: [0, 128, 0], # water
2: [0, 0, 0] # other
}
class ImageData():
def __init__(self, file_path, calib_path, label_path=None):
self.image = cv2.imread(file_path)
intrinsics = read_calib_file(calib_path)
focal_len = intrinsics['focal_len'][0]
principal_x = intrinsics['principal_x'][0]
principal_y = intrinsics['principal_y'][0]
pp_mm_x = intrinsics['pp_mm_x'][0]
pp_mm_y = intrinsics['pp_mm_y'][0]
# print(f"{focal_len}, {principal_x}, {principal_y}, {pp_mm_x}, {pp_mm_y}")
self.camera_matrix = self.create_camera_matrix(focal_len, principal_x, principal_y, pp_mm_x, pp_mm_y)
self.dist_coeffs = np.array([0.0, 0.0, 0.0, 0.0, 0.0])
self.semantic_classes = None
self.colour_label = None
self.semantic_classes = {'road': [0, 0, 128], 'water': [0, 128, 0], 'other': [0, 0, 0]} # In the opencv BGR convention
if label_path is not None:
if os.path.exists(label_path):
label_img = cv2.imread(label_path)
else:
# Catch for no label existing #
print(f"Could not load label \'{label_path}\'. Using blank labels.")
label_img = np.zeros(self.image.shape).astype(np.uint8)
self.colour_label = cv2.resize(label_img, (self.image.shape[1], self.image.shape[0]), interpolation=cv2.INTER_NEAREST)
H, W, _ = label_img.shape
self.label_img = np.full((H, W), 2, dtype=np.uint8) # unknown = 255
# Convert to uint8 in case it's float
img = label_img.astype(np.uint8)
for class_idx, color in color_key.items():
# Create mask where all 3 channels match
mask = np.all(img == color, axis=2)
self.label_img[mask] = class_idx
self.label_img = cv2.resize(self.label_img, (self.image.shape[1], self.image.shape[0]), interpolation=cv2.INTER_NEAREST)
def create_camera_matrix(self, focal_length_mm, principal_point_x_pixels, principal_point_y_pixels,
pixels_per_mm_x, pixels_per_mm_y):
"""
Create camera matrix from physical camera parameters.
Args:
focal_length_mm: Focal length in millimeters
principal_point_x_pixels: Principal point X coordinate in pixels
principal_point_y_pixels: Principal point Y coordinate in pixels
pixels_per_mm_x: Pixels per millimeter in X direction
pixels_per_mm_y: Pixels per millimeter in Y direction
Returns:
camera_matrix: 3x3 camera intrinsic matrix
"""
# Check for None or invalid values
if any(x is None for x in [focal_length_mm, principal_point_x_pixels, principal_point_y_pixels,
pixels_per_mm_x, pixels_per_mm_y]):
print("ERROR: One or more input parameters is None!")
return None
if pixels_per_mm_x == 0 or pixels_per_mm_y == 0:
print("ERROR: pixels_per_mm cannot be zero!")
return None
try:
# Convert focal length from mm to pixels
fx = focal_length_mm * pixels_per_mm_x
fy = focal_length_mm * pixels_per_mm_y
# Principal point is already in pixels
cx = principal_point_x_pixels
cy = principal_point_y_pixels
camera_matrix = np.array([
[fx, 0, cx],
[0, fy, cy],
[0, 0, 1]
], dtype=np.float64)
return camera_matrix
except Exception as e:
print(f"ERROR in create_camera_matrix: {e}")
return None
def project_points(self, points, colours, cmap, valid_cam, colour_norm=None, semantic_label=False):
# , beam_id, azimuth
# Project to image coordinates
rvec = np.zeros(3) # No additional rotation
tvec = np.zeros(3) # No additional translation
image_points, _ = cv2.projectPoints(points, rvec, tvec, self.camera_matrix, self.dist_coeffs)
image_points = image_points.reshape(-1, 2)
# Filter points within image bounds
h, w = self.image.shape[0], self.image.shape[1]
valid_img_mask = ((image_points[:, 0] >= 0) & (image_points[:, 0] < w) &
(image_points[:, 1] >= 0) & (image_points[:, 1] < h))
valid_mask = valid_img_mask & valid_cam
points2project = image_points[valid_mask]
if colour_norm is None:
colour2project = colours[valid_mask]/colours[valid_img_mask].max()
else:
colour2project = colours[valid_mask]/colour_norm
if semantic_label:
# Build meta_points: x, y, z, intensity, u, v, semantic_label
valid_3d = points[valid_mask] # (N, 3) xyz in camera frame
valid_intensity = colours[valid_mask] # (N,) intensity
valid_uv = points2project # (N, 2) pixel coords
valid_labels = np.array([
self.label_img[int(pt[1]), int(pt[0])]
for pt in valid_uv
])
meta_points = np.column_stack([
valid_3d, # x, y, z
valid_intensity, # intensity
valid_uv, # u, v
valid_labels # semantic label
])
img_vis = self.image.copy()
mask_img = np.zeros((self.image.shape[0], self.image.shape[1]))
# Draw points
for (point, c) in zip(points2project.astype(int), colour2project):
r, g, b, _ = cmap(c)
colour = (r*255, g*255, b*255)
cv2.circle(img_vis, (int(point[0]), int(point[1])), 5, colour, -1) # -1 = filled circle
cv2.circle(mask_img, (int(point[0]), int(point[1])), 10, 255, -1)
if semantic_label:
return img_vis, image_points, valid_mask, mask_img, meta_points
else:
return img_vis, image_points, valid_mask, mask_img
def get_image_coords(self, points):
# Project to image coordinates
rvec = np.zeros(3) # No additional rotation
tvec = np.zeros(3) # No additional translation
image_points, _ = cv2.projectPoints(points, rvec, tvec, self.camera_matrix, self.dist_coeffs)
image_points = image_points.reshape(-1, 2)
return image_points