Ich habe kürzlich Pytorch gelernt, also werde ich damit spielen.
Alles was Sie tun müssen, ist die Punkte auszurichten.
Zu diesem Zweck hat icp ein Bild, das dazu neigt, in eine lokale Lösung zu fallen, aber Läuft die hochmoderne Optimierungsfunktion von pytorch nicht ziemlich gut? Ich werde es mit der flauschigen Erwartung versuchen.
Der Fluss ist wie folgt.
für jeden Punkt der Punktgruppe B.
   1.Transformationsmatrix$P = [R|t]$Ist definiert.
Die Ausrichtung erfolgt durch Optimierung dieses Parameters.
   2.Berechnen Sie die nächste Nachbarschaft der Punktgruppe und erhalten Sie die Menge der nächsten Punkte.
   3.Transformationsmatrix$P$Die Punkte der Punktgruppe B, zu denen
Die Punkte, die der Punktgruppe A am nächsten liegen, diese beiden, werden von der Verlustfunktion bewertet.
   4.Optimierungsprozess
Optimierte Transformationsmatrix$P$Bewerben und erneut von 1 ausführen
Überprüfen Sie mit dem folgenden Ablauf.
1.Bereiten Sie zwei identische Punktgruppen vor und bewegen Sie sich nur (Anpassen der 3D-Parameter)
2.Bereiten Sie zwei identische Punktgruppen vor und führen Sie nur eine Drehung durch (Anpassung der 9-dimensionalen Parameter).
3.Bereiten Sie zwei identische Punktgruppen vor und drehen / bewegen Sie sich (12-dimensionale Parametereinstellung)
3.Bereiten Sie zwei verschiedene Punktgruppen vor und drehen / bewegen Sie sich (12-dimensionale Parametereinstellung)
3.Fügen Sie der anderen Seite Rauschen hinzu, bereiten Sie zwei verschiedene Punktgruppen vor und drehen / bewegen Sie sich (12-dimensionale Parametereinstellung)
Ich habe das geschrieben, aber ich habe in der ersten Phase versagt. Ich bin noch nicht an Pytorch gewöhnt, also fehlt vielleicht etwas.
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
        #Versuchen Sie es in Punkten
        for j in range(epoch):
            for didx in range(len(pclB.points)):
                cnt += 1
                optimizer.zero_grad()
                #Nächste Berechnung
                [_, Aidx1, _] = kd_tree_A.search_knn_vector_3d(pclB.points[didx], 1)
                ptA_sample = pclA.points[Aidx1[0]]
                ptB_sample = pclB.points[didx]
                #Versteckte Koordinaten
                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, " :Error= ", 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(" :Error= ", loss.item(),"\t Fehler mit der richtigen Konvertierungsmatrix= ",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
        #Versuchen Sie es in Punkten
        for j in range(epoch):
            for didx in range(len(pclB.points)):
                cnt += 1
                optimizer.zero_grad()
                #Holen Sie sich die Punkte der Punktgruppe A, die jedem Punkt der Punktgruppe B am nächsten liegen
                [_, Aidx1, _] = kd_tree_A.search_knn_vector_3d(pclB.points[didx], 1)
                ptA_sample = pclA.points[Aidx1[0]]
                ptB_sample = pclB.points[didx]
                #Versteckte Koordinaten
                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)
                #Konvertieren Sie jeden Punkt in Tensor
                A_tor = torch.tensor(ptA_sample.tolist(), requires_grad=False)
                B_tor = torch.tensor(ptB_sample.tolist(), requires_grad=False)
                #Passen Sie Punktgruppe B an Punktgruppe A an.
                answer = A_tor
                output = (B_tor + transP)
                #Verlustberechnung->Optimierung
                loss = criterion(answer, output)
                loss.backward()
                optimizer.step()
                #Vergleich mit der richtigen Umrechnungsmatrix. (0 ist wünschenswert)
                ls = np.linalg.norm(testP - transP.to('cpu').detach().numpy().copy())
                history['train_loss'].append(loss)
                history['test_acc'].append(ls)
            print(" :Error= ", loss.item(), "\t Fehler mit der richtigen Konvertierungsmatrix= ", ls)
            #Reflektieren Sie das Anpassungsergebnis->Berechnung des nächsten Nachbarn erneut in der nächsten Schleife
            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))
    #Eine Gruppe von Punkten mit einem etwas höheren Schwierigkeitsgrad. Vielleicht geht das noch nicht ...
    # pclB = read_point_cloud("bun045.ply")
    # B = np.array(pclB.points)
    # B = np.array(random.sample(B.tolist(), POINT_NUM))
    # #Rauschen hinzufügen
    # B += np.random.randn(POINT_NUM, 3) * 0.005
    # #Gewähren von Unordnung (außer Betrieb) von Punktgruppen
    # 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()
Sehen wir uns das Ausgabeergebnis der Verlustfunktion an.
Betrachtet man dies allein, so scheint es, als würde es im Handumdrehen gegen 0 konvergieren.

Und dies ist ein Vergleich der durch Optimierung ausgegebenen Konvertierungsmatrix und der Konvertierungsmatrix der richtigen Antwort.

... Ich glaube, ich bin zuerst etwas niedriger geworden, aber ich habe die ganze Zeit Hunger. Es ist ein großer Fehler von 0,5. Ich gebe auch eine Gruppe von Punkten aus, aber ich werde sie weglassen, weil sie nur ein wenig näher war.
Es gibt keinen Ausreißer und es gibt nur 3 Dimensionen, aber warum ... Ich habe das Gefühl, ich mache einfach einen Fehler bei der Verwendung von Pytorch. Wenn Sie wissen, kontaktieren Sie mich bitte.
Als nächstes werden wir PointNet LK untersuchen, eine Erweiterung des T-Netzes von PointNet. https://github.com/wentaoyuan/it-net https://www.slideshare.net/naoyachiba18/pointnetlk-robust-efficient-point-cloud-registration-using-pointnet-167874587