Spaces:
Sleeping
Sleeping
import scipy.io | |
import numpy as np | |
import cv2 | |
import glob | |
import matplotlib.pyplot as plt | |
import vtk | |
def run_space_carving(): | |
data = scipy.io.loadmat("uploads_spacecarving/data/dino_Ps.mat")["P"] | |
projections = [data[0, i] for i in range(data.shape[1])] | |
# === Load and preprocess images === | |
files = sorted(glob.glob("uploads_spacecarving/data/*.ppm")) | |
images = [] | |
for f in files: | |
im = cv2.imread(f, cv2.IMREAD_UNCHANGED).astype(float) | |
im /= 255 | |
images.append(im[:, :, ::-1]) # BGR to RGB | |
# === Create silhouettes === | |
imgH, imgW, _ = images[0].shape | |
silhouettes = [] | |
for im in images: | |
mask = np.abs(im - [0.0, 0.0, 0.75]) | |
mask = np.sum(mask, axis=2) | |
y, x = np.where(mask <= 1.1) | |
im[y, x, :] = [0.0, 0.0, 0.0] | |
im = im[:, :, 0] | |
im[im > 0] = 1.0 | |
im = im.astype(np.uint8) | |
kernel = np.ones((5, 5), np.uint8) | |
im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel) | |
silhouettes.append(im) | |
# === Create voxel grid === | |
s = 120 | |
x, y, z = np.mgrid[:s, :s, :s] | |
pts = np.vstack((x.flatten(), y.flatten(), z.flatten())).astype(float).T | |
nb_points_init = pts.shape[0] | |
# Normalize and center | |
pts[:, 0] /= np.max(pts[:, 0]) | |
pts[:, 1] /= np.max(pts[:, 1]) | |
pts[:, 2] /= np.max(pts[:, 2]) | |
center = np.mean(pts, axis=0) | |
pts -= center | |
pts /= 5 | |
pts[:, 2] -= 0.62 | |
# Homogeneous coordinates | |
pts_hom = np.vstack((pts.T, np.ones((1, nb_points_init)))) | |
# === Voxel carving: count silhouettes where voxel is occupied === | |
filled = [] | |
for P, sil in zip(projections, silhouettes): | |
uvs = P @ pts_hom | |
uvs /= uvs[2, :] | |
uvs = np.round(uvs).astype(int) | |
x_valid = np.logical_and(uvs[0, :] >= 0, uvs[0, :] < imgW) | |
y_valid = np.logical_and(uvs[1, :] >= 0, uvs[1, :] < imgH) | |
valid = np.logical_and(x_valid, y_valid) | |
indices = np.where(valid)[0] | |
fill = np.zeros(uvs.shape[1]) | |
sub_uvs = uvs[:2, indices] | |
res = sil[sub_uvs[1, :], sub_uvs[0, :]] | |
fill[indices] = res | |
filled.append(fill) | |
filled = np.vstack(filled) | |
occupancy = np.sum(filled, axis=0) | |
# === Save voxel grid as .vtr (only the voxels with occupancy > threshold) === | |
threshold = 25 | |
occupancy_mask = (occupancy > threshold).astype(np.float32) | |
# Create grid coordinates | |
x_coords = sorted(list(set(np.round(pts[:, 0][::s*s], 6)))) | |
y_coords = sorted(list(set(np.round(pts[:, 1][:s*s:s], 6)))) | |
z_coords = sorted(list(set(np.round(pts[:, 2][:s], 6)))) | |
x_array = vtk.vtkFloatArray() | |
y_array = vtk.vtkFloatArray() | |
z_array = vtk.vtkFloatArray() | |
for val in x_coords: | |
x_array.InsertNextValue(val) | |
for val in y_coords: | |
y_array.InsertNextValue(val) | |
for val in z_coords: | |
z_array.InsertNextValue(val) | |
# Only add occupancy values for retained voxels | |
values = vtk.vtkFloatArray() | |
values.SetName("Occupancy") | |
for i in range(len(occupancy_mask)): | |
values.InsertNextValue(occupancy_mask[i]) | |
# Create rectilinear grid | |
rgrid = vtk.vtkRectilinearGrid() | |
rgrid.SetDimensions(len(x_coords), len(y_coords), len(z_coords)) | |
rgrid.SetXCoordinates(x_array) | |
rgrid.SetYCoordinates(y_array) | |
rgrid.SetZCoordinates(z_array) | |
rgrid.GetPointData().SetScalars(values) | |
# Save to .vtr | |
writer = vtk.vtkXMLRectilinearGridWriter() | |
writer.SetFileName("res_space/shape.vtr") | |
writer.SetInputData(rgrid) | |
writer.Write() | |