Files
chri002-ComfyUI_depthMapOpe…/test.ipynb
T
2025-03-20 16:46:32 +01:00

39 KiB

In [ ]:
!nvidia-smi
In [ ]:

#@title Load library
TORCH_ENABLED = True
SCIPY_ENABLED = True

from transformers import pipeline
import requests
import numpy as np
from PIL import Image
from math import cos, sin
import math as m
import os
import cv2
import pandas as pd
import gc
try:
  from scipy.spatial import cKDTree
except:
  SCIPY_ENABLED = False
try:
  import torch
except:
  TORCH_ENABLED = False
In [ ]:

#@title Define functions

def clean():
  for I in range(0,20):
    gc.collect()
    torch.cuda.empty_cache()

def export_PLY(points, name_file="model.ply", multiple_files=False, format_ascii="ascii"):

    # Write PLY header
    header = [
        "ply",
        f"format {(format_ascii)} 1.0",
        f"element vertex {(points.shape[0])}",
        "property float x",
        "property float y",
        "property float z",
        "property uchar red",
        "property uchar green",
        "property uchar blue",
        "end_header\n"
    ]

    if not(name_file.endswith(".ply")):
        name_file+=".ply"

    if "ascii" in format_ascii:
        header_cons = "\n".join(header)
        if not(multiple_files):
            with open(name_file, 'wb') as f:
                np.savetxt(f, points, fmt='%g %g %g %d %d %d', header=header_cons, comments='')
            with open(name_file, 'rb+') as fout:
                fout.seek(-1, os.SEEK_END)
                fout.truncate()
        else:
            def split_array(arr, n):
                return [arr[i:i+n] for i in range(0, len(arr), n)]
            for idx,points_ck in enumerate(split_array(points, 2097152)):
                header = [
                    "ply",
                    f"format {(format_ascii)} 1.0",
                    f"element vertex {(points_ck.shape[0])}",
                    "property float x",
                    "property float y",
                    "property float z",
                    "property uchar red",
                    "property uchar green",
                    "property uchar blue",
                    "end_header\n"
                ]
                name_file_t = name_file.split(".ply")[0]+"_"+str(idx)+".ply"
                with open(name_file_t, 'wb') as f:
                    np.savetxt(f, points_ck, fmt='%g %g %g %d %d %d', header=header_cons, comments='')
                with open(name_file_t, 'rb+') as fout:
                    fout.seek(-1, os.SEEK_END)
                    fout.truncate()

    else:
        xyz = points[:, :3].astype(np.float32)
        rgb = points[:, 3:6].astype(np.uint8)



        if (multiple_files):
            def split_array(arr, n):
                return [arr[i:i+n] for i in range(0, len(arr), n)]
            xyz = split_array(xyz, 2097152)
            rgb = split_array(rgb, 2097152)
        else:
            xyz =[xyz]
            rgb =[rgb]

        for idx,xyz_ in enumerate(xyz):
            header = [
                "ply",
                f"format {(format_ascii)} 1.0",
                f"element vertex {(xyz_.shape[0])}",
                "property float x",
                "property float y",
                "property float z",
                "property uchar red",
                "property uchar green",
                "property uchar blue",
                "end_header"
            ]
            structured_array = np.zeros(xyz_.shape[0], dtype=[
                ('x', '<f4'),  # Little-endian float32
                ('y', '<f4'),
                ('z', '<f4'),
                ('red', 'u1'),  # Unsigned byte (0-255)
                ('green', 'u1'),
                ('blue', 'u1')
            ])
            rgb_ = rgb[idx]
            name_file_t = (name_file.split(".ply")[0]+"_"+str(idx)+".ply" if multiple_files else name_file)
            structured_array['x'] = xyz_[:, 0]
            structured_array['y'] = xyz_[:, 1]
            structured_array['z'] = xyz_[:, 2]
            structured_array['red'] = rgb_[:, 0]
            structured_array['green'] = rgb_[:, 1]
            structured_array['blue'] = rgb_[:, 2]
            with open(name_file_t, 'wb') as f:
                f.write('\n'.join(header).encode('utf-8'))
                f.write(b'\n')  # Header ends with a newline
                structured_array.tofile(f)

