2DPcloudreg / codes.py
Amould's picture
Update codes.py
69d1aad verified
import os, sys
import numpy as np
import random
import time
import json
import matplotlib.pyplot as plt
import tqdm
import torch
def generate_standard_elips(N_samples = 10, a= 1,b = 1):
radius = 0.5
center = 0
N_samples1 = int(N_samples/2 - 1)
N_samples2 = N_samples - N_samples1
x1 = np.random.uniform((center-radius)*a,(center+radius)*a, size = N_samples1)
x1_ordered = np.sort(x1)
y1 = center + b*np.sqrt(radius**2 - ((x1_ordered-center)/a)**2)
x2 = np.random.uniform((center-radius)*a,(center+radius)*a, size = N_samples - N_samples1)
x2_ordered = -np.sort(-x2) #the minus sign to sort descindingly
y2 = center - b*np.sqrt(radius**2 - ((x2_ordered-center)/a)**2)
x = np.concatenate([x1_ordered, x2_ordered], axis=0)
y = np.concatenate([y1, y2], axis=0)
return x, y
def destandarize_point(d, dim=128):
return dim*(d + 0.5)
def To_pointcloud(x,y,z=0):
N_points = x.shape[0]
point_cloud = np.zeros([N_points,3])
point_cloud[:,0] = x
point_cloud[:,1] = y
if not z==0:
point_cloud[:,2] = z
return point_cloud
def To_xyz(point_cloud):
x = point_cloud[:,0]
y = point_cloud[:,1]
z = point_cloud[:,2]
return x,y,z
def random_rigid_transformation(dim=2):
#dim = 4
rotation_x = 0
rotation_y = 0
rotation_z = random.uniform(0, 2)*np.pi
translation_x = random.uniform(-1, 1)*dim
translation_y = random.uniform(-1, 1)*dim
translation_z = 0
reflection_x = random.sample([-1,1],1)[0]
reflection_y = random.sample([-1,1],1)[0]
reflection_z = 1
Rotx = np.array([[1,0,0],
[0,np.cos(rotation_x),-np.sin(rotation_x)],
[0,np.sin(rotation_x),np.cos(rotation_x)]])
Roty = np.array([[np.cos(rotation_y),0,np.sin(rotation_y)],
[0,1,0],
[-np.sin(rotation_y),0,np.cos(rotation_y)]])
Rotz = np.array([[np.cos(rotation_z),-np.sin(rotation_z),0],
[np.sin(rotation_z),np.cos(rotation_z),0],
[0,0,1]])
Rotation = np.matmul(Rotz, np.matmul(Roty,Rotx))
Reflection = np.array([[reflection_x,0,0],[0,reflection_y,0],[0,0,reflection_z]])
Translation = np.array([translation_x,translation_y,translation_z])
RefRotation = np.matmul(Reflection,Rotation)
return RefRotation, Translation
def rigid_2Dtransformation(prdction):
#prediction = [rotationz, reflectionx, reflectiony, translationx, translationy]
N_examples = prdction['rotation'].shape[0]
Translation = prdction['translation']
Reflection = torch.zeros([N_examples,3,3])#
Reflection[:,0,0] = prdction['reflection'][:,0]
Reflection[:,1,1] = prdction['reflection'][:,1]
Reflection[:,2,2] = 1.
rotation_z = prdction['rotation'][:,2]
Rotation = torch.zeros([N_examples,3,3])#np.repeat(np.eye(3)[None,:,:],N_examples, axis=0))
Rotation[:,0,0] = torch.cos(rotation_z)
Rotation[:,1,1] = torch.cos(rotation_z)
Rotation[:,0,1] = -torch.sin(rotation_z)
Rotation[:,2,2] = 1.
Rotation[:,1,0] = torch.sin(rotation_z)
RefRotation = torch.matmul(Reflection,Rotation)
return RefRotation, Translation
def batch_hausdorff_prcnt_distance(batch_point_cloud1, point_cloud2, percentile = 0.95):
assert point_cloud2.shape[0]==3
assert batch_point_cloud1.shape[1]==3
distances = torch.norm(batch_point_cloud1[:, :, None,:] - point_cloud2[None, :, :,None], dim=1)
dists1 = torch.min(distances, dim=1).values
dists2 = torch.min(distances, dim=2).values
# Calculate the 95th percentile distance
percentile_95 = torch.quantile(torch.cat([dists1, dists2],axis=1), percentile, interpolation='linear', dim=1)
return percentile_95
def HDloss(prd, pointcloud_source_norm_torch,pointcloud_target_norm_torch, percentile = 0.95):
A, b = rigid_2Dtransformation(prd)
point_cloud_wrapped = torch.matmul(A, pointcloud_source_norm_torch.T) + b[:,:,None]
loss = batch_hausdorff_prcnt_distance(point_cloud_wrapped, pointcloud_target_norm_torch.T, percentile)
return loss
def Mean_HDloss(prd, pointcloud_source_norm_torch, pointcloud_target_norm_torch, percentile = 0.95):
loss = HDloss(prd, pointcloud_source_norm_torch, pointcloud_target_norm_torch, percentile = 0.95)
return torch.mean(loss)
def wrap_pointcloud(record, pointcloud_source):
#normalize first
PC1_mean = np.mean(pointcloud_source, axis=0)
pointcloud_source_norm = pointcloud_source - PC1_mean
pointcloud_source_norm_torch = torch.tensor(pointcloud_source_norm, requires_grad=False).to(torch.float32)
# find Tx
A, b = rigid_2Dtransformation(record)
point_cloud_wrapped = torch.matmul(A, pointcloud_source_norm_torch.T) + b[:,:,None]
return point_cloud_wrapped
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
def move_dict2device(dictionary,device):
for key in list(dictionary.keys()):
dictionary[key] = dictionary[key].to(device)
return dictionary
eps = 0.000001948
class Optimization_model(torch.nn.Module):
def __init__(self):
super(Optimization_model, self).__init__()
self.alpha = torch.nn.Parameter(torch.tensor(0.5, requires_grad=True))
self.rotation = torch.nn.Parameter(torch.tensor([0.0, 0.0, 0.0], requires_grad=True))
self.translation = torch.nn.Parameter(torch.tensor([0.01,-0.01, 0.0], requires_grad=True))
self.reflection = torch.nn.Parameter(torch.sign(torch.tensor([0.01,-0.01, 1], requires_grad=True)))
#self.rigid = torch.nn.Parameter(torch.tensor([0.0,1.0,1.0,0.1,0.1], requires_grad=True))
def forward(self, input_X_batch):
predicted_rotation = self.alpha*self.rotation + (1-self.alpha)*input_X_batch['rotation']
predicted_translation = self.alpha*self.translation + (1-self.alpha)*input_X_batch['translation']
predicted_reflection = torch.sign(self.alpha*self.reflection +
(1-self.alpha)*input_X_batch['reflection']+eps)
return {'rotation':predicted_rotation,
'translation':predicted_translation,
'reflection':predicted_reflection}
class Dataset(torch.utils.data.Dataset):
def __init__(self, dataset_size, N_dim = 2):
self.dataset_size = dataset_size
self.N_dim = 2
def __len__(self):
return int(self.dataset_size)
def __getitem__(self, index):
rotation = np.pi*(-1 + 2*torch.rand([3]))
translation = -0.1 + 0.2*torch.rand([3])
reflection = torch.sign(torch.rand([3]) - 0.5)
if self.N_dim == 2:
rotation[0:2]=0
translation[2]=0
reflection[2]=1
random_solution = {'rotation':rotation,
'translation':translation,
'reflection':reflection}
return random_solution
def pil_to_numpy(im):
im.load()
# Unpack data
e = Image._getencoder(im.mode, "raw", im.mode)
e.setimage(im.im)
# NumPy buffer for the result
shape, typestr = Image._conv_type_shape(im)
data = np.empty(shape, dtype=np.dtype(typestr))
mem = data.data.cast("B", (data.data.nbytes,))
bufsize, s, offset = 65536, 0, 0
while not s:
l, s, d = e.encode(bufsize)
mem[offset:offset + len(d)] = d
offset += len(d)
if s < 0:
raise RuntimeError("encoder error %d in tobytes" % s)
return data
def load_image_pil_accelerated(image_path, dim=128):
image = Image.open(image_path).convert("RGB")
array = pil_to_numpy(image)
tensor = torch.from_numpy(np.rollaxis(array,2,0)/255).to(torch.float32)
tensor = torchvision.transforms.Resize((dim,dim))(tensor)
return tensor
def preprocess_image(image_path, dim = 128):
img = torch.zeros([1,3,dim,dim])
img[0] = load_image_pil_accelerated(image_path, dim)
return img