def visualize_corres(points, correspondences, model):
    points += np.array([1., 0., 0.]).reshape((1, 3))
    tree = NN(n_neighbors=1000).fit(points)
    for idx in [88190, 132644]:  #range(100):
        #idx = np.random.randint(points.shape[0]-1)
        print('visualizing around point %d' % idx)
        dists, indices = tree.kneighbors(points[idx, :].reshape((1, 3)))
        neighbors = indices[0, :]
        source = points[neighbors, :]
        #import ipdb; ipdb.set_trace()
        target = model.verts[correspondences[neighbors], :]
        edges = vis.getEdges(source, target, 1000, color=np.array([1., 0, 0]))
        o3d.draw_geometries([
            vis.getPointCloud(points),
            vis.getTriangleMesh(model.verts, model.faces), edges
        ])
def visualize_smoothness(points, correspondences, model):
    points += np.array([1., 0., 0.]).reshape((1, 3))
    tree = NN(n_neighbors=10).fit(points)
    dists, indices = tree.kneighbors(points)
    corres = correspondences[indices]  # [n_points, 10]
    target_points = model.verts[corres, :]  # [n_points, 10, 3]
    mean = target_points.mean(axis=1)  # [n_points, 3]
    dists = target_points - mean[:, np.newaxis, :]  # [n_points, 10, 3]
    dists = np.square(dists).sum(axis=1).sum(axis=1)  # [n_points]
    max_dist = dists.max()
    min_dist = dists.min()
    dists = (dists - min_dist) / (max_dist - min_dist)
    r = np.array([1.0, 0, 0])
    b = np.array([0, 0, 1.])
    colors = np.array([(r * (di) + b * (1.0 - di)) for di in dists])
    pcd = vis.getPointCloud(points)
    pcd.colors = o3d.utility.Vector3dVector(colors)
    o3d.draw_geometries([pcd, vis.getTriangleMesh(model.verts, model.faces)])
        rotations = [
            linalg.rodriguez(
                np.array([0., 1., 0.]) * thetas[i] + np.random.randn(3) * 0.2)
            for i in range(n_views)
        ]
        for i, rotation in enumerate(rotations):
            np.savetxt('%s/%d.txt' % (rotation_path, i), rotation)
    else:
        rotations = [
            np.loadtxt('%s/%d.txt' % (rotation_path, i)).reshape((3, 3))
            for i in range(n_views)
        ]

    os.system('mkdir -p %s' % render_path)
    rest_mesh = helper.loadSMPLModels()[0]
    rest_mesh = vis.getTriangleMesh(rest_mesh.verts, rest_mesh.faces)
    #gt_descriptors = helper.loadSMPLDescriptors('Laplacian_N')['male']
    #dsc_tree = NN(n_neighbors=1, n_jobs=10).fit(gt_descriptors)
    IDlist = np.arange(1, 45)

    for scan_id in IDlist[args.offset:(args.offset + args.length)]:
        """ Correspondence translation """
        #raw_mesh = o3d.io.read_triangle_mesh(SCAN.format(scan_id)) # raw mesh
        #reg_mesh = o3d.io.read_triangle_mesh(REG.format(scan_id)) # registration mesh
        #tree = NN(n_neighbors=1, n_jobs=10).fit(np.array(reg_mesh.vertices))
        #dists, indices = tree.kneighbors(np.array(raw_mesh.vertices))
        #scan2reg = indices[:, 0]
        #Nraw = np.array(raw_mesh.vertices).shape[0]
        #Nreg = np.array(reg_mesh.vertices).shape[0]

        mesh = o3d.io.read_triangle_mesh(SCAN.format(scan_id))
                np.array([0., 1., 0.]) * thetas[i] + np.random.randn(3) * 0.2)
            for i in range(n_views)
        ]
        for i, rotation in enumerate(rotations):
            np.savetxt('%s/%d.txt' % (rotation_path, i), rotation)
    else:
        rotations = [
            np.loadtxt('%s/%d.txt' % (rotation_path, i)).reshape((3, 3))
            for i in range(n_views)
        ]

    os.system('mkdir -p %s' % render_path)
    rest_mesh = helper.loadAnimalModels()['horse']
    #edges = computeGraph(6890, rest_mesh.faces, knn=7)
    rest_mesh = vis.getTriangleMesh(
        np.array(rest_mesh.vertices),
        np.array(rest_mesh.triangles).astype(np.int32))
    gt_descriptors = helper.loadAnimalDescriptors(desc='horse')
    #dsc_tree = NN(n_neighbors=1, n_jobs=10).fit(gt_descriptors)

    for scan_id in range(args.offset, args.offset + args.length):
        """ Correspondence translation """
        #raw_mesh = o3d.io.read_triangle_mesh(SCAN.format(scan_id)) # raw mesh
        reg_mesh = o3d.io.read_triangle_mesh(
            REG.format(scan_id))  # registration mesh
        #tree = NN(n_neighbors=1, n_jobs=10).fit(np.array(reg_mesh.vertices))
        #dists, indices = tree.kneighbors(np.array(raw_mesh.vertices))
        #scan2reg = indices[:, 0]
        #Nraw = np.array(raw_mesh.vertices).shape[0]
        Nreg = np.array(reg_mesh.vertices).shape[0]
  MAT_PATH = '{}/{{0:06d}}'.format(render_path)
  MAT = '{}/{{0:06d}}/{{1:03d}}.mat'.format(render_path)
  OBJ = '{}/{{0:06d}}/{{1:03d}}.obj'.format(render_path)
  os.system('mkdir -p %s' % render_path)
  models = helper.loadSMPLModels()
  gt_dsc = helper.loadSMPLDescriptors(desc='Laplacian_n')
  edges = computeGraph(6890, models[0].faces, knn=args.knn)
  for mesh_id in range(offset, offset+length):
    os.system('mkdir -p %s' % MAT_PATH.format(mesh_id))
    params = np.array(smpl_params[mesh_id, :])
    params[11:14] = 0.0
    gender = int(params[0])
    model = models[gender]
    zero_params = np.zeros(85)
    model.update_params(zero_params)
    rest_mesh = vis.getTriangleMesh(model.verts, model.faces)
    params = np.concatenate([np.zeros(3), params[1:]], axis=0)
    model.update_params(params)
    mesh = vis.getTriangleMesh(model.verts, model.faces)
    point_rotations, point_translations = helper.computeLocalRotations(np.array(mesh.vertices), np.array(mesh.triangles), np.array(rest_mesh.vertices), np.arange(np.array(mesh.vertices).shape[0]), edges=edges) # [N, 3]

    #mat_file = MAT.format(mesh_id)
    depths = []
    points3d = []
    valid_pixel_indices = []
    correspondences = []
    intrinsics = []
    extrinsics = []
    params_list = []
    gt_feats = []
    gt_transformations = []