def from2Dto3D_vectorized(arrayDepth, arrayPixel, maxZ, quality=1):
    # Check if the input shapes are compatible
    assert arrayPixel.shape[:2] == arrayDepth.shape, "Pixel and Depth map shapes do not match"
    W, H = arrayDepth.shape  # Original dimensions

    if quality > 1:
        # Calculate new dimensions based on quality
        new_W = (W - 1) * quality + 1
        new_H = (H - 1) * quality + 1

        # Generate new coordinates using linspace
        new_X = np.linspace(0, W-1, new_W)
        new_Y = np.linspace(0, H-1, new_H)

        # Create meshgrid for new coordinates
        xi, yi = np.meshgrid(new_X, new_Y, indexing='ij')  # shapes (new_W, new_H)

        # Prepare indices for interpolation
        x0 = np.floor(xi).astype(int)
        x1 = np.clip(x0 + 1, 0, W-1)
        y0 = np.floor(yi).astype(int)
        y1 = np.clip(y0 + 1, 0, H-1)

        dx = xi - x0
        dy = yi - y0

        # Interpolate arrayDepth
        tl = arrayDepth[x0, y0]
        tr = arrayDepth[x0, y1]
        bl = arrayDepth[x1, y0]
        br = arrayDepth[x1, y1]
        interpolated_depth = (
            (1 - dx) * (1 - dy) * tl +
            dx * (1 - dy) * tr +
            (1 - dx) * dy * bl +
            dx * dy * br
        )

        # Interpolate arrayPixel for each channel
        interpolated_pixel = np.zeros((new_W, new_H, 3), dtype=arrayPixel.dtype)
        for c in range(3):
            tl_c = arrayPixel[x0, y0, c]
            tr_c = arrayPixel[x0, y1, c]
            bl_c = arrayPixel[x1, y0, c]
            br_c = arrayPixel[x1, y1, c]
            interpolated_c = (
                (1 - dx) * (1 - dy) * tl_c +
                dx * (1 - dy) * tr_c +
                (1 - dx) * dy * bl_c +
                dx * dy * br_c
            )
            interpolated_pixel[:, :, c] = interpolated_c.astype(arrayPixel.dtype)

        # Update variables to use interpolated arrays
        W, H = new_W, new_H
        arrayDepth = interpolated_depth
        arrayPixel = interpolated_pixel
        # Use new_X and new_Y for coordinates
        final_X, final_Y = np.meshgrid(new_X, new_Y, indexing='ij')
    else:
        # Original coordinates
        x = np.arange(W)
        y = np.arange(H)
        final_X, final_Y = np.meshgrid(x, y, indexing='ij')  # shapes (W, H)

    # Calculate scaled Z values
    d_min = np.min(arrayDepth)
    d_max = np.max(arrayDepth)
    if d_max - d_min > 1e-9:
        Z = -(arrayDepth - d_min) / (d_max - d_min) * maxZ
    else:
        Z = np.zeros_like(arrayDepth, dtype=np.float64)

    # Extract RGB components
    R = arrayPixel[:, :, 0]
    G = arrayPixel[:, :, 1]
    B = arrayPixel[:, :, 2]

    # Stack all components and reshape to Nx6
    # Transpose to shape (H, W) for correct ordering when using 'ij' indexing
    points = np.stack([
        final_Y.T, final_X.T, Z.T,
        R.T, G.T, B.T
    ], axis=-1)
    points = points.reshape(-1, 6)

    return points


