J'ai récemment appris le pytorch alors je vais jouer avec.
Tout ce que vous avez à faire est d'aligner les points.
Le but est que l'icp ait une image personnelle qui a tendance à tomber dans une solution locale, La fonction d'optimisation de pointe de pytorch ne fonctionne-t-elle pas plutôt bien? Je vais l'essayer avec l'attente moelleuse.
Le flux est le suivant.
pour chaque point du groupe de points B
1.Matrice de transformation$P = [R|t]$Est défini.
L'alignement est effectué en optimisant ce paramètre.
2.Calculez le voisinage le plus proche du groupe de points et obtenez l'ensemble des points les plus proches.
3.Matrice de transformation$P$Les points du groupe de points B auxquels
Les points les plus proches du groupe de points A, ces deux, sont évalués par la fonction de perte.
4.Processus d'optimisation
Matrice de transformation optimisée$P$Appliquer et recommencer à partir de 1
Vérifiez avec le flux suivant.
1.Préparez deux groupes de points identiques et déplacez uniquement (ajustement des paramètres 3D)
2.Préparez deux groupes de points identiques et effectuez uniquement une rotation (ajustement des paramètres à 9 dimensions)
3.Préparer deux groupes de points identiques et faire pivoter / déplacer (réglage des paramètres en 12 dimensions)
3.Préparer deux groupes de points différents et faire pivoter / déplacer (réglage des paramètres en 12 dimensions)
3.Ajoutez du bruit de l'autre côté, préparez deux groupes de points différents et faites pivoter / déplacer (réglage des paramètres en 12 dimensions)
J'ai écrit cela, mais j'ai échoué au premier stade. Je ne suis pas encore habitué au pytorch, alors peut-être qu'il manque quelque chose.
tetst.py
import copy
import numpy as np
import open3d as o3d
import random
import math
import torch.nn as nn
import torch.nn.functional as F
import torch
import torch.optim as optim
import matplotlib.pyplot as plt
epoch = 1000
def getPLYfromNumpy(nplist):
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(nplist)
return pcd
def write_point_cloud(path, pcl):
assert o3d.io.write_point_cloud(path, pcl), "write pcl error : " + path
def read_point_cloud(path):
pcl = o3d.io.read_point_cloud(path)
if len(pcl.points) == 0: assert False, "load pcl error : " + path
return pcl
def Register_EachPoint_RT(pclA, pclB,testP,criterion,optimizer):
history = {
'train_loss': [],
'test_acc': [],
}
transP = torch.tensor(
[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]],
requires_grad=True)
params = [transP]
optimizer = optimizer(params)
kd_tree_A = o3d.geometry.KDTreeFlann(pclA)
cnt = 0
#Essayez-le en points
for j in range(epoch):
for didx in range(len(pclB.points)):
cnt += 1
optimizer.zero_grad()
#Calcul le plus proche
[_, Aidx1, _] = kd_tree_A.search_knn_vector_3d(pclB.points[didx], 1)
ptA_sample = pclA.points[Aidx1[0]]
ptB_sample = pclB.points[didx]
#Coordonnées cachées
ptA_sample = np.array([ptA_sample[0], ptA_sample[1], ptA_sample[2], 1])
ptB_sample = np.array([ptB_sample[0], ptB_sample[1], ptB_sample[2], 1])
ptA_sample = ptA_sample.reshape(4, 1)
ptB_sample = ptB_sample.reshape(4, 1)
A_tor = torch.tensor(ptA_sample.tolist(), requires_grad=False)
B_tor = torch.tensor(ptB_sample.tolist(), requires_grad=False)
answer = A_tor
output = torch.mm(transP, B_tor)
loss = criterion(answer, output)
loss.backward()
optimizer.step()
# print( j, cnt, " :Erreur= ", loss.item(),"\n",transP)
ls = np.linalg.norm(testP - transP.to('cpu').detach().numpy().copy())
history['train_loss'].append(loss)
history['test_acc'].append(ls)
print(" :Erreur= ", loss.item(),"\t Erreur avec la matrice de conversion correcte= ",ls)
plt.figure()
plt.plot(range(1, cnt + 1), history['train_loss'], label='train_loss')
plt.xlabel('train_loss')
plt.legend()
plt.savefig('train_loss.png')
plt.figure()
plt.plot(range(1, cnt + 1), history['test_acc'], label='test_acc')
plt.xlabel('test_acc')
plt.legend()
plt.savefig('test_acc.png')
return transP
def Register_EachPoint_T(pclA, pclB,testP,criterion,optimizer):
history = {
'train_loss': [],
'test_acc': [],
}
transP = torch.tensor([[0.0], [0.0], [0.0]],requires_grad=True)
params = [transP]
optimizer = optimizer(params)
kd_tree_A = o3d.geometry.KDTreeFlann(pclA)
cnt = 0
#Essayez-le en points
for j in range(epoch):
for didx in range(len(pclB.points)):
cnt += 1
optimizer.zero_grad()
#Obtenez les points du groupe de points A les plus proches de chaque point du groupe de points B
[_, Aidx1, _] = kd_tree_A.search_knn_vector_3d(pclB.points[didx], 1)
ptA_sample = pclA.points[Aidx1[0]]
ptB_sample = pclB.points[didx]
#Coordonnées cachées
ptA_sample = np.array([ptA_sample[0], ptA_sample[1], ptA_sample[2]])
ptB_sample = np.array([ptB_sample[0], ptB_sample[1], ptB_sample[2]])
ptA_sample = ptA_sample.reshape(3, 1)
ptB_sample = ptB_sample.reshape(3, 1)
#Convertir chaque point en Tensor
A_tor = torch.tensor(ptA_sample.tolist(), requires_grad=False)
B_tor = torch.tensor(ptB_sample.tolist(), requires_grad=False)
#Ajustez le groupe de points B pour correspondre au groupe de points A.
answer = A_tor
output = (B_tor + transP)
#Calcul des pertes->optimisation
loss = criterion(answer, output)
loss.backward()
optimizer.step()
#Comparaison avec la bonne matrice de conversion. (0 est souhaitable)
ls = np.linalg.norm(testP - transP.to('cpu').detach().numpy().copy())
history['train_loss'].append(loss)
history['test_acc'].append(ls)
print(" :Erreur= ", loss.item(), "\t Erreur avec la matrice de conversion correcte= ", ls)
#Refléter le résultat de l'ajustement->Calcul du voisin le plus proche à nouveau dans la boucle suivante
nptransP = transP.to('cpu').detach().numpy().copy().reshape(1,3)
pclB = getPLYfromNumpy(pclB.points + nptransP)
plt.figure()
plt.plot(range(1, cnt + 1), history['train_loss'], label='train_loss')
plt.xlabel('train_loss')
plt.legend()
plt.savefig('train_loss.png')
plt.figure()
plt.plot(range(1, cnt + 1), history['test_acc'], label='test_acc')
plt.xlabel('test_acc')
plt.legend()
plt.savefig('test_acc.png')
return transP
POINT_NUM = 1024
# http://graphics.stanford.edu/data/3Dscanrep/
pclA = read_point_cloud("bun000.ply")
A = np.array(pclA.points)
A = np.array(random.sample(A.tolist(), POINT_NUM))
#Un groupe de points avec un niveau de difficulté légèrement plus élevé. Peut-être que cela ne peut pas encore être fait ...
# pclB = read_point_cloud("bun045.ply")
# B = np.array(pclB.points)
# B = np.array(random.sample(B.tolist(), POINT_NUM))
# #Ajoute du bruit
# B += np.random.randn(POINT_NUM, 3) * 0.005
# #Accorder le désordre (dans l'ordre) des groupes de points
# np.random.shuffle(B)
# pclB_sample = getPLYfromNumpy(B)
pclA_sample = getPLYfromNumpy(A)
T_Projection = np.array([[1, 0, 0, 0.5],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
T_translation = np.array([[T_Projection[0][3]], [T_Projection[1][3]], [T_Projection[2][3]]])
pclA_trans_sample = getPLYfromNumpy(A).transform(T_Projection)
write_point_cloud("A_before.ply", pclA_sample)
write_point_cloud("A_rot_before.ply", pclA_trans_sample)
def testEstimateT(pclA_sample,pclA_trans_sample,T_translation):
optimizer = optim.Adam
# MSELoss
transP = Register_EachPoint_T(pclA_sample, pclA_trans_sample, T_translation, nn.MSELoss(),optimizer)
T_res = np.array([[1, 0, 0, transP[0]],
[0, 1, 0, transP[1]],
[0, 0, 1, transP[2]],
[0, 0, 0, 1]])
pclA_res = copy.copy(pclA_trans_sample)
pclA_res = pclA_res.transform(T_res)
write_point_cloud("TOnlytest_A_rot_after_MSELoss.ply", pclA_res)
# # L1Loss
# transP = Register_EachPoint_T(pclA_sample, pclA_trans_sample, T_translation, nn.L1Loss(),optimizer)
# T_res = np.array([[1, 0, 0, transP[0]],
# [0, 1, 0, transP[1]],
# [0, 0, 1, transP[2]],
# [0, 0, 0, 1]])
# pclA_res = copy.copy(pclA_trans_sample)
# pclA_res = pclA_res.transform(T_res)
# write_point_cloud("TOnlytest_A_rot_after_L1Loss.ply", pclA_res)
def testEstimateRT(pclA_sample,pclA_trans_sample,T_Projection):
optimizer = optim.Adam
# MSELoss
transP = Register_EachPoint_RT(pclA_sample, pclA_trans_sample, T_Projection, nn.MSELoss(),optimizer)
transP = transP.to('cpu').detach().numpy().copy()
pclA_res = copy.copy(pclA_trans_sample)
pclA_res = pclA_res.transform(transP)
write_point_cloud("RTtest_A_rot_after_MSELoss.ply", pclA_res)
testEstimateT(pclA_sample, pclA_trans_sample, T_translation)
# testEstimateRT(pclA_sample, pclA_trans_sample, T_Projection)
exit()
Voyons le résultat de sortie de la fonction de perte. En regardant cela seul, il semble qu'il converge vers 0 en un clin d'œil.
Et ceci est une comparaison de la matrice de conversion sortie par optimisation et de la matrice de conversion de la bonne réponse.
... Je pense que j'ai baissé un peu au début, mais j'ai toujours faim. C'est une grosse erreur de 0,5. J'ai également sorti un groupe de points, mais je vais l'omettre car c'était seulement un peu plus proche.
Il n'y a pas de valeur aberrante et il n'y a que 3 dimensions, mais pourquoi ... J'ai l'impression que je fais simplement une erreur en utilisant Pytorch. Si vous le savez, veuillez me contacter.
Ensuite, nous étudierons PointNet LK, qui est une extension du T-net de PointNet. https://github.com/wentaoyuan/it-net https://www.slideshare.net/naoyachiba18/pointnetlk-robust-efficient-point-cloud-registration-using-pointnet-167874587