def align(points,
          correspondences,
          normals,
          model,
          weights=None,
          weightPoint2Plane=0.9,
          max_iter=100):
    """ Align a SMPL model to a set of points.

  Args:
    points: np.ndarray of shape [N, 3]. Raw point cloud.
    correspondences: integer np.ndarray of shape [N].
                     j = correspondences[i] indicates a edge between
                     points[i] and model.verts[j]
    normals: np.ndarray of shape [N, 3]. normals.
    model: SMPLModel object.
    weights: [N] floats. Indicating confidence score of each correspondence.
    weightPoint2Plane: a float in [0, 1].
    max_iter: maximum number of iterations.
  Returns:
    params: SMPL parameters.
  """
    if weights is None:
        weights = np.ones(correspondences.shape[0])
    fixed_dict = {
        'points': points,
        'normals': np.array(normals),
        'correspondences': np.array(correspondences).astype(np.int32),
        'weights': weights,
    }
    params = np.random.randn(85) * 1e-3
    update_model(model, params)
    for itr in range(max_iter):
        mesh = vis.getTriangleMesh(model.verts, model.faces)
        mesh.compute_vertex_normals()
        model.compute_derivatives()

        moving_points = model.verts
        moving_normals = np.array(mesh.vertex_normals)
        if itr > 30:
            fixed_dict['weights'][:] = 0.0
            new_fixed_dict = update_correspondences(
                fixed_dict['points'], fixed_dict['normals'], moving_points,
                moving_normals, fixed_dict['correspondences'],
                fixed_dict['weights'])
            cur_fixed_dict = new_fixed_dict
        else:
            cur_fixed_dict = fixed_dict
        cur_fixed_dict['weights'] = update_correspondence_weights(
            cur_fixed_dict['points'],
            cur_fixed_dict['normals'],
            moving_points,
            moving_normals,
            cur_fixed_dict['correspondences'],
        )
        res_dict = gauss_newton(moving_points, cur_fixed_dict['points'],
                                cur_fixed_dict['normals'],
                                cur_fixed_dict['correspondences'],
                                cur_fixed_dict['weights'],
                                model.derivatives['v'], weightPoint2Plane)
        params += res_dict['dparams']
        update_model(model, params)
        #o3d.draw_geometries([vis.getTriangleMesh(model.verts, model.faces), vis.getPointCloud(points)])
        #print('dist=%4.6f, dparams=%3.4f' % (res_dict['dist'], np.linalg.norm(res_dict['dparams'], 2)))
    return params