def from2Dto3D_vectorized_torch(arrayDepth, arrayPixel, maxZ, quality=1):
    # Ensure inputs are PyTorch tensors
    assert isinstance(arrayDepth, torch.Tensor), "arrayDepth must be a torch.Tensor"
    assert isinstance(arrayPixel, torch.Tensor), "arrayPixel must be a torch.Tensor"

    # Check shape compatibility

    assert arrayPixel.shape[:2] == arrayDepth.shape, "Pixel and Depth map shapes do not match"
    W, H = arrayDepth.shape  # Original dimensions

    if quality > 1:
        # Calculate new dimensions
        new_W = (W - 1) * quality + 1
        new_H = (H - 1) * quality + 1

        # Generate coordinates (CHANGED: torch.linspace instead of np.linspace)
        new_X = torch.linspace(0, W-1, new_W, device=arrayDepth.device)
        new_Y = torch.linspace(0, H-1, new_H, device=arrayDepth.device)

        # Create meshgrid (CHANGED: torch.meshgrid with indexing='ij')
        xi, yi = torch.meshgrid(new_X, new_Y, indexing='ij')

        # Prepare indices (CHANGED: torch.floor/int/clamp)
        x0 = torch.floor(xi).long()
        x1 = torch.clamp(x0 + 1, 0, W-1)
        y0 = torch.floor(yi).long()
        y1 = torch.clamp(y0 + 1, 0, H-1)

        dx = xi - x0
        dy = yi - y0

        # Interpolate depth (CHANGED: Tensor indexing)
        tl = arrayDepth[x0, y0]
        tr = arrayDepth[x0, y1]
        bl = arrayDepth[x1, y0]
        br = arrayDepth[x1, y1]
        interpolated_depth = (
            (1 - dx) * (1 - dy) * tl +
            dx * (1 - dy) * tr +
            (1 - dx) * dy * bl +
            dx * dy * br
        )

        # Interpolate pixel (CHANGED: Tensor operations preserve dtype)
        interpolated_pixel = torch.zeros((new_W, new_H, 3),
                                      dtype=arrayPixel.dtype,
                                      device=arrayPixel.device)
        for c in range(3):
            tl_c = arrayPixel[x0, y0, c]
            tr_c = arrayPixel[x0, y1, c]
            bl_c = arrayPixel[x1, y0, c]
            br_c = arrayPixel[x1, y1, c]
            interpolated_c = (
                (1 - dx) * (1 - dy) * tl_c +
                dx * (1 - dy) * tr_c +
                (1 - dx) * dy * bl_c +
                dx * dy * br_c
            )
            interpolated_pixel[:, :, c] = interpolated_c.to(arrayPixel.dtype)

        W, H = new_W, new_H
        arrayDepth = interpolated_depth
        arrayPixel = interpolated_pixel
        final_X, final_Y = xi, yi
    else:
        # Original coordinates (CHANGED: torch.arange)
        x = torch.arange(W, device=arrayDepth.device)
        y = torch.arange(H, device=arrayDepth.device)
        final_X, final_Y = torch.meshgrid(x, y, indexing='ij')

    # Calculate Z (CHANGED: Tensor operations)
    d_min = torch.min(arrayDepth)
    d_max = torch.max(arrayDepth)
    if (d_max - d_min).item() > 1e-9:  # CHANGED: .item() for scalar comparison
        Z = -(arrayDepth - d_min) / (d_max - d_min) * maxZ
    else:
        Z = torch.zeros_like(arrayDepth)

    # Extract RGB (CHANGED: Tensor slicing)
    R = arrayPixel[:, :, 0]
    G = arrayPixel[:, :, 1]
    B = arrayPixel[:, :, 2]

    # Stack components (CHANGED: permute instead of transpose)
    points = torch.stack([
        final_Y.permute(1, 0),  # Equivalent to .T in NumPy
        final_X.permute(1, 0),
        Z.permute(1, 0),
        R.permute(1, 0),
        G.permute(1, 0),
        B.permute(1, 0)
    ], dim=-1)

    return points.view(-1, 6)  # CHANGED: view instead of reshape

def transform_points(points, translate=(0, 0, 0), rotate=(0, 0, 0), scale=(1,1,1)):
    """Apply 3D transformations to points (rotation first, then translation)"""
    # Convert rotation angles to radians if needed (modify if using degrees)
    rx, ry, rz = rotate


    # Create rotation matrices
    # X-axis rotation
    rot_x = np.array([
        [1, 0, 0],
        [0, cos(rx), -sin(rx)],
        [0, sin(rx), cos(rx)]
    ], dtype=np.float64)

    # Y-axis rotation
    rot_y = np.array([
        [cos(ry), 0, sin(ry)],
        [0, 1, 0],
        [-sin(ry), 0, cos(ry)]
    ], dtype=np.float64)

    # Z-axis rotation
    rot_z = np.array([
        [cos(rz), -sin(rz), 0],
        [sin(rz), cos(rz), 0],
        [0, 0, 1]
    ], dtype=np.float64)


    # Combined rotation matrix (Z-Y-X order)
    rotation_matrix = rot_z @ rot_y @ rot_x

    points[:,0:3] = points[:,0:3].astype(np.float64)

    points[:,0:3] = (points[:,0:3] * np.array(scale, dtype=np.float64)).astype(np.float64)

    # Apply rotation
    points[:,0:3] = (points[:,0:3] @ rotation_matrix.T).astype(np.float64)

    # Apply translation
    points[:,0:3] = (points[:,0:3] + np.array(translate, dtype=np.float64)).astype(np.float64)

    return points

