clean-code and add params' explanation
This commit is contained in:
parent
25a0c9af31
commit
0bc8fede9e
27
README.md
27
README.md
@ -25,9 +25,12 @@ Light Gaussian implementation: [This link](https://github.com/pablodawson/4DGaus
|
|||||||
|
|
||||||
|
|
||||||
## News
|
## News
|
||||||
|
|
||||||
|
2024.6.25: we clean the code and add an explanation of the parameters.
|
||||||
|
|
||||||
2024.3.25: Update guidance for hypernerf and dynerf dataset.
|
2024.3.25: Update guidance for hypernerf and dynerf dataset.
|
||||||
|
|
||||||
2024.03.04: We change the hyperparameters of the Neu3D dataset, corresponding to our paper
|
2024.03.04: We change the hyperparameters of the Neu3D dataset, corresponding to our paper.
|
||||||
|
|
||||||
2024.02.28: Update SIBR viewer guidance.
|
2024.02.28: Update SIBR viewer guidance.
|
||||||
|
|
||||||
@ -89,7 +92,7 @@ Meanwhile, [Plenoptic Dataset](https://github.com/facebookresearch/Neural_3D_Vid
|
|||||||
```
|
```
|
||||||
|
|
||||||
**For multipleviews scenes:**
|
**For multipleviews scenes:**
|
||||||
If you want to train your own dataset of multipleviews scenes,you can orginize your dataset as follows:
|
If you want to train your own dataset of multipleviews scenes, you can orginize your dataset as follows:
|
||||||
|
|
||||||
```
|
```
|
||||||
├── data
|
├── data
|
||||||
@ -105,11 +108,11 @@ If you want to train your own dataset of multipleviews scenes,you can orginize y
|
|||||||
│ ├── ...
|
│ ├── ...
|
||||||
│ | ...
|
│ | ...
|
||||||
```
|
```
|
||||||
After that,you can use the `multipleviewprogress.sh` we provided to generate related data of poses and pointcloud.You can use it as follows:
|
After that, you can use the `multipleviewprogress.sh` we provided to generate related data of poses and pointcloud.You can use it as follows:
|
||||||
```bash
|
```bash
|
||||||
bash multipleviewprogress.sh (youe dataset name)
|
bash multipleviewprogress.sh (youe dataset name)
|
||||||
```
|
```
|
||||||
You need to ensure that the data folder is orginized as follows after running multipleviewprogress.sh:
|
You need to ensure that the data folder is organized as follows after running multipleviewprogress.sh:
|
||||||
```
|
```
|
||||||
├── data
|
├── data
|
||||||
| | multipleview
|
| | multipleview
|
||||||
@ -181,7 +184,7 @@ You can customize your training config through the config files.
|
|||||||
|
|
||||||
## Checkpoint
|
## Checkpoint
|
||||||
|
|
||||||
Also, you can training your model with checkpoint.
|
Also, you can train your model with checkpoint.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
python train.py -s data/dnerf/bouncingballs --port 6017 --expname "dnerf/bouncingballs" --configs arguments/dnerf/bouncingballs.py --checkpoint_iterations 200 # change it.
|
python train.py -s data/dnerf/bouncingballs --port 6017 --expname "dnerf/bouncingballs" --configs arguments/dnerf/bouncingballs.py --checkpoint_iterations 200 # change it.
|
||||||
@ -199,7 +202,7 @@ python train.py -s data/dnerf/bouncingballs --port 6017 --expname "dnerf/bouncin
|
|||||||
Run the following script to render the images.
|
Run the following script to render the images.
|
||||||
|
|
||||||
```
|
```
|
||||||
python render.py --model_path "output/dnerf/bouncingballs/" --skip_train --configs arguments/dnerf/bouncingballs.py &
|
python render.py --model_path "output/dnerf/bouncingballs/" --skip_train --configs arguments/dnerf/bouncingballs.py
|
||||||
```
|
```
|
||||||
|
|
||||||
## Evaluation
|
## Evaluation
|
||||||
@ -297,11 +300,13 @@ We would like to express our sincere gratitude to [@zhouzhenghong-gt](https://gi
|
|||||||
Some insights about neural voxel grids and dynamic scenes reconstruction originate from [TiNeuVox](https://github.com/hustvl/TiNeuVox). If you find this repository/work helpful in your research, welcome to cite these papers and give a ⭐.
|
Some insights about neural voxel grids and dynamic scenes reconstruction originate from [TiNeuVox](https://github.com/hustvl/TiNeuVox). If you find this repository/work helpful in your research, welcome to cite these papers and give a ⭐.
|
||||||
|
|
||||||
```
|
```
|
||||||
@article{wu20234dgaussians,
|
@InProceedings{Wu_2024_CVPR,
|
||||||
title={4D Gaussian Splatting for Real-Time Dynamic Scene Rendering},
|
author = {Wu, Guanjun and Yi, Taoran and Fang, Jiemin and Xie, Lingxi and Zhang, Xiaopeng and Wei, Wei and Liu, Wenyu and Tian, Qi and Wang, Xinggang},
|
||||||
author={Wu, Guanjun and Yi, Taoran and Fang, Jiemin and Xie, Lingxi and Zhang, Xiaopeng and Wei Wei and Liu, Wenyu and Tian, Qi and Wang Xinggang},
|
title = {4D Gaussian Splatting for Real-Time Dynamic Scene Rendering},
|
||||||
journal={arXiv preprint arXiv:2310.08528},
|
booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
|
||||||
year={2023}
|
month = {June},
|
||||||
|
year = {2024},
|
||||||
|
pages = {20310-20320}
|
||||||
}
|
}
|
||||||
|
|
||||||
@inproceedings{TiNeuVox,
|
@inproceedings{TiNeuVox,
|
||||||
|
|||||||
@ -73,35 +73,35 @@ class PipelineParams(ParamGroup):
|
|||||||
super().__init__(parser, "Pipeline Parameters")
|
super().__init__(parser, "Pipeline Parameters")
|
||||||
class ModelHiddenParams(ParamGroup):
|
class ModelHiddenParams(ParamGroup):
|
||||||
def __init__(self, parser):
|
def __init__(self, parser):
|
||||||
self.net_width = 64
|
self.net_width = 64 # width of deformation MLP, larger will increase the rendering quality and decrase the training/rendering speed.
|
||||||
self.timebase_pe = 4
|
self.timebase_pe = 4 # useless
|
||||||
self.defor_depth = 1
|
self.defor_depth = 1 # depth of deformation MLP, larger will increase the rendering quality and decrase the training/rendering speed.
|
||||||
self.posebase_pe = 10
|
self.posebase_pe = 10 # useless
|
||||||
self.scale_rotation_pe = 2
|
self.scale_rotation_pe = 2 # useless
|
||||||
self.opacity_pe = 2
|
self.opacity_pe = 2 # useless
|
||||||
self.timenet_width = 64
|
self.timenet_width = 64 # useless
|
||||||
self.timenet_output = 32
|
self.timenet_output = 32 # useless
|
||||||
self.bounds = 1.6
|
self.bounds = 1.6
|
||||||
self.plane_tv_weight = 0.0001
|
self.plane_tv_weight = 0.0001 # TV loss of spatial grid
|
||||||
self.time_smoothness_weight = 0.01
|
self.time_smoothness_weight = 0.01 # TV loss of temporal grid
|
||||||
self.l1_time_planes = 0.0001
|
self.l1_time_planes = 0.0001 # TV loss of temporal grid
|
||||||
self.kplanes_config = {
|
self.kplanes_config = {
|
||||||
'grid_dimensions': 2,
|
'grid_dimensions': 2,
|
||||||
'input_coordinate_dim': 4,
|
'input_coordinate_dim': 4,
|
||||||
'output_coordinate_dim': 32,
|
'output_coordinate_dim': 32,
|
||||||
'resolution': [64, 64, 64, 25]
|
'resolution': [64, 64, 64, 25] # [64,64,64]: resolution of spatial grid. 25: resolution of temporal grid, better to be half length of dynamic frames
|
||||||
}
|
}
|
||||||
self.multires = [1, 2, 4, 8]
|
self.multires = [1, 2, 4, 8] # multi resolution of voxel grid
|
||||||
self.no_dx=False
|
self.no_dx=False # cancel the deformation of Gaussians' position
|
||||||
self.no_grid=False
|
self.no_grid=False # cancel the spatial-temporal hexplane.
|
||||||
self.no_ds=False
|
self.no_ds=False # cancel the deformation of Gaussians' scaling
|
||||||
self.no_dr=False
|
self.no_dr=False # cancel the deformation of Gaussians' rotations
|
||||||
self.no_do=True
|
self.no_do=True # cancel the deformation of Gaussians' opacity
|
||||||
self.no_dshs=True
|
self.no_dshs=True # cancel the deformation of SH colors.
|
||||||
self.empty_voxel=False
|
self.empty_voxel=False # useless
|
||||||
self.grid_pe=0
|
self.grid_pe=0 # useless, I was trying to add positional encoding to hexplane's features
|
||||||
self.static_mlp=False
|
self.static_mlp=False # useless
|
||||||
self.apply_rotation=False
|
self.apply_rotation=False # useless
|
||||||
|
|
||||||
|
|
||||||
super().__init__(parser, "ModelHiddenParams")
|
super().__init__(parser, "ModelHiddenParams")
|
||||||
|
|||||||
@ -161,6 +161,7 @@ def save_point_cloud(points, model_path, timestamp):
|
|||||||
pcd.points = o3d.utility.Vector3dVector(points)
|
pcd.points = o3d.utility.Vector3dVector(points)
|
||||||
ply_path = os.path.join(output_path,f"points_{timestamp}.ply")
|
ply_path = os.path.join(output_path,f"points_{timestamp}.ply")
|
||||||
o3d.io.write_point_cloud(ply_path, pcd)
|
o3d.io.write_point_cloud(ply_path, pcd)
|
||||||
|
# This scripts can help you to merge many 4DGS.
|
||||||
parser = ArgumentParser(description="Testing script parameters")
|
parser = ArgumentParser(description="Testing script parameters")
|
||||||
model = ModelParams(parser, sentinel=True)
|
model = ModelParams(parser, sentinel=True)
|
||||||
pipeline = PipelineParams(parser)
|
pipeline = PipelineParams(parser)
|
||||||
@ -228,5 +229,3 @@ for index, viewpoint in tqdm(enumerate(scene1.getVideoCameras())):
|
|||||||
torchvision.utils.save_image(result["render"],os.path.join(render_path,f"output_image{index}.png"))
|
torchvision.utils.save_image(result["render"],os.path.join(render_path,f"output_image{index}.png"))
|
||||||
|
|
||||||
imageio.mimwrite(os.path.join(render_path, 'video_rgb.mp4'), render_images, fps=30, codec='libx265')
|
imageio.mimwrite(os.path.join(render_path, 'video_rgb.mp4'), render_images, fps=30, codec='libx265')
|
||||||
# points = get_state_at_time(gaussians, viewpoint)
|
|
||||||
# save_point_cloud(points, args.model_path, index)
|
|
||||||
11
render.py
11
render.py
@ -23,7 +23,6 @@ from argparse import ArgumentParser
|
|||||||
from arguments import ModelParams, PipelineParams, get_combined_args, ModelHiddenParams
|
from arguments import ModelParams, PipelineParams, get_combined_args, ModelHiddenParams
|
||||||
from gaussian_renderer import GaussianModel
|
from gaussian_renderer import GaussianModel
|
||||||
from time import time
|
from time import time
|
||||||
# import torch.multiprocessing as mp
|
|
||||||
import threading
|
import threading
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
def multithread_write(image_list, path):
|
def multithread_write(image_list, path):
|
||||||
@ -53,32 +52,24 @@ def render_set(model_path, name, iteration, views, gaussians, pipeline, backgrou
|
|||||||
render_images = []
|
render_images = []
|
||||||
gt_list = []
|
gt_list = []
|
||||||
render_list = []
|
render_list = []
|
||||||
# breakpoint()
|
|
||||||
print("point nums:",gaussians._xyz.shape[0])
|
print("point nums:",gaussians._xyz.shape[0])
|
||||||
for idx, view in enumerate(tqdm(views, desc="Rendering progress")):
|
for idx, view in enumerate(tqdm(views, desc="Rendering progress")):
|
||||||
if idx == 0:time1 = time()
|
if idx == 0:time1 = time()
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
rendering = render(view, gaussians, pipeline, background,cam_type=cam_type)["render"]
|
rendering = render(view, gaussians, pipeline, background,cam_type=cam_type)["render"]
|
||||||
# torchvision.utils.save_image(rendering, os.path.join(render_path, '{0:05d}'.format(idx) + ".png"))
|
|
||||||
render_images.append(to8b(rendering).transpose(1,2,0))
|
render_images.append(to8b(rendering).transpose(1,2,0))
|
||||||
# print(to8b(rendering).shape)
|
|
||||||
render_list.append(rendering)
|
render_list.append(rendering)
|
||||||
if name in ["train", "test"]:
|
if name in ["train", "test"]:
|
||||||
if cam_type != "PanopticSports":
|
if cam_type != "PanopticSports":
|
||||||
gt = view.original_image[0:3, :, :]
|
gt = view.original_image[0:3, :, :]
|
||||||
else:
|
else:
|
||||||
gt = view['image'].cuda()
|
gt = view['image'].cuda()
|
||||||
# torchvision.utils.save_image(gt, os.path.join(gts_path, '{0:05d}'.format(idx) + ".png"))
|
|
||||||
gt_list.append(gt)
|
gt_list.append(gt)
|
||||||
# if idx >= 10:
|
|
||||||
# break
|
|
||||||
time2=time()
|
time2=time()
|
||||||
print("FPS:",(len(views)-1)/(time2-time1))
|
print("FPS:",(len(views)-1)/(time2-time1))
|
||||||
# print("writing training images.")
|
|
||||||
|
|
||||||
multithread_write(gt_list, gts_path)
|
multithread_write(gt_list, gts_path)
|
||||||
# print("writing rendering images.")
|
|
||||||
|
|
||||||
multithread_write(render_list, render_path)
|
multithread_write(render_list, render_path)
|
||||||
|
|
||||||
|
|||||||
@ -307,7 +307,6 @@ def read_timeline(path):
|
|||||||
timestamp_mapper = {}
|
timestamp_mapper = {}
|
||||||
max_time_float = max(time_line)
|
max_time_float = max(time_line)
|
||||||
for index, time in enumerate(time_line):
|
for index, time in enumerate(time_line):
|
||||||
# timestamp_mapper[time] = index
|
|
||||||
timestamp_mapper[time] = time/max_time_float
|
timestamp_mapper[time] = time/max_time_float
|
||||||
|
|
||||||
return timestamp_mapper, max_time_float
|
return timestamp_mapper, max_time_float
|
||||||
@ -548,18 +547,12 @@ def readPanopticmeta(datadir, json_path):
|
|||||||
cam_ids = test_meta['cam_id'][index]
|
cam_ids = test_meta['cam_id'][index]
|
||||||
|
|
||||||
time = index / len(test_meta['fn'])
|
time = index / len(test_meta['fn'])
|
||||||
# breakpoint()
|
|
||||||
for focal, w2c, fn, cam in zip(focals, w2cs, fns, cam_ids):
|
for focal, w2c, fn, cam in zip(focals, w2cs, fns, cam_ids):
|
||||||
image_path = os.path.join(datadir,"ims")
|
image_path = os.path.join(datadir,"ims")
|
||||||
image_name=fn
|
image_name=fn
|
||||||
|
|
||||||
# breakpoint()
|
|
||||||
image = Image.open(os.path.join(datadir,"ims",fn))
|
image = Image.open(os.path.join(datadir,"ims",fn))
|
||||||
im_data = np.array(image.convert("RGBA"))
|
im_data = np.array(image.convert("RGBA"))
|
||||||
# breakpoint()
|
|
||||||
im_data = PILtoTorch(im_data,None)[:3,:,:]
|
im_data = PILtoTorch(im_data,None)[:3,:,:]
|
||||||
# breakpoint()
|
|
||||||
# print(w2c,focal,image_name)
|
|
||||||
camera = setup_camera(w, h, focal, w2c)
|
camera = setup_camera(w, h, focal, w2c)
|
||||||
cam_infos.append({
|
cam_infos.append({
|
||||||
"camera":camera,
|
"camera":camera,
|
||||||
@ -568,7 +561,6 @@ def readPanopticmeta(datadir, json_path):
|
|||||||
|
|
||||||
cam_centers = np.linalg.inv(test_meta['w2c'][0])[:, :3, 3] # Get scene radius
|
cam_centers = np.linalg.inv(test_meta['w2c'][0])[:, :3, 3] # Get scene radius
|
||||||
scene_radius = 1.1 * np.max(np.linalg.norm(cam_centers - np.mean(cam_centers, 0)[None], axis=-1))
|
scene_radius = 1.1 * np.max(np.linalg.norm(cam_centers - np.mean(cam_centers, 0)[None], axis=-1))
|
||||||
# breakpoint()
|
|
||||||
return cam_infos, max_time, scene_radius
|
return cam_infos, max_time, scene_radius
|
||||||
|
|
||||||
def readPanopticSportsinfos(datadir):
|
def readPanopticSportsinfos(datadir):
|
||||||
|
|||||||
@ -22,7 +22,6 @@ from utils.sh_utils import RGB2SH
|
|||||||
from simple_knn._C import distCUDA2
|
from simple_knn._C import distCUDA2
|
||||||
from utils.graphics_utils import BasicPointCloud
|
from utils.graphics_utils import BasicPointCloud
|
||||||
from utils.general_utils import strip_symmetric, build_scaling_rotation
|
from utils.general_utils import strip_symmetric, build_scaling_rotation
|
||||||
# from utils.point_utils import addpoint, combine_pointcloud, downsample_point_cloud_open3d, find_indices_in_A
|
|
||||||
from scene.deformation import deform_network
|
from scene.deformation import deform_network
|
||||||
from scene.regulation import compute_plane_smoothness
|
from scene.regulation import compute_plane_smoothness
|
||||||
class GaussianModel:
|
class GaussianModel:
|
||||||
@ -49,9 +48,7 @@ class GaussianModel:
|
|||||||
self.active_sh_degree = 0
|
self.active_sh_degree = 0
|
||||||
self.max_sh_degree = sh_degree
|
self.max_sh_degree = sh_degree
|
||||||
self._xyz = torch.empty(0)
|
self._xyz = torch.empty(0)
|
||||||
# self._deformation = torch.empty(0)
|
|
||||||
self._deformation = deform_network(args)
|
self._deformation = deform_network(args)
|
||||||
# self.grid = TriPlaneGrid()
|
|
||||||
self._features_dc = torch.empty(0)
|
self._features_dc = torch.empty(0)
|
||||||
self._features_rest = torch.empty(0)
|
self._features_rest = torch.empty(0)
|
||||||
self._scaling = torch.empty(0)
|
self._scaling = torch.empty(0)
|
||||||
@ -232,9 +229,7 @@ class GaussianModel:
|
|||||||
deform = self._deformation[:,:,:time].sum(dim=-1)
|
deform = self._deformation[:,:,:time].sum(dim=-1)
|
||||||
xyz = self._xyz + deform
|
xyz = self._xyz + deform
|
||||||
return xyz
|
return xyz
|
||||||
# def save_ply_dynamic(path):
|
|
||||||
# for time in range(self._deformation.shape(-1)):
|
|
||||||
# xyz = self.compute_deformation(time)
|
|
||||||
def load_model(self, path):
|
def load_model(self, path):
|
||||||
print("loading model from exists{}".format(path))
|
print("loading model from exists{}".format(path))
|
||||||
weight_dict = torch.load(os.path.join(path,"deformation.pth"),map_location="cuda")
|
weight_dict = torch.load(os.path.join(path,"deformation.pth"),map_location="cuda")
|
||||||
@ -448,49 +443,18 @@ class GaussianModel:
|
|||||||
def densify_and_clone(self, grads, grad_threshold, scene_extent, density_threshold=20, displacement_scale=20, model_path=None, iteration=None, stage=None):
|
def densify_and_clone(self, grads, grad_threshold, scene_extent, density_threshold=20, displacement_scale=20, model_path=None, iteration=None, stage=None):
|
||||||
grads_accum_mask = torch.where(torch.norm(grads, dim=-1) >= grad_threshold, True, False)
|
grads_accum_mask = torch.where(torch.norm(grads, dim=-1) >= grad_threshold, True, False)
|
||||||
|
|
||||||
# 主动增加稀疏点云
|
|
||||||
# if not hasattr(self,"voxel_size"):
|
|
||||||
# self.voxel_size = 8
|
|
||||||
# if not hasattr(self,"density_threshold"):
|
|
||||||
# self.density_threshold = density_threshold
|
|
||||||
# if not hasattr(self,"displacement_scale"):
|
|
||||||
# self.displacement_scale = displacement_scale
|
|
||||||
# point_cloud = self.get_xyz.detach().cpu()
|
|
||||||
# sparse_point_mask = self.downsample_point(point_cloud)
|
|
||||||
# _, low_density_points, new_points, low_density_index = addpoint(point_cloud[sparse_point_mask],density_threshold=self.density_threshold,displacement_scale=self.displacement_scale,iter_pass=0)
|
|
||||||
# sparse_point_mask = sparse_point_mask.to(grads_accum_mask)
|
|
||||||
# low_density_index = low_density_index.to(grads_accum_mask)
|
|
||||||
# if new_points.shape[0] < 100 :
|
|
||||||
# self.density_threshold /= 2
|
|
||||||
# self.displacement_scale /= 2
|
|
||||||
# print("reduce diplacement_scale to: ",self.displacement_scale)
|
|
||||||
# global_mask = torch.zeros((point_cloud.shape[0]), dtype=torch.bool).to(grads_accum_mask)
|
|
||||||
# global_mask[sparse_point_mask] = low_density_index
|
|
||||||
# selected_pts_mask_grow = torch.logical_and(global_mask, grads_accum_mask)
|
|
||||||
# print("降采样点云:",sparse_point_mask.sum(),"选中的稀疏点云:",global_mask.sum(),"梯度累计点云:",grads_accum_mask.sum(),"选中增长点云:",selected_pts_mask_grow.sum())
|
|
||||||
# Extract points that satisfy the gradient condition
|
|
||||||
selected_pts_mask = torch.logical_and(grads_accum_mask,
|
selected_pts_mask = torch.logical_and(grads_accum_mask,
|
||||||
torch.max(self.get_scaling, dim=1).values <= self.percent_dense*scene_extent)
|
torch.max(self.get_scaling, dim=1).values <= self.percent_dense*scene_extent)
|
||||||
# breakpoint()
|
|
||||||
new_xyz = self._xyz[selected_pts_mask]
|
new_xyz = self._xyz[selected_pts_mask]
|
||||||
# - 0.001 * self._xyz.grad[selected_pts_mask]
|
|
||||||
new_features_dc = self._features_dc[selected_pts_mask]
|
new_features_dc = self._features_dc[selected_pts_mask]
|
||||||
new_features_rest = self._features_rest[selected_pts_mask]
|
new_features_rest = self._features_rest[selected_pts_mask]
|
||||||
new_opacities = self._opacity[selected_pts_mask]
|
new_opacities = self._opacity[selected_pts_mask]
|
||||||
new_scaling = self._scaling[selected_pts_mask]
|
new_scaling = self._scaling[selected_pts_mask]
|
||||||
new_rotation = self._rotation[selected_pts_mask]
|
new_rotation = self._rotation[selected_pts_mask]
|
||||||
new_deformation_table = self._deformation_table[selected_pts_mask]
|
new_deformation_table = self._deformation_table[selected_pts_mask]
|
||||||
# if opt.add_point:
|
|
||||||
# selected_xyz, grow_xyz = self.add_point_by_mask(selected_pts_mask_grow.to(self.get_xyz.device), self.displacement_scale)
|
|
||||||
self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_deformation_table)
|
self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_deformation_table)
|
||||||
# print("被动增加点云:",selected_xyz.shape[0])
|
|
||||||
# print("主动增加点云:",selected_pts_mask.sum())
|
|
||||||
# if model_path is not None and iteration is not None:
|
|
||||||
# point = combine_pointcloud(self.get_xyz.detach().cpu().numpy(), new_xyz.detach().cpu().numpy(), selected_xyz.detach().cpu().numpy())
|
|
||||||
# write_path = os.path.join(model_path,"add_point_cloud")
|
|
||||||
# os.makedirs(write_path,exist_ok=True)
|
|
||||||
# o3d.io.write_point_cloud(os.path.join(write_path,f"iteration_{stage}{iteration}.ply"),point)
|
|
||||||
# print("write output.")
|
|
||||||
@property
|
@property
|
||||||
def get_aabb(self):
|
def get_aabb(self):
|
||||||
return self._deformation.get_aabb
|
return self._deformation.get_aabb
|
||||||
@ -505,23 +469,12 @@ class GaussianModel:
|
|||||||
mask_d = mask_c.all(dim=1)
|
mask_d = mask_c.all(dim=1)
|
||||||
final_point = final_point[mask_d]
|
final_point = final_point[mask_d]
|
||||||
|
|
||||||
# while (mask_d.sum()/final_point.shape[0])<0.5:
|
|
||||||
# perturb/=2
|
|
||||||
# displacements = torch.randn(selected_point.shape[0], 3).to(selected_point) * perturb
|
|
||||||
# final_point = selected_point + displacements
|
|
||||||
# mask_a = final_point<xyz_max
|
|
||||||
# mask_b = final_point>xyz_min
|
|
||||||
# mask_c = mask_a & mask_b
|
|
||||||
# mask_d = mask_c.all(dim=1)
|
|
||||||
# final_point = final_point[mask_d]
|
|
||||||
return final_point, mask_d
|
return final_point, mask_d
|
||||||
def add_point_by_mask(self, selected_pts_mask, perturb=0):
|
def add_point_by_mask(self, selected_pts_mask, perturb=0):
|
||||||
selected_xyz = self._xyz[selected_pts_mask]
|
selected_xyz = self._xyz[selected_pts_mask]
|
||||||
new_xyz, mask = self.get_displayment(selected_xyz, self.get_xyz.detach(),perturb)
|
new_xyz, mask = self.get_displayment(selected_xyz, self.get_xyz.detach(),perturb)
|
||||||
# displacements = torch.randn(selected_xyz.shape[0], 3).to(self._xyz) * perturb
|
|
||||||
|
|
||||||
# new_xyz = selected_xyz + displacements
|
|
||||||
# - 0.001 * self._xyz.grad[selected_pts_mask]
|
|
||||||
new_features_dc = self._features_dc[selected_pts_mask][mask]
|
new_features_dc = self._features_dc[selected_pts_mask][mask]
|
||||||
new_features_rest = self._features_rest[selected_pts_mask][mask]
|
new_features_rest = self._features_rest[selected_pts_mask][mask]
|
||||||
new_opacities = self._opacity[selected_pts_mask][mask]
|
new_opacities = self._opacity[selected_pts_mask][mask]
|
||||||
@ -532,56 +485,7 @@ class GaussianModel:
|
|||||||
|
|
||||||
self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_deformation_table)
|
self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_deformation_table)
|
||||||
return selected_xyz, new_xyz
|
return selected_xyz, new_xyz
|
||||||
def downsample_point(self, point_cloud):
|
|
||||||
if not hasattr(self,"voxel_size"):
|
|
||||||
self.voxel_size = 8
|
|
||||||
point_downsample = point_cloud
|
|
||||||
flag = False
|
|
||||||
while point_downsample.shape[0]>1000:
|
|
||||||
if flag:
|
|
||||||
self.voxel_size+=8
|
|
||||||
point_downsample = downsample_point_cloud_open3d(point_cloud,voxel_size=self.voxel_size)
|
|
||||||
flag = True
|
|
||||||
print("point size:",point_downsample.shape[0])
|
|
||||||
# downsampled_point_mask = torch.eq(point_downsample.view(1,-1,3), point_cloud.view(-1,1,3)).all(dim=1)
|
|
||||||
downsampled_point_index = find_indices_in_A(point_cloud, point_downsample)
|
|
||||||
downsampled_point_mask = torch.zeros((point_cloud.shape[0]), dtype=torch.bool).to(point_downsample.device)
|
|
||||||
downsampled_point_mask[downsampled_point_index]=True
|
|
||||||
return downsampled_point_mask
|
|
||||||
def grow(self, density_threshold=20, displacement_scale=20, model_path=None, iteration=None, stage=None):
|
|
||||||
if not hasattr(self,"voxel_size"):
|
|
||||||
self.voxel_size = 8
|
|
||||||
if not hasattr(self,"density_threshold"):
|
|
||||||
self.density_threshold = density_threshold
|
|
||||||
if not hasattr(self,"displacement_scale"):
|
|
||||||
self.displacement_scale = displacement_scale
|
|
||||||
flag = False
|
|
||||||
point_cloud = self.get_xyz.detach().cpu()
|
|
||||||
point_downsample = point_cloud.detach()
|
|
||||||
downsampled_point_index = self.downsample_point(point_downsample)
|
|
||||||
|
|
||||||
|
|
||||||
_, low_density_points, new_points, low_density_index = addpoint(point_cloud[downsampled_point_index],density_threshold=self.density_threshold,displacement_scale=self.displacement_scale,iter_pass=0)
|
|
||||||
if new_points.shape[0] < 100 :
|
|
||||||
self.density_threshold /= 2
|
|
||||||
self.displacement_scale /= 2
|
|
||||||
print("reduce diplacement_scale to: ",self.displacement_scale)
|
|
||||||
|
|
||||||
elif new_points.shape[0] == 0:
|
|
||||||
print("no point added")
|
|
||||||
return
|
|
||||||
global_mask = torch.zeros((point_cloud.shape[0]), dtype=torch.bool)
|
|
||||||
|
|
||||||
global_mask[downsampled_point_index] = low_density_index
|
|
||||||
global_mask
|
|
||||||
selected_xyz, new_xyz = self.add_point_by_mask(global_mask.to(self.get_xyz.device), self.displacement_scale)
|
|
||||||
print("point growing,add point num:",global_mask.sum())
|
|
||||||
if model_path is not None and iteration is not None:
|
|
||||||
point = combine_pointcloud(point_cloud, selected_xyz.detach().cpu().numpy(), new_xyz.detach().cpu().numpy())
|
|
||||||
write_path = os.path.join(model_path,"add_point_cloud")
|
|
||||||
os.makedirs(write_path,exist_ok=True)
|
|
||||||
o3d.io.write_point_cloud(os.path.join(write_path,f"iteration_{stage}{iteration}.ply"),point)
|
|
||||||
return
|
|
||||||
def prune(self, max_grad, min_opacity, extent, max_screen_size):
|
def prune(self, max_grad, min_opacity, extent, max_screen_size):
|
||||||
prune_mask = (self.get_opacity < min_opacity).squeeze()
|
prune_mask = (self.get_opacity < min_opacity).squeeze()
|
||||||
|
|
||||||
|
|||||||
@ -17,10 +17,7 @@ class DenseGrid(nn.Module):
|
|||||||
super(DenseGrid, self).__init__()
|
super(DenseGrid, self).__init__()
|
||||||
self.channels = channels
|
self.channels = channels
|
||||||
self.world_size = world_size
|
self.world_size = world_size
|
||||||
# self.xyz_max = xyz_max
|
|
||||||
# self.xyz_min = xyz_min
|
|
||||||
# self.register_buffer('xyz_min', torch.Tensor(xyz_min))
|
|
||||||
# self.register_buffer('xyz_max', torch.Tensor(xyz_max))
|
|
||||||
self.grid = nn.Parameter(torch.ones([1, channels, *world_size]))
|
self.grid = nn.Parameter(torch.ones([1, channels, *world_size]))
|
||||||
|
|
||||||
def forward(self, xyz):
|
def forward(self, xyz):
|
||||||
|
|||||||
@ -134,13 +134,9 @@ class Load_hyper_data(Dataset):
|
|||||||
if idx in self.map.keys():
|
if idx in self.map.keys():
|
||||||
return self.map[idx]
|
return self.map[idx]
|
||||||
camera = self.all_cam_params[idx]
|
camera = self.all_cam_params[idx]
|
||||||
# camera = self.video_path[idx]
|
|
||||||
w = self.image_one.size[0]
|
w = self.image_one.size[0]
|
||||||
h = self.image_one.size[1]
|
h = self.image_one.size[1]
|
||||||
# image = PILtoTorch(image,None)
|
|
||||||
# image = image.to(torch.float32)
|
|
||||||
time = self.video_time[idx]
|
time = self.video_time[idx]
|
||||||
# .astype(np.float32)
|
|
||||||
R = camera.orientation.T
|
R = camera.orientation.T
|
||||||
T = - camera.position @ R
|
T = - camera.position @ R
|
||||||
FovY = focal2fov(camera.focal_length, self.h)
|
FovY = focal2fov(camera.focal_length, self.h)
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
import open3d as o3d
|
|
||||||
import os
|
|
||||||
# 指定根目录路径
|
|
||||||
root_path = "data/dynerf/sear_steak/"
|
|
||||||
|
|
||||||
# 文件名
|
|
||||||
input_file = "points3D.ply"
|
|
||||||
output_file = "points3d_filtered.ply"
|
|
||||||
|
|
||||||
# 读取点云数据
|
|
||||||
point_cloud_before = o3d.io.read_point_cloud(os.path.join(root_path, input_file))
|
|
||||||
|
|
||||||
# 计算过滤前的点的数量
|
|
||||||
num_points_before = len(point_cloud_before.points)
|
|
||||||
|
|
||||||
# 计算过滤前的点云的边界框大小
|
|
||||||
bbox_before = point_cloud_before.get_axis_aligned_bounding_box()
|
|
||||||
bbox_size_before = bbox_before.get_max_bound() - bbox_before.get_min_bound()
|
|
||||||
|
|
||||||
# 进行离群点滤波
|
|
||||||
cl, ind = point_cloud_before.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)
|
|
||||||
|
|
||||||
# 创建一个新的点云对象,包含滤波后的点
|
|
||||||
filtered_point_cloud = point_cloud_before.select_by_index(ind)
|
|
||||||
|
|
||||||
# 保存滤波后的点云到新文件
|
|
||||||
o3d.io.write_point_cloud(os.path.join(root_path, output_file), filtered_point_cloud)
|
|
||||||
|
|
||||||
# 计算过滤后的点的数量
|
|
||||||
num_points_after = len(filtered_point_cloud.points)
|
|
||||||
|
|
||||||
# 计算边界框的大小
|
|
||||||
bbox = filtered_point_cloud.get_axis_aligned_bounding_box()
|
|
||||||
bbox_size = bbox.get_max_bound() - bbox.get_min_bound()
|
|
||||||
|
|
||||||
print(f"过滤前的点数: {num_points_before}")
|
|
||||||
print(f"过滤前的点云边界框大小: {bbox_size_before}")
|
|
||||||
print(f"过滤后的点数: {num_points_after}")
|
|
||||||
print(f"过滤后的点云边界框大小: {bbox_size}")
|
|
||||||
print(f"离群点过滤完成,结果已保存到 {output_file}")
|
|
||||||
@ -2,24 +2,14 @@ import open3d as o3d
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
def grow_sparse_regions(input_file, output_file):
|
def grow_sparse_regions(input_file, output_file):
|
||||||
# 读取输入的ply文件
|
|
||||||
pcd = o3d.io.read_point_cloud(input_file)
|
pcd = o3d.io.read_point_cloud(input_file)
|
||||||
|
|
||||||
# 计算点云的密度
|
|
||||||
densities = o3d.geometry.PointCloud.compute_nearest_neighbor_distance(pcd)
|
densities = o3d.geometry.PointCloud.compute_nearest_neighbor_distance(pcd)
|
||||||
avg_density = np.average(densities)
|
avg_density = np.average(densities)
|
||||||
print(f"Average density: {avg_density}")
|
print(f"Average density: {avg_density}")
|
||||||
|
sparse_indices = np.where(densities > avg_density * 1.2)[0]
|
||||||
# 找到稀疏部分
|
|
||||||
sparse_indices = np.where(densities > avg_density * 1.2)[0] # 这里我们假设稀疏部分的密度大于平均密度的1.2倍
|
|
||||||
sparse_points = np.asarray(pcd.points)[sparse_indices]
|
sparse_points = np.asarray(pcd.points)[sparse_indices]
|
||||||
breakpoint()
|
|
||||||
# 复制并增长稀疏部分
|
|
||||||
# for _ in range(5): # 这里我们假设每个稀疏点复制5次
|
|
||||||
# pcd.points.extend(sparse_points)
|
|
||||||
|
|
||||||
# 将结果保存到输入的路径中
|
|
||||||
o3d.io.write_point_cloud(output_file, pcd)
|
o3d.io.write_point_cloud(output_file, pcd)
|
||||||
|
|
||||||
# 使用函数
|
|
||||||
grow_sparse_regions("data/hypernerf/vrig/chickchicken/dense_downsample.ply", "data/hypernerf/interp/chickchicken/dense_downsample.ply")
|
grow_sparse_regions("data/hypernerf/vrig/chickchicken/dense_downsample.ply", "data/hypernerf/interp/chickchicken/dense_downsample.ply")
|
||||||
@ -41,7 +41,6 @@ for jsonfile in tqdm(cameras):
|
|||||||
image_size = cams[0]['image_size']
|
image_size = cams[0]['image_size']
|
||||||
image = Image.open(os.path.join(image_dir,images[0]))
|
image = Image.open(os.path.join(image_dir,images[0]))
|
||||||
size = image.size
|
size = image.size
|
||||||
# breakpoint()
|
|
||||||
object_images_file = open(os.path.join(colmap_dir,"images.txt"),"w")
|
object_images_file = open(os.path.join(colmap_dir,"images.txt"),"w")
|
||||||
object_cameras_file = open(os.path.join(colmap_dir,"cameras.txt"),"w")
|
object_cameras_file = open(os.path.join(colmap_dir,"cameras.txt"),"w")
|
||||||
|
|
||||||
@ -50,19 +49,13 @@ cnt=0
|
|||||||
sizes=2
|
sizes=2
|
||||||
while len(cams)//sizes > 200:
|
while len(cams)//sizes > 200:
|
||||||
sizes += 1
|
sizes += 1
|
||||||
# breakpoint()
|
|
||||||
for cam, image in zip(cams, images):
|
for cam, image in zip(cams, images):
|
||||||
cnt+=1
|
cnt+=1
|
||||||
|
|
||||||
# print(image)
|
|
||||||
# breakpoint()
|
|
||||||
if cnt % sizes != 0:
|
if cnt % sizes != 0:
|
||||||
continue
|
continue
|
||||||
# print("begin to write")
|
|
||||||
R = np.array(cam['orientation']).T
|
R = np.array(cam['orientation']).T
|
||||||
# breakpoint()
|
|
||||||
T = -np.array(cam['position'])@R
|
T = -np.array(cam['position'])@R
|
||||||
# T = -np.matmul(R,T)
|
|
||||||
|
|
||||||
T = [str(i) for i in T]
|
T = [str(i) for i in T]
|
||||||
qevc = [str(i) for i in rotmat2qvec(R.T)]
|
qevc = [str(i) for i in rotmat2qvec(R.T)]
|
||||||
@ -73,7 +66,6 @@ for cam, image in zip(cams, images):
|
|||||||
shutil.copy(os.path.join(image_dir,image),os.path.join(imagecolmap_dir,image))
|
shutil.copy(os.path.join(image_dir,image),os.path.join(imagecolmap_dir,image))
|
||||||
print(idx)
|
print(idx)
|
||||||
# write camera infomation.
|
# write camera infomation.
|
||||||
# print(1,"SIMPLE_PINHOLE",image_size[0],image_size[1],focal[0],image_sizep0/2,image_size[1]/2,file=object_cameras_file)
|
|
||||||
object_point_file = open(os.path.join(colmap_dir,"points3D.txt"),"w")
|
object_point_file = open(os.path.join(colmap_dir,"points3D.txt"),"w")
|
||||||
|
|
||||||
object_cameras_file.close()
|
object_cameras_file.close()
|
||||||
|
|||||||
@ -98,17 +98,6 @@ H, W, focal = poses[0, :, -1]
|
|||||||
focal = focal/2
|
focal = focal/2
|
||||||
focal = [focal, focal]
|
focal = [focal, focal]
|
||||||
poses = np.concatenate([poses[..., 1:2], -poses[..., :1], poses[..., 2:4]], -1)
|
poses = np.concatenate([poses[..., 1:2], -poses[..., :1], poses[..., 2:4]], -1)
|
||||||
# poses, _ = center_poses(
|
|
||||||
# poses, blender2opencv
|
|
||||||
# ) # Re-center poses so that the average is near the center.
|
|
||||||
# near_original = near_fars.min()
|
|
||||||
# scale_factor = near_original * 0.75
|
|
||||||
# near_fars /= (
|
|
||||||
# scale_factor # rescale nearest plane so that it is at z = 4/3.
|
|
||||||
# )
|
|
||||||
# poses[..., 3] /= scale_factor
|
|
||||||
# Sample N_views poses for validation - NeRF-like camera trajectory.
|
|
||||||
# val_poses = directions
|
|
||||||
videos = glob.glob(os.path.join(root_dir, "cam[0-9][0-9]"))
|
videos = glob.glob(os.path.join(root_dir, "cam[0-9][0-9]"))
|
||||||
videos = sorted(videos)
|
videos = sorted(videos)
|
||||||
image_paths = []
|
image_paths = []
|
||||||
@ -132,8 +121,6 @@ for index, image in enumerate(image_paths):
|
|||||||
shutil.copy(image,goal_path)
|
shutil.copy(image,goal_path)
|
||||||
|
|
||||||
print(poses)
|
print(poses)
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
# write image information.
|
# write image information.
|
||||||
object_images_file = open(os.path.join(colmap_dir,"images.txt"),"w")
|
object_images_file = open(os.path.join(colmap_dir,"images.txt"),"w")
|
||||||
for idx, pose in enumerate(poses):
|
for idx, pose in enumerate(poses):
|
||||||
@ -147,15 +134,12 @@ for idx, pose in enumerate(poses):
|
|||||||
R = np.linalg.inv(R)
|
R = np.linalg.inv(R)
|
||||||
T = -np.matmul(R,T)
|
T = -np.matmul(R,T)
|
||||||
T = [str(i) for i in T]
|
T = [str(i) for i in T]
|
||||||
# T = ["%.3f"%i for i in pose[:3,3]]
|
|
||||||
qevc = [str(i) for i in rotmat2qvec(R)]
|
qevc = [str(i) for i in rotmat2qvec(R)]
|
||||||
# breakpoint()
|
|
||||||
print(idx+1," ".join(qevc)," ".join(T),1,image_name_list[idx],"\n",file=object_images_file)
|
print(idx+1," ".join(qevc)," ".join(T),1,image_name_list[idx],"\n",file=object_images_file)
|
||||||
# breakpoint()
|
|
||||||
|
|
||||||
# write camera infomation.
|
# write camera infomation.
|
||||||
object_cameras_file = open(os.path.join(colmap_dir,"cameras.txt"),"w")
|
object_cameras_file = open(os.path.join(colmap_dir,"cameras.txt"),"w")
|
||||||
print(1,"SIMPLE_PINHOLE",1352,1014,focal[0],1352/2,1014/2,file=object_cameras_file)
|
print(1,"SIMPLE_PINHOLE",1352,1014,focal[0],1352/2,1014/2,file=object_cameras_file) #
|
||||||
object_point_file = open(os.path.join(colmap_dir,"points3D.txt"),"w")
|
object_point_file = open(os.path.join(colmap_dir,"points3D.txt"),"w")
|
||||||
|
|
||||||
object_cameras_file.close()
|
object_cameras_file.close()
|
||||||
|
|||||||
@ -2,22 +2,15 @@ import open3d as o3d
|
|||||||
import os
|
import os
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
def merge_point_clouds(directory, output_file):
|
def merge_point_clouds(directory, output_file):
|
||||||
# 初始化一个空的点云
|
|
||||||
merged_pcd = o3d.geometry.PointCloud()
|
merged_pcd = o3d.geometry.PointCloud()
|
||||||
|
|
||||||
# 遍历文件夹下的所有文件
|
|
||||||
for filename in tqdm(os.listdir(directory)):
|
for filename in tqdm(os.listdir(directory)):
|
||||||
if filename.endswith('.ply'):
|
if filename.endswith('.ply'):
|
||||||
# 读取点云文件
|
|
||||||
pcd = o3d.io.read_point_cloud(os.path.join(directory, filename))
|
pcd = o3d.io.read_point_cloud(os.path.join(directory, filename))
|
||||||
# 将点云合并
|
|
||||||
merged_pcd += pcd
|
merged_pcd += pcd
|
||||||
|
|
||||||
# 移除位置相同的点
|
|
||||||
merged_pcd = merged_pcd.remove_duplicate_points()
|
merged_pcd = merged_pcd.remove_duplicate_points()
|
||||||
|
|
||||||
# 将合并后的点云输出到一个文件中
|
|
||||||
o3d.io.write_point_cloud(output_file, merged_pcd)
|
o3d.io.write_point_cloud(output_file, merged_pcd)
|
||||||
|
|
||||||
# 使用函数
|
|
||||||
merge_point_clouds("point_clouds_directory", "merged.ply")
|
merge_point_clouds("point_clouds_directory", "merged.ply")
|
||||||
39
test.py
39
test.py
@ -1,39 +0,0 @@
|
|||||||
import cv2
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
def sorted_alphanumeric(data):
|
|
||||||
"""
|
|
||||||
对给定的数据进行字母数字排序(考虑数字的数值大小)
|
|
||||||
"""
|
|
||||||
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
|
||||||
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
|
||||||
return sorted(data, key=alphanum_key)
|
|
||||||
def create_video_from_images(folder_path, output_file, frame_rate=30, img_size=None):
|
|
||||||
images = [img for img in os.listdir(folder_path) if img.endswith(".jpg") or img.endswith(".png")]
|
|
||||||
images = sorted_alphanumeric(images) # 使用自定义的排序函数
|
|
||||||
|
|
||||||
# 获取第一张图片的尺寸
|
|
||||||
frame = cv2.imread(os.path.join(folder_path, images[0]))
|
|
||||||
height, width, layers = frame.shape
|
|
||||||
|
|
||||||
# 如果指定了img_size,则调整尺寸
|
|
||||||
if img_size is not None:
|
|
||||||
width, height = img_size
|
|
||||||
|
|
||||||
# 定义视频编码和创建VideoWriter对象
|
|
||||||
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 可以更改为其他编码器
|
|
||||||
video = cv2.VideoWriter(output_file, fourcc, frame_rate, (width, height))
|
|
||||||
|
|
||||||
for image in images:
|
|
||||||
img = cv2.imread(os.path.join(folder_path, image))
|
|
||||||
if img_size is not None:
|
|
||||||
img = cv2.resize(img, img_size)
|
|
||||||
video.write(img)
|
|
||||||
|
|
||||||
cv2.destroyAllWindows()
|
|
||||||
video.release()
|
|
||||||
|
|
||||||
# 使用示例
|
|
||||||
folder_path = 'output/editing_render' # 替换为您的图片文件夹路径
|
|
||||||
output_file = 'output_video.mp4' # 输出视频文件名
|
|
||||||
create_video_from_images(folder_path, output_file)
|
|
||||||
@ -7,60 +7,34 @@ import open3d as o3d
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from torch_cluster import grid_cluster
|
from torch_cluster import grid_cluster
|
||||||
def voxel_down_sample_custom(points, voxel_size):
|
def voxel_down_sample_custom(points, voxel_size):
|
||||||
# 将点云归一化到体素网格
|
|
||||||
voxel_grid = torch.floor(points / voxel_size)
|
voxel_grid = torch.floor(points / voxel_size)
|
||||||
|
|
||||||
# 找到唯一的体素,并获取它们在原始体素网格中的索引
|
|
||||||
unique_voxels, inverse_indices = torch.unique(voxel_grid, dim=0, return_inverse=True)
|
unique_voxels, inverse_indices = torch.unique(voxel_grid, dim=0, return_inverse=True)
|
||||||
|
|
||||||
# 创建一个新的点云,其中每个点是其对应体素中所有点的平均值
|
|
||||||
new_points = torch.zeros_like(unique_voxels)
|
new_points = torch.zeros_like(unique_voxels)
|
||||||
new_points_count = torch.zeros(unique_voxels.size(0), dtype=torch.long)
|
new_points_count = torch.zeros(unique_voxels.size(0), dtype=torch.long)
|
||||||
# for i in tqdm(range(points.size(0))):
|
|
||||||
new_points[inverse_indices] = points
|
new_points[inverse_indices] = points
|
||||||
# new_points_count[inverse_indices[i]] += 1
|
|
||||||
# new_points /= new_points_count.unsqueeze(-1)
|
|
||||||
|
|
||||||
return new_points, inverse_indices
|
return new_points, inverse_indices
|
||||||
def downsample_point_cloud(points, ratio):
|
def downsample_point_cloud(points, ratio):
|
||||||
# 创建一个TensorDataset
|
|
||||||
dataset = TensorDataset(points)
|
dataset = TensorDataset(points)
|
||||||
|
|
||||||
# 计算下采样后的点的数量
|
|
||||||
num_points = len(dataset)
|
num_points = len(dataset)
|
||||||
num_downsampled_points = int(num_points * ratio)
|
num_downsampled_points = int(num_points * ratio)
|
||||||
|
|
||||||
# 使用random_split进行下采样
|
|
||||||
downsampled_dataset, _ = random_split(dataset, [num_downsampled_points, num_points - num_downsampled_points])
|
downsampled_dataset, _ = random_split(dataset, [num_downsampled_points, num_points - num_downsampled_points])
|
||||||
|
|
||||||
# 获取下采样后的点的index和点云矩阵
|
|
||||||
indices = torch.tensor([i for i, _ in enumerate(downsampled_dataset)])
|
indices = torch.tensor([i for i, _ in enumerate(downsampled_dataset)])
|
||||||
downsampled_points = torch.stack([x for x, in downsampled_dataset])
|
downsampled_points = torch.stack([x for x, in downsampled_dataset])
|
||||||
|
|
||||||
return indices, downsampled_points
|
return indices, downsampled_points
|
||||||
|
|
||||||
def downsample_point_cloud_open3d(points, voxel_size):
|
def downsample_point_cloud_open3d(points, voxel_size):
|
||||||
# 创建一个点云对象
|
|
||||||
|
|
||||||
downsampled_pcd, inverse_indices = voxel_down_sample_custom(points, voxel_size)
|
downsampled_pcd, inverse_indices = voxel_down_sample_custom(points, voxel_size)
|
||||||
downsampled_points = downsampled_pcd
|
downsampled_points = downsampled_pcd
|
||||||
# 获取下采样后的点云矩阵
|
|
||||||
|
|
||||||
return torch.tensor(downsampled_points)
|
return torch.tensor(downsampled_points)
|
||||||
def downsample_point_cloud_cluster(points, voxel_size):
|
def downsample_point_cloud_cluster(points, voxel_size):
|
||||||
# 创建一个点云对象
|
|
||||||
cluster = grid_cluster(points, size=torch.tensor([1,1,1]))
|
cluster = grid_cluster(points, size=torch.tensor([1,1,1]))
|
||||||
|
|
||||||
# 获取下采样后的点云矩阵
|
|
||||||
# downsampled_points = np.asarray(downsampled_pcd.points)
|
|
||||||
|
|
||||||
return cluster, points
|
return cluster, points
|
||||||
import torch
|
import torch
|
||||||
from sklearn.neighbors import NearestNeighbors
|
from sklearn.neighbors import NearestNeighbors
|
||||||
|
|
||||||
def upsample_point_cloud(points, density_threshold, displacement_scale, iter_pass):
|
def upsample_point_cloud(points, density_threshold, displacement_scale, iter_pass):
|
||||||
# 计算每个点的密度
|
|
||||||
# breakpoint()
|
|
||||||
try:
|
try:
|
||||||
nbrs = NearestNeighbors(n_neighbors=2+iter_pass, algorithm='ball_tree').fit(points)
|
nbrs = NearestNeighbors(n_neighbors=2+iter_pass, algorithm='ball_tree').fit(points)
|
||||||
distances, indices = nbrs.kneighbors(points)
|
distances, indices = nbrs.kneighbors(points)
|
||||||
@ -68,88 +42,52 @@ def upsample_point_cloud(points, density_threshold, displacement_scale, iter_pas
|
|||||||
print("no point added")
|
print("no point added")
|
||||||
return points, torch.tensor([]), torch.tensor([]), torch.zeros((points.shape[0]), dtype=torch.bool)
|
return points, torch.tensor([]), torch.tensor([]), torch.zeros((points.shape[0]), dtype=torch.bool)
|
||||||
|
|
||||||
# 找出密度低的点
|
|
||||||
low_density_points = points[distances[:,1] > density_threshold]
|
low_density_points = points[distances[:,1] > density_threshold]
|
||||||
low_density_index = distances[:,1] > density_threshold
|
low_density_index = distances[:,1] > density_threshold
|
||||||
low_density_index = torch.from_numpy(low_density_index)
|
low_density_index = torch.from_numpy(low_density_index)
|
||||||
# 复制这些点并添加随机位移
|
|
||||||
num_points = low_density_points.shape[0]
|
num_points = low_density_points.shape[0]
|
||||||
displacements = torch.randn(num_points, 3) * displacement_scale
|
displacements = torch.randn(num_points, 3) * displacement_scale
|
||||||
new_points = low_density_points + displacements
|
new_points = low_density_points + displacements
|
||||||
# 返回新的点云矩阵
|
|
||||||
return points, low_density_points, new_points, low_density_index
|
return points, low_density_points, new_points, low_density_index
|
||||||
|
|
||||||
|
|
||||||
def visualize_point_cloud(points, low_density_points, new_points):
|
def visualize_point_cloud(points, low_density_points, new_points):
|
||||||
# 创建一个点云对象
|
|
||||||
pcd = o3d.geometry.PointCloud()
|
pcd = o3d.geometry.PointCloud()
|
||||||
|
|
||||||
# 给被选中的点云添加一个小的偏移量
|
|
||||||
low_density_points += 0.01
|
low_density_points += 0.01
|
||||||
|
|
||||||
# 将所有的点合并到一起
|
|
||||||
all_points = np.concatenate([points, low_density_points, new_points], axis=0)
|
all_points = np.concatenate([points, low_density_points, new_points], axis=0)
|
||||||
pcd.points = o3d.utility.Vector3dVector(all_points)
|
pcd.points = o3d.utility.Vector3dVector(all_points)
|
||||||
|
|
||||||
# 创建颜色数组
|
|
||||||
colors = np.zeros((all_points.shape[0], 3))
|
colors = np.zeros((all_points.shape[0], 3))
|
||||||
colors[:points.shape[0]] = [0, 0, 0] # 黑色表示初始化的点云
|
colors[:points.shape[0]] = [0, 0, 0]
|
||||||
colors[points.shape[0]:points.shape[0]+low_density_points.shape[0]] = [1, 0, 0] # 红色表示被选中的点云
|
colors[points.shape[0]:points.shape[0]+low_density_points.shape[0]] = [1, 0, 0]
|
||||||
colors[points.shape[0]+low_density_points.shape[0]:] = [0, 1, 0] # 绿色表示增长的点云
|
colors[points.shape[0]+low_density_points.shape[0]:] = [0, 1, 0]
|
||||||
pcd.colors = o3d.utility.Vector3dVector(colors)
|
pcd.colors = o3d.utility.Vector3dVector(colors)
|
||||||
|
|
||||||
# 显示点云
|
|
||||||
o3d.visualization.draw_geometries([pcd])
|
o3d.visualization.draw_geometries([pcd])
|
||||||
def combine_pointcloud(points, low_density_points, new_points):
|
def combine_pointcloud(points, low_density_points, new_points):
|
||||||
pcd = o3d.geometry.PointCloud()
|
pcd = o3d.geometry.PointCloud()
|
||||||
|
|
||||||
# 给被选中的点云添加一个小的偏移量
|
|
||||||
low_density_points += 0.01
|
low_density_points += 0.01
|
||||||
new_points -= 0.01
|
new_points -= 0.01
|
||||||
# 将所有的点合并到一起
|
|
||||||
all_points = np.concatenate([points, low_density_points, new_points], axis=0)
|
all_points = np.concatenate([points, low_density_points, new_points], axis=0)
|
||||||
pcd.points = o3d.utility.Vector3dVector(all_points)
|
pcd.points = o3d.utility.Vector3dVector(all_points)
|
||||||
|
|
||||||
# 创建颜色数组
|
|
||||||
colors = np.zeros((all_points.shape[0], 3))
|
colors = np.zeros((all_points.shape[0], 3))
|
||||||
colors[:points.shape[0]] = [0, 0, 0] # 黑色表示初始化的点云
|
colors[:points.shape[0]] = [0, 0, 0]
|
||||||
colors[points.shape[0]:points.shape[0]+low_density_points.shape[0]] = [1, 0, 0] # 红色表示被选中的点云
|
colors[points.shape[0]:points.shape[0]+low_density_points.shape[0]] = [1, 0, 0]
|
||||||
colors[points.shape[0]+low_density_points.shape[0]:] = [0, 1, 0] # 绿色表示增长的点云
|
colors[points.shape[0]+low_density_points.shape[0]:] = [0, 1, 0]
|
||||||
pcd.colors = o3d.utility.Vector3dVector(colors)
|
pcd.colors = o3d.utility.Vector3dVector(colors)
|
||||||
return pcd
|
return pcd
|
||||||
def addpoint(point_cloud,density_threshold,displacement_scale, iter_pass,):
|
def addpoint(point_cloud,density_threshold,displacement_scale, iter_pass,):
|
||||||
# density_threshold: 密度的阈值,越大能筛选出越稀疏的点。
|
|
||||||
# displacement_scale: 在以displacement_scale的圆心内随机生成点
|
|
||||||
|
|
||||||
points, low_density_points, new_points, low_density_index = upsample_point_cloud(point_cloud,density_threshold,displacement_scale, iter_pass)
|
points, low_density_points, new_points, low_density_index = upsample_point_cloud(point_cloud,density_threshold,displacement_scale, iter_pass)
|
||||||
# breakpoint()
|
|
||||||
# breakpoint()
|
|
||||||
print("low_density_points",low_density_points.shape[0])
|
print("low_density_points",low_density_points.shape[0])
|
||||||
|
|
||||||
|
|
||||||
return point_cloud, low_density_points, new_points, low_density_index
|
return point_cloud, low_density_points, new_points, low_density_index
|
||||||
def find_point_indices(origin_point, goal_point):
|
def find_point_indices(origin_point, goal_point):
|
||||||
indices = torch.nonzero((origin_point[:, None] == goal_point).all(-1), as_tuple=True)[0]
|
indices = torch.nonzero((origin_point[:, None] == goal_point).all(-1), as_tuple=True)[0]
|
||||||
return indices
|
return indices
|
||||||
def find_indices_in_A(A, B):
|
def find_indices_in_A(A, B):
|
||||||
"""
|
|
||||||
找出子集矩阵 B 中每个点在点云矩阵 A 中的索引 u。
|
|
||||||
|
|
||||||
参数:
|
|
||||||
A (torch.Tensor): 点云矩阵 A,大小为 [N, 3]。
|
|
||||||
B (torch.Tensor): 子集矩阵 B,大小为 [M, 3]。
|
|
||||||
|
|
||||||
返回:
|
|
||||||
torch.Tensor: 包含 B 中每个点在 A 中的索引 u 的张量,形状为 (M,)。
|
|
||||||
"""
|
|
||||||
is_equal = torch.eq(B.view(1, -1, 3), A.view(-1, 1, 3))
|
is_equal = torch.eq(B.view(1, -1, 3), A.view(-1, 1, 3))
|
||||||
u_indices = torch.nonzero(is_equal, as_tuple=False)[:, 0]
|
u_indices = torch.nonzero(is_equal, as_tuple=False)[:, 0]
|
||||||
return torch.unique(u_indices)
|
return torch.unique(u_indices)
|
||||||
if __name__ =="__main__":
|
if __name__ =="__main__":
|
||||||
#
|
|
||||||
from time import time
|
from time import time
|
||||||
pass_=0
|
pass_=0
|
||||||
# filename=f"pointcloud/pass_{pass_}.ply"
|
|
||||||
filename = "point_cloud.ply"
|
filename = "point_cloud.ply"
|
||||||
pcd = o3d.io.read_point_cloud(filename)
|
pcd = o3d.io.read_point_cloud(filename)
|
||||||
point_cloud = torch.tensor(pcd.points)
|
point_cloud = torch.tensor(pcd.points)
|
||||||
@ -170,7 +108,6 @@ if __name__ =="__main__":
|
|||||||
flag = True
|
flag = True
|
||||||
|
|
||||||
print("point size:",point_downsample.shape[0])
|
print("point size:",point_downsample.shape[0])
|
||||||
# downsampled_point_index = find_point_indices(point_cloud, point_downsample)
|
|
||||||
downsampled_point_index = find_indices_in_A(point_cloud, point_downsample)
|
downsampled_point_index = find_indices_in_A(point_cloud, point_downsample)
|
||||||
print("selected_num",point_cloud[downsampled_point_index].shape[0])
|
print("selected_num",point_cloud[downsampled_point_index].shape[0])
|
||||||
_, low_density_points, new_points, low_density_index = addpoint(point_cloud[downsampled_point_index],density_threshold=density_threshold,displacement_scale=displacement_scale,iter_pass=0)
|
_, low_density_points, new_points, low_density_index = addpoint(point_cloud[downsampled_point_index],density_threshold=density_threshold,displacement_scale=displacement_scale,iter_pass=0)
|
||||||
@ -188,9 +125,7 @@ if __name__ =="__main__":
|
|||||||
if low_density_points.shape[0] == 0:
|
if low_density_points.shape[0] == 0:
|
||||||
print("no more points.")
|
print("no more points.")
|
||||||
continue
|
continue
|
||||||
# breakpoint()
|
|
||||||
point = combine_pointcloud(point_cloud, low_density_points, new_points)
|
point = combine_pointcloud(point_cloud, low_density_points, new_points)
|
||||||
point_cloud = torch.tensor(point.points)
|
point_cloud = torch.tensor(point.points)
|
||||||
o3d.io.write_point_cloud(f"pointcloud/pass_{i}.ply",point)
|
o3d.io.write_point_cloud(f"pointcloud/pass_{i}.ply",point)
|
||||||
# visualize_qpoint_cloud( point_cloud, low_density_points, new_points)
|
|
||||||
|
|
||||||
@ -3,15 +3,12 @@ from scipy.spatial.transform import Rotation as R
|
|||||||
from scene.utils import Camera
|
from scene.utils import Camera
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
def rotation_matrix_to_quaternion(rotation_matrix):
|
def rotation_matrix_to_quaternion(rotation_matrix):
|
||||||
"""将旋转矩阵转换为四元数"""
|
|
||||||
return R.from_matrix(rotation_matrix).as_quat()
|
return R.from_matrix(rotation_matrix).as_quat()
|
||||||
|
|
||||||
def quaternion_to_rotation_matrix(quat):
|
def quaternion_to_rotation_matrix(quat):
|
||||||
"""将四元数转换为旋转矩阵"""
|
|
||||||
return R.from_quat(quat).as_matrix()
|
return R.from_quat(quat).as_matrix()
|
||||||
|
|
||||||
def quaternion_slerp(q1, q2, t):
|
def quaternion_slerp(q1, q2, t):
|
||||||
"""在两个四元数之间进行球面线性插值(SLERP)"""
|
|
||||||
# 计算两个四元数之间的点积
|
# 计算两个四元数之间的点积
|
||||||
dot = np.dot(q1, q2)
|
dot = np.dot(q1, q2)
|
||||||
|
|
||||||
@ -32,13 +29,10 @@ def quaternion_slerp(q1, q2, t):
|
|||||||
return np.cos(theta) * q1 + np.sin(theta) * q3
|
return np.cos(theta) * q1 + np.sin(theta) * q3
|
||||||
|
|
||||||
def bezier_interpolation(p1, p2, t):
|
def bezier_interpolation(p1, p2, t):
|
||||||
"""在两点之间使用贝塞尔曲线进行插值"""
|
|
||||||
return (1 - t) * p1 + t * p2
|
return (1 - t) * p1 + t * p2
|
||||||
def linear_interpolation(v1, v2, t):
|
def linear_interpolation(v1, v2, t):
|
||||||
"""线性插值"""
|
|
||||||
return (1 - t) * v1 + t * v2
|
return (1 - t) * v1 + t * v2
|
||||||
def smooth_camera_poses(cameras, num_interpolations=5):
|
def smooth_camera_poses(cameras, num_interpolations=5):
|
||||||
"""对一系列相机位姿进行平滑处理,通过在每对位姿之间插入额外的位姿"""
|
|
||||||
smoothed_cameras = []
|
smoothed_cameras = []
|
||||||
smoothed_times = []
|
smoothed_times = []
|
||||||
total_poses = len(cameras) - 1 + (len(cameras) - 1) * num_interpolations
|
total_poses = len(cameras) - 1 + (len(cameras) - 1) * num_interpolations
|
||||||
@ -48,44 +42,26 @@ def smooth_camera_poses(cameras, num_interpolations=5):
|
|||||||
cam1 = cameras[i]
|
cam1 = cameras[i]
|
||||||
cam2 = cameras[i + 1]
|
cam2 = cameras[i + 1]
|
||||||
|
|
||||||
# 将旋转矩阵转换为四元数
|
|
||||||
quat1 = rotation_matrix_to_quaternion(cam1.orientation)
|
quat1 = rotation_matrix_to_quaternion(cam1.orientation)
|
||||||
quat2 = rotation_matrix_to_quaternion(cam2.orientation)
|
quat2 = rotation_matrix_to_quaternion(cam2.orientation)
|
||||||
|
|
||||||
for j in range(num_interpolations + 1):
|
for j in range(num_interpolations + 1):
|
||||||
t = j / (num_interpolations + 1)
|
t = j / (num_interpolations + 1)
|
||||||
|
|
||||||
# 插值方向
|
|
||||||
interp_orientation_quat = quaternion_slerp(quat1, quat2, t)
|
interp_orientation_quat = quaternion_slerp(quat1, quat2, t)
|
||||||
interp_orientation_matrix = quaternion_to_rotation_matrix(interp_orientation_quat)
|
interp_orientation_matrix = quaternion_to_rotation_matrix(interp_orientation_quat)
|
||||||
|
|
||||||
# 插值位置
|
|
||||||
interp_position = linear_interpolation(cam1.position, cam2.position, t)
|
interp_position = linear_interpolation(cam1.position, cam2.position, t)
|
||||||
|
|
||||||
# 计算插值时间戳
|
|
||||||
interp_time = i*10 / (len(cameras) - 1) + time_increment * j
|
interp_time = i*10 / (len(cameras) - 1) + time_increment * j
|
||||||
|
|
||||||
# 添加新的相机位姿和时间戳
|
|
||||||
newcam = deepcopy(cam1)
|
newcam = deepcopy(cam1)
|
||||||
newcam.orientation = interp_orientation_matrix
|
newcam.orientation = interp_orientation_matrix
|
||||||
newcam.position = interp_position
|
newcam.position = interp_position
|
||||||
smoothed_cameras.append(newcam)
|
smoothed_cameras.append(newcam)
|
||||||
smoothed_times.append(interp_time)
|
smoothed_times.append(interp_time)
|
||||||
|
|
||||||
# 添加最后一个原始位姿和时间戳
|
|
||||||
smoothed_cameras.append(cameras[-1])
|
smoothed_cameras.append(cameras[-1])
|
||||||
smoothed_times.append(1.0)
|
smoothed_times.append(1.0)
|
||||||
print(smoothed_times)
|
print(smoothed_times)
|
||||||
return smoothed_cameras, smoothed_times
|
return smoothed_cameras, smoothed_times
|
||||||
|
|
||||||
# # 示例:使用两个相机位姿
|
|
||||||
# cam1 = Camera(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), np.array([0, 0, 0]))
|
|
||||||
# cam2 = Camera(np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]), np.array([1, 1, 1]))
|
|
||||||
|
|
||||||
# # 应用平滑处理
|
|
||||||
# smoothed_cameras = smooth_camera_poses([cam1, cam2], num_interpolations=5)
|
|
||||||
|
|
||||||
# # 打印结果
|
|
||||||
# for cam in smoothed_cameras:
|
|
||||||
# print("Orientation:\n", cam.orientation)
|
|
||||||
# print("Position:", cam.position)
|
|
||||||
|
|||||||
@ -11,15 +11,8 @@ def get_state_at_time(pc,viewpoint_camera):
|
|||||||
scales = pc._scaling
|
scales = pc._scaling
|
||||||
rotations = pc._rotation
|
rotations = pc._rotation
|
||||||
cov3D_precomp = None
|
cov3D_precomp = None
|
||||||
|
|
||||||
# time0 = get_time()
|
|
||||||
# means3D_deform, scales_deform, rotations_deform, opacity_deform = pc._deformation(means3D[deformation_point], scales[deformation_point],
|
|
||||||
# rotations[deformation_point], opacity[deformation_point],
|
|
||||||
# time[deformation_point])
|
|
||||||
means3D_final, scales_final, rotations_final, opacity_final, shs_final = pc._deformation(means3D, scales,
|
means3D_final, scales_final, rotations_final, opacity_final, shs_final = pc._deformation(means3D, scales,
|
||||||
rotations, opacity, shs,
|
rotations, opacity, shs,
|
||||||
time)
|
time)
|
||||||
# scales_final = pc.scaling_activation(scales_final)
|
|
||||||
# rotations_final = pc.rotation_activation(rotations_final)
|
|
||||||
# opacity = pc.opacity_activation(opacity_final)
|
|
||||||
return means3D_final, scales_final, rotations_final, opacity, shs_final
|
return means3D_final, scales_final, rotations_final, opacity, shs_final
|
||||||
@ -25,26 +25,17 @@ def render_training_image(scene, gaussians, viewpoints, render_func, pipe, backg
|
|||||||
gt_np = viewpoint['image'].permute(1,2,0).cpu().numpy()
|
gt_np = viewpoint['image'].permute(1,2,0).cpu().numpy()
|
||||||
else:
|
else:
|
||||||
gt_np = viewpoint.original_image.permute(1,2,0).cpu().numpy()
|
gt_np = viewpoint.original_image.permute(1,2,0).cpu().numpy()
|
||||||
image_np = image.permute(1, 2, 0).cpu().numpy() # 转换通道顺序为 (H, W, 3)
|
image_np = image.permute(1, 2, 0).cpu().numpy() # (H, W, 3)
|
||||||
depth_np = depth.permute(1, 2, 0).cpu().numpy()
|
depth_np = depth.permute(1, 2, 0).cpu().numpy()
|
||||||
depth_np /= depth_np.max()
|
depth_np /= depth_np.max()
|
||||||
depth_np = np.repeat(depth_np, 3, axis=2)
|
depth_np = np.repeat(depth_np, 3, axis=2)
|
||||||
image_np = np.concatenate((gt_np, image_np, depth_np), axis=1)
|
image_np = np.concatenate((gt_np, image_np, depth_np), axis=1)
|
||||||
image_with_labels = Image.fromarray((np.clip(image_np,0,1) * 255).astype('uint8')) # 转换为8位图像
|
image_with_labels = Image.fromarray((np.clip(image_np,0,1) * 255).astype('uint8'))
|
||||||
# 创建PIL图像对象的副本以绘制标签
|
|
||||||
draw1 = ImageDraw.Draw(image_with_labels)
|
draw1 = ImageDraw.Draw(image_with_labels)
|
||||||
|
font = ImageFont.truetype('./utils/TIMES.TTF', size=40)
|
||||||
# 选择字体和字体大小
|
text_color = (255, 0, 0)
|
||||||
font = ImageFont.truetype('./utils/TIMES.TTF', size=40) # 请将路径替换为您选择的字体文件路径
|
|
||||||
|
|
||||||
# 选择文本颜色
|
|
||||||
text_color = (255, 0, 0) # 白色
|
|
||||||
|
|
||||||
# 选择标签的位置(左上角坐标)
|
|
||||||
label1_position = (10, 10)
|
label1_position = (10, 10)
|
||||||
label2_position = (image_with_labels.width - 100 - len(label2) * 10, 10) # 右上角坐标
|
label2_position = (image_with_labels.width - 100 - len(label2) * 10, 10)
|
||||||
|
|
||||||
# 在图像上添加标签
|
|
||||||
draw1.text(label1_position, label1, fill=text_color, font=font)
|
draw1.text(label1_position, label1, fill=text_color, font=font)
|
||||||
draw1.text(label2_position, label2, fill=text_color, font=font)
|
draw1.text(label2_position, label2, fill=text_color, font=font)
|
||||||
|
|
||||||
@ -58,42 +49,20 @@ def render_training_image(scene, gaussians, viewpoints, render_func, pipe, backg
|
|||||||
os.makedirs(point_cloud_path)
|
os.makedirs(point_cloud_path)
|
||||||
if not os.path.exists(image_path):
|
if not os.path.exists(image_path):
|
||||||
os.makedirs(image_path)
|
os.makedirs(image_path)
|
||||||
# image:3,800,800
|
|
||||||
|
|
||||||
# point_save_path = os.path.join(point_cloud_path,f"{iteration}.jpg")
|
|
||||||
for idx in range(len(viewpoints)):
|
for idx in range(len(viewpoints)):
|
||||||
image_save_path = os.path.join(image_path,f"{iteration}_{idx}.jpg")
|
image_save_path = os.path.join(image_path,f"{iteration}_{idx}.jpg")
|
||||||
render(gaussians,viewpoints[idx],image_save_path,scaling = 1,cam_type=dataset_type)
|
render(gaussians,viewpoints[idx],image_save_path,scaling = 1,cam_type=dataset_type)
|
||||||
# render(gaussians,point_save_path,scaling = 0.1)
|
|
||||||
# 保存带有标签的图像
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pc_mask = gaussians.get_opacity
|
pc_mask = gaussians.get_opacity
|
||||||
pc_mask = pc_mask > 0.1
|
pc_mask = pc_mask > 0.1
|
||||||
xyz = gaussians.get_xyz.detach()[pc_mask.squeeze()].cpu().permute(1,0).numpy()
|
|
||||||
# visualize_and_save_point_cloud(xyz, viewpoint.R, viewpoint.T, point_save_path)
|
|
||||||
# 如果需要,您可以将PIL图像转换回PyTorch张量
|
|
||||||
# return image
|
|
||||||
# image_with_labels_tensor = torch.tensor(image_with_labels, dtype=torch.float32).permute(2, 0, 1) / 255.0
|
|
||||||
def visualize_and_save_point_cloud(point_cloud, R, T, filename):
|
def visualize_and_save_point_cloud(point_cloud, R, T, filename):
|
||||||
# 创建3D散点图
|
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
ax = fig.add_subplot(111, projection='3d')
|
ax = fig.add_subplot(111, projection='3d')
|
||||||
R = R.T
|
R = R.T
|
||||||
# 应用旋转和平移变换
|
|
||||||
T = -R.dot(T)
|
T = -R.dot(T)
|
||||||
transformed_point_cloud = np.dot(R, point_cloud) + T.reshape(-1, 1)
|
transformed_point_cloud = np.dot(R, point_cloud) + T.reshape(-1, 1)
|
||||||
# pcd = o3d.geometry.PointCloud()
|
|
||||||
# pcd.points = o3d.utility.Vector3dVector(transformed_point_cloud.T) # 转置点云数据以匹配Open3D的格式
|
|
||||||
# transformed_point_cloud[2,:] = -transformed_point_cloud[2,:]
|
|
||||||
# 可视化点云
|
|
||||||
ax.scatter(transformed_point_cloud[0], transformed_point_cloud[1], transformed_point_cloud[2], c='g', marker='o')
|
ax.scatter(transformed_point_cloud[0], transformed_point_cloud[1], transformed_point_cloud[2], c='g', marker='o')
|
||||||
ax.axis("off")
|
ax.axis("off")
|
||||||
# ax.set_xlabel('X Label')
|
|
||||||
# ax.set_ylabel('Y Label')
|
|
||||||
# ax.set_zlabel('Z Label')
|
|
||||||
|
|
||||||
# 保存渲染结果为图片
|
|
||||||
plt.savefig(filename)
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user