def project_points(points, fov=60, rotation=None, translation=None, scale=None, aspect_ratio=1, img_size=(1000,1000)):
    """Fast 3D->2D projection with perspective correction"""
    if rotation is None:
        rotation = np.zeros(3)
    if translation is None:
        translation = np.zeros(3)
    if scale is None:
        scale = np.ones(3)

    # Calcolo parametri camera
    fov_rad = m.radians(fov)
    focal_length = img_size[1] / (2 * m.tan(fov_rad / 2))  # Focal length verticale

    # Trasformazioni (camera guarda lungo -Z)

    points = transform_points(points, translate=translation, rotate=rotation, scale=scale)

    # Seleziona punti DAVANTI alla camera (z < 0)
    valid = points[:, 2] < 0
    points_t = points #[valid]

    if len(points_t) == 0:
        return np.empty((0, 2)), np.array([]), np.empty((0, 3))

    # Calcolo coordinate proiettate
    z = -points_t[:, 2]  # Converti in distanza positiva
    x_proj = (points_t[:, 0] * focal_length) / (z * aspect_ratio)
    y_proj = (points_t[:, 1] * focal_length) / z

    # Conversione a coordinate immagine (Y non invertito)
    pixel_x = (x_proj + img_size[0]/2).astype(int)
    pixel_y = (y_proj + img_size[1]/2).astype(int)  # Rimosso il segno negativo

    # Clip e normalizzazione
    pixel_x = np.clip(pixel_x, 0, img_size[0]-1)
    pixel_y = np.clip(pixel_y, 0, img_size[1]-1)
    z_norm = (z - z.min()) / (z.max() - z.min())

    return np.column_stack([pixel_x, pixel_y]), z_norm, points_t[:, 3:6]

def project_points_ortho(points, rotation=None, translation=None, scale=None):
    """Orthographic 3D->2D projection"""
    if rotation is None:
        rotation = np.zeros(3)
    if translation is None:
        translation = np.zeros(3)
    if scale is None:
        scale = np.ones(3)


    # Apply transformations
    points = transform_points(points, translate=translation, rotate=rotation, scale=scale)

    # Orthographic projection
    x_proj = points[:, 0]  # Simple scaling + centering offset
    y_proj = points[:, 1]

    # Normalize depth (similar to perspective version)
    z = points[:, 2]
    z_min = z.min()
    z_max = z.max()
    z_range = z_max - z_min + 1e-5  # Avoid division by zero
    z_norm = (z - z_min) / z_range

    colors = points[:,3:6]

    return np.column_stack([x_proj, y_proj]), z_norm, colors

def render_points_fast(points, rotation=None, translation=None, scale=None,
                      img_size=(1000, 1000), color=False, cameraType=0, fov=60, correction=False, ksize=(2,2), thresh=2):
    """Ultra-fast rendering using pure NumPy and PIL"""
    # Project points to 2D
    if cameraType==0:
        proj, depth, colors = project_points_ortho(points, rotation=rotation, translation=translation)
    else:
        proj, depth, colors = project_points(points, fov=fov, aspect_ratio=img_size[1]/img_size[1], rotation=rotation, translation=translation, scale=scale, img_size=img_size)

    if isinstance(proj, torch.Tensor):
      proj=proj.detach().cpu().numpy()
      depth=depth.detach().cpu().numpy()
      colors=colors.detach().cpu().numpy()

    # Convert to integer coordinates and filter valid points
    proj = proj.astype(np.int32)
    valid = (proj[:, 0] >= 0) & (proj[:, 0] < img_size[0]) & \
            (proj[:, 1] >= 0) & (proj[:, 1] < img_size[1])

    proj = proj[valid]
    depth = depth[valid]
    colors = colors[valid]

    # Grayscale rendering based on depth
    max_depth = depth.max() if depth.size > 0 else 1
    min_depth = depth.min() if depth.size > 0 else 0
    if max_depth - min_depth > 0:
        depth_normalized = (depth - min_depth) / (max_depth - min_depth)
    else:
        depth_normalized = np.zeros_like(depth)
    intensities = (255 - (depth_normalized * 255)).astype(np.uint16)

    # Sort points by descending intensity to prioritize closer points
    sorted_indices = np.argsort(-intensities)
    proj_sorted = proj[sorted_indices]
    y_coords = proj_sorted[:, 1]
    x_coords = proj_sorted[:, 0]

    df = pd.DataFrame({'y': y_coords, 'x': x_coords})
    unique_indices = df.drop_duplicates().index.to_numpy()

    # Extract unique coordinates and colors
    unique_y = y_coords[unique_indices]
    unique_x = x_coords[unique_indices]

    if color:
        # Extract colors from valid points (assuming points are Nx[x,y,z,r,g,b])
        point_colors = colors.astype(np.uint16)
        colors_sorted = point_colors[sorted_indices]

        unique_colors = colors_sorted[unique_indices]

        # Create color buffer and assign colors
        color_buffer = np.ones((img_size[1], img_size[0], 3))
        color_buffer = color_buffer*-1
        color_buffer[unique_y, unique_x] = unique_colors

        img = color_buffer
    else:
        point_colors = intensities
        colors_sorted = point_colors[sorted_indices]

        unique_colors = colors_sorted[unique_indices]

        # Create color buffer and assign colors
        color_buffer = np.ones((img_size[1], img_size[0]))
        color_buffer = color_buffer*-1
        color_buffer[unique_y, unique_x] = unique_colors

        img = color_buffer


    if correction:
        point_colors = intensities
        colors_sorted = point_colors[sorted_indices]

        unique_colors = colors_sorted[unique_indices]

        # Create color buffer and assign colors
        depth_buffer = np.zeros((img_size[1], img_size[0]))
        depth_buffer[unique_y, unique_x] = unique_colors

        img_depth = depth_buffer

        img = np.array(img)
        img_dep = np.array(img_depth)

        img_blur = blur_image_excluding_black(img, ksize, thresh)
        #print(np.unique(img_blur))
        mask = img_dep < thresh

        (img[mask]) = (img_blur[mask])

        img = img

    return img

def clean_points(points, k, m):
    points = np.asarray(points)
    if points.size == 0:
        return points.copy()
    if k <= 0:
        raise ValueError("k must be a positive integer")
    n = len(points)
    if k > n - 1:
        return np.empty((0, points.shape[1]))
    tree = cKDTree(points, balanced_tree=False)
    # Query k+1 to include the point itself, then select the k-th neighbor
    distances, _ = tree.query(points, k=k+1, workers=-1)
    kth_distances = distances[:, k]  # k-th neighbor after excluding self
    mask = kth_distances <= m
    return points[mask]

def interpolate_points(points, alpha=0.5, n_c=3):
    """
    Interpolate three new points for each original point, positioned between the original and its three nearest neighbors.

    Parameters:
    points (numpy.ndarray): Input array of shape (N, 6) where each row is (x, y, z, r, g, b).
    alpha (float): Interpolation factor (0.0 = original point, 1.0 = neighbor). Default is 0.5 (midpoint).

    Returns:
    numpy.ndarray: Array of interpolated points with shape (3*N, 6).
    """
    # Extract coordinates and colors
    coords = points[:, :3]
    colors = points[:, 3:]
    N = coords.shape[0]

    # Build KDTree for efficient neighbor lookup
    tree = cKDTree(coords, balanced_tree=False)

    # Query for 4 nearest neighbors (including self), then exclude self
    _, indices = tree.query(coords, k=n_c+1, workers=-1)
    neighbor_indices = indices[:, 1:(n_c+1)]  # Shape (N, 3)

    # Prepare indices for vectorized operations
    original_indices = np.repeat(np.arange(N), n_c)
    neighbors_flat = neighbor_indices.ravel()

    # Gather original and neighbor data
    original_coords = coords[original_indices]
    neighbor_coords = coords[neighbors_flat]

    original_colors = colors[original_indices]
    neighbor_colors = colors[neighbors_flat]

    # Interpolate coordinates and colors
    interpolated_coords = (1 - alpha) * original_coords + alpha * neighbor_coords
    interpolated_colors = (1 - alpha) * original_colors + alpha * neighbor_colors

    # Combine into new points array
    new_points = np.hstack((interpolated_coords, interpolated_colors))

    combined_points = np.vstack((points, new_points))

    return combined_points

def convolve2d_np(image, kernel, mode='same'):
    # Flip the kernel for convolution
    kernel = np.flipud(np.fliplr(kernel))
    k_h, k_w = kernel.shape
    i_h, i_w = image.shape

    # Determine padding
    if mode == 'same':
        pad_top = (k_h - 1) // 2
        pad_bottom = (k_h - 1) - pad_top
        pad_left = (k_w - 1) // 2
        pad_right = (k_w - 1) - pad_left
        padded_image = np.pad(image, ((pad_top, pad_bottom), (pad_left, pad_right)), mode='constant')
    elif mode == 'valid':
        padded_image = image
    elif mode == 'full':
        padded_image = np.pad(image, ((k_h-1, k_h-1), (k_w-1, k_w-1)), mode='constant')
    else:
        raise ValueError("Mode must be 'same', 'valid', or 'full'")

    # Generate sliding windows
    windows = np.lib.stride_tricks.sliding_window_view(padded_image, (k_h, k_w))

    # Perform convolution by summing element-wise multiplication
    result = np.sum(windows * kernel.reshape(1, 1, k_h, k_w), axis=(-2, -1))

    return result

def blur_image_excluding_black(image, kernel_size=(4,4), threshold=2):
    # Create mask for non-black pixels (all channels zero)
    if image.ndim == 3:
        mask = np.any(image > threshold, axis=-1).astype(float)
    else:
        mask = (image > threshold).astype(float)

    kernel = np.ones(kernel_size)

    if image.ndim == 3:
        blurred = np.ones_like(image)*-1
        for c in range(image.shape[2]):
            channel = image[:, :, c]
            masked_channel = channel * mask
            sum_matrix = convolve2d_np(masked_channel, kernel, mode='same')
            count_matrix = convolve2d_np(mask, kernel, mode='same')
            with np.errstate(divide='ignore', invalid='ignore'):
                mean_matrix = sum_matrix / count_matrix
                # Where count is zero, use original pixel if non-black, else 0
                blurred_channel = np.where(count_matrix > 1, mean_matrix, -1)
            blurred[:, :, c] = blurred_channel
    else:
        masked_image = image * mask
        sum_matrix = convolve2d_np(masked_image, kernel, mode='same')
        count_matrix = convolve2d_np(mask, kernel, mode='same')
        with np.errstate(divide='ignore', invalid='ignore'):
            mean_matrix = sum_matrix / count_matrix
            blurred = np.where(count_matrix > 0, mean_matrix, masked_image)

    return blurred
In [ ]:

from google.colab import files
import ipywidgets as widgets
from IPython.display import display
import PIL
from PIL import Image, ImageDraw, ImageFilter

#@title #Load image from upload file




loadImage = False
mask = Image.new('RGBA', (512, 512),  (255, 255, 255))
initt = None
url = None


display("Load Image:")
Up = files.upload()
for k, v in Up.items():
    initt=Image.open(k)


print(initt.size)
In [ ]:
#@title Generate depth map
test =True #@param {"type":"boolean"}
# load pipe
pipe = pipeline(task="depth-estimation", model="depth-anything/Depth-Anything-V2-Large-hf")

# load image
if test:
 url = 'https://raw.githubusercontent.com/chri002/ComfyUI_depthMapOperation/refs/heads/main/assets/start.jpg'
 image = Image.open(requests.get(url, stream=True).raw)
 image = image.resize((int(image.size[0]), int(image.size[1])))
 print(image.size)
else:
 image=initt.convert("RGB")
# inference
depth_img = pipe(image)["depth"]
In [ ]:
#@title Generate Cloud Points
depth =512#@param {"type" : "number"}

quality=2 #@param {"type" : "integer"}
img = torch.from_numpy((np.array(image)))
depth_map = torch.from_numpy(np.array(depth_img))
points = (from2Dto3D_vectorized_torch(depth_map, img, depth, quality)).cpu().numpy()
In [ ]:
#@title Clean Cloud Points

k = 20#@param {"type" : "integer"}
distance = 16#@param {"type" : "number"}

points = transform_points(points, translate=(0, 0, 0), rotate=(0, 0, 0), scale=(1,1,2))
points = (clean_points(points, k=k, m=distance))
points = transform_points(points, translate=(0, 0, 0), rotate=(0, 0, 0), scale=(1,1,0.5))
In [ ]:
#@title Local Rotation
rx=0#@param {"type" : "number"}
ry=0#@param {"type" : "number"}
rz=0#@param {"type" : "number"}

mx, Mx, my, My, mz, Mz = points[:,0].min(), points[:,0].max(), points[:,1].min(), points[:,1].max(), points[:,2].min(), points[:,2].max()
tx = -(Mx+mx)/2
ty = -(My+my)/2
tz = -(Mz+mz)/2

points = transform_points(points, translate=(tx, ty, tz), rotate=(0, 0, 0), scale=(1,1,1))
points = transform_points(points, translate=(0, 0, 0), rotate=(rx/180*m.pi, ry/180*m.pi, rz/180*m.pi), scale=(1,1,1))
points = transform_points(points, translate=(-tx, -ty, -tz), rotate=(0, 0, 0), scale=(1,1,1))
In [ ]:
#@title Translation
tx=0#@param {"type" : "number"}
ty=0#@param {"type" : "number"}
tz=0#@param {"type" : "number"}

points = transform_points(points, translate=(tx, ty, tz), rotate=(0, 0, 0), scale=(1,1,1))
In [ ]:
#@title Scale
sx=1#@param {"type" : "number"}
sy=1#@param {"type" : "number"}
sz=1#@param {"type" : "number"}

points = transform_points(points, translate=(0,0,0), rotate=(0, 0, 0), scale=(sx,sy,sz))
In [ ]:
#@title Points interpolation
interpolate = 3 #@param {"type":"number"}
points =  (interpolate_points(points, alpha=0.5, n_c=interpolate))
In [ ]:
#@title Generate image
import datetime
start = datetime.datetime.now()

tend = 0



width,height = image.size
translation = np.array([-width/2,-height/2,0])
scale = np.array([1,1,-1])
fov=45 #@param {"type" : "number"}
correction = True #@param{"type":"boolean"}
k_size =2 #@param{"type" : "number"}
points_cop = transform_points(points.copy(), translate=translation, scale=scale)
translation = np.array([0,0, -(height/m.sin(m.radians(fov)))])
points_cop = transform_points(points_cop, translate=translation)


end_img = (render_points_fast(points_cop, img_size=(width,height), color=True, cameraType=1, fov=fov, correction=correction, ksize=(k_size,k_size), thresh=3))

background = 125*np.ones((int(image.size[0]/20),int(image.size[1]/20),3))
background[1::2, ::2,:]=255
background[::2, 1::2,:]=255
background= cv2.resize(background, image.size, interpolation = cv2.INTER_NEAREST)

mask = end_img[:,:,0]==-1
end_img[mask] = background[mask]
mask = end_img[:,:,1]==-1
end_img[mask] = background[mask]
mask = end_img[:,:,2]==-1
end_img[mask] = background[mask]

tend=datetime.datetime.now()

delta=tend-start

print("vertices: ",points.shape[0],"\ntime: ",delta)

img_end = Image.fromarray(end_img.astype(np.uint8))

images = [image, img_end]
widths, heights = zip(*(i.size for i in images))

total_width = sum(widths)
max_height = max(heights)

new_im = Image.new('RGB', (total_width, max_height))

x_offset = 0
for im in images:
  new_im.paste(im, (x_offset,0))
  x_offset += im.size[0]

display(new_im)
In [ ]:
#@title Show Image
img_end
In [ ]:
#@title Export PLY
export_PLY(points.detach().cpu().numpy(), name_file="model.ply", multiple_files=False, format_ascii="binary_little_endian")
In [ ]:
#@title Clean memory
clean()