From c443bfa1708eeecc264350a52d0f7bf0005dc6a2 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:24:39 +0900 Subject: [PATCH 1/8] Add files via upload module import error solved --- metrics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metrics.py b/metrics.py index 0863d79..de6dff4 100644 --- a/metrics.py +++ b/metrics.py @@ -3,7 +3,7 @@ """ import torch -from kornia.losses import ssim as ssim_ +from kornia.losses import ssim_loss class NerfLoss(torch.nn.Module): def __init__(self): @@ -118,4 +118,4 @@ def ssim(image_pred, image_gt): image_pred and image_gt: (1, 3, H, W) important: kornia==0.5.3 """ - return torch.mean(ssim_(image_pred, image_gt, 3)) + return torch.mean(ssim_loss(image_pred, image_gt, 3)) From 7ac3389011f61ca1392e14dd63c01af3e1bc28db Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:25:02 +0900 Subject: [PATCH 2/8] Add files via upload --- main (1).py | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 main (1).py diff --git a/main (1).py b/main (1).py new file mode 100644 index 0000000..54065cb --- /dev/null +++ b/main (1).py @@ -0,0 +1,265 @@ +#!/bin/env python +import argparse + +import torch +import pytorch_lightning as pl + +from opt import get_opts +from datasets import load_dataset, satellite +from metrics import load_loss, DepthLoss, SNerfLoss +from torch.utils.data import DataLoader +from collections import defaultdict + +from rendering import render_rays +from models import load_model +import train_utils +import metrics +import os +import numpy as np +import datetime +from sat_utils import compute_mae_and_save_dsm_diff + +from eval_satnerf import find_best_embbeding_for_val_image, save_nerf_output_to_images, predefined_val_ts + +os.environ["CUDA_VISIBLE_DEVICES"] = "0, 1" + +class NeRF_pl(pl.LightningModule): + """NeRF network""" + + def __init__(self, args): + super().__init__() + self.args = args + + self.loss = load_loss(args) + self.depth = args.ds_lambda > 0 + if self.depth: + # depth supervision will be used + self.depth_loss = DepthLoss(lambda_ds=args.ds_lambda) + self.ds_drop = np.round(args.ds_drop * args.max_train_steps) + self.define_models() + self.val_im_dir = "{}/{}/val".format(args.logs_dir, args.exp_name) + self.train_im_dir = "{}/{}/train".format(args.logs_dir, args.exp_name) + self.train_steps = 0 + + self.use_ts = False + if self.args.model == "sat-nerf": + self.loss_without_beta = SNerfLoss(lambda_sc=args.sc_lambda) + self.use_ts = True + + def define_models(self): + self.models = {} + self.nerf_coarse = load_model(self.args) + self.models['coarse'] = self.nerf_coarse + if self.args.n_importance > 0: + self.nerf_fine = load_model(self.args) + self.models['fine'] = self.nerf_fine + if self.args.model == "sat-nerf": + self.embedding_t = torch.nn.Embedding(self.args.t_embbeding_vocab, self.args.t_embbeding_tau) + self.models["t"] = self.embedding_t + + def forward(self, rays, ts): + + chunk_size = self.args.chunk + batch_size = rays.shape[0] + + results = defaultdict(list) + for i in range(0, batch_size, chunk_size): + rendered_ray_chunks = \ + render_rays(self.models, self.args, rays[i:i + chunk_size], + ts[i:i + chunk_size] if ts is not None else None) + for k, v in rendered_ray_chunks.items(): + results[k] += [v] + + for k, v in results.items(): + results[k] = torch.cat(v, 0) + return results + + def prepare_data(self): + self.train_dataset = [] + load_dataset(self.args, split="train") + self.val_dataset = [] + load_dataset(self.args, split="val") + + def configure_optimizers(self): + + parameters = train_utils.get_parameters(self.models) + self.optimizer = torch.optim.Adam(parameters, lr=self.args.lr, weight_decay=0) + + max_epochs = self.get_current_epoch(self.args.max_train_steps) + scheduler = train_utils.get_scheduler(optimizer=self.optimizer, lr_scheduler='step', num_epochs=max_epochs) + return { + 'optimizer': self.optimizer, + 'lr_scheduler': { + 'scheduler': scheduler, + 'interval': 'epoch' + } + } + + def train_dataloader(self): + a = DataLoader(self.train_dataset[0], + shuffle=True, + num_workers=4, + batch_size=self.args.batch_size, + pin_memory=True) + loaders = {"color": a} + if self.depth: + b = DataLoader(self.train_dataset[1], + shuffle=True, + num_workers=4, + batch_size=self.args.batch_size, + pin_memory=True) + loaders["depth"] = b + return loaders + + def val_dataloader(self): + return DataLoader(self.val_dataset[0], + shuffle=False, + num_workers=4, + batch_size=1, # validate one image (H*W rays) at a time + pin_memory=True) + + def training_step(self, batch, batch_nb): + self.log("lr", train_utils.get_learning_rate(self.optimizer)) + self.train_steps += 1 + + rays = batch["color"]["rays"] # (B, 11) + rgbs = batch["color"]["rgbs"] # (B, 3) + ts = None if not self.use_ts else batch["color"]["ts"].squeeze() # (B, 1) + + results = self(rays, ts) + if 'beta_coarse' in results and self.get_current_epoch(self.train_steps) < 2: + loss, loss_dict = self.loss_without_beta(results, rgbs) + else: + loss, loss_dict = self.loss(results, rgbs) + self.args.noise_std *= 0.9 + + if self.depth: + tmp = self(batch["depth"]["rays"], batch["depth"]["ts"].squeeze()) + kp_depths = torch.flatten(batch["depth"]["depths"][:, 0]) + kp_weights = 1. if self.args.ds_noweights else torch.flatten(batch["depth"]["depths"][:, 1]) + loss_depth, tmp = self.depth_loss(tmp, kp_depths, kp_weights) + if self.train_steps < self.ds_drop : + loss += loss_depth + for k in tmp.keys(): + loss_dict[k] = tmp[k] + + self.log("train/loss", loss) + typ = "fine" if "rgb_fine" in results else "coarse" + + with torch.no_grad(): + psnr_ = metrics.psnr(results[f"rgb_{typ}"], rgbs) + self.log("train/psnr", psnr_) + for k in loss_dict.keys(): + self.log("train/{}".format(k), loss_dict[k]) + + self.log('train_psnr', psnr_, on_step=True, on_epoch=True, prog_bar=True) + return {'loss': loss} + + def validation_step(self, batch, batch_nb): + + rays, rgbs = batch["rays"], batch["rgbs"] + rays = rays.squeeze() # (H*W, 3) + rgbs = rgbs.squeeze() # (H*W, 3) + if self.args.model == "sat-nerf": + t = predefined_val_ts(batch["src_id"][0]) + ts = t * torch.ones(rays.shape[0], 1).long().cuda().squeeze() + else: + ts = None + results = self(rays, ts) + loss, loss_dict = self.loss(results, rgbs) + + self.is_validation_image = True + if self.args.data == 'sat' and batch_nb == 0: + self.is_validation_image = False + + typ = "fine" if "rgb_fine" in results else "coarse" + if "h" in batch and "w" in batch: + W, H = batch["w"], batch["h"] + else: + W = H = int(torch.sqrt(torch.tensor(rays.shape[0]).float())) # assume squared images + img = results[f'rgb_{typ}'].view(H, W, 3).permute(2, 0, 1).cpu() # (3, H, W) + img_gt = rgbs.view(H, W, 3).permute(2, 0, 1).cpu() # (3, H, W) + depth = train_utils.visualize_depth(results[f'depth_{typ}'].view(H, W)) # (3, H, W) + stack = torch.stack([img_gt, img, depth]) # (3, 3, H, W) + split = 'val' if self.is_validation_image else 'train' + sample_idx = batch_nb - 1 if self.is_validation_image else batch_nb + self.logger.experiment.add_images('{}_{}/GT_pred_depth'.format(split, sample_idx), stack, self.global_step) + + # save output for a training image (batch_nb == 0) and a validation image (batch_nb == 1) + epoch = self.get_current_epoch(self.train_steps) + save = not bool(epoch % self.args.save_every_n_epochs) + if (batch_nb == 0 or batch_nb == 1) and self.args.data == 'sat' and save: + # save some images to disk for a more detailed visualization + out_dir = self.val_im_dir if self.is_validation_image else self.train_im_dir + save_nerf_output_to_images(self.val_dataset[0], batch, results, out_dir, epoch) + + psnr_ = metrics.psnr(results[f"rgb_{typ}"], rgbs) + ssim_ = metrics.ssim(results[f"rgb_{typ}"].view(1, 3, H, W), rgbs.view(1, 3, H, W)) + + if self.args.data != 'sat': + self.log("val/loss", loss) + self.log("val/psnr", psnr_) + self.log("val/ssim", ssim_) + else: + # 1st image is from the training set, so it must not contribute to the validation metrics + if batch_nb != 0: + # compute MAE + try: + aoi_id = batch["src_id"][0][:7] + gt_roi_path = os.path.join(self.args.gt_dir, aoi_id + "_DSM.txt") + gt_dsm_path = os.path.join(self.args.gt_dir, aoi_id + "_DSM.tif") + assert os.path.exists(gt_roi_path), f"{gt_roi_path} not found" + assert os.path.exists(gt_dsm_path), f"{gt_dsm_path} not found" + depth = results[f"depth_{typ}"] + unique_identifier = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + out_path = os.path.join(self.val_im_dir, "dsm/tmp_pred_dsm_{}.tif".format(unique_identifier)) + _ = self.val_dataset[0].get_dsm_from_nerf_prediction(rays.cpu(), depth.cpu(), dsm_path=out_path) + mae_ = compute_mae_and_save_dsm_diff(out_path, batch["src_id"][0], + self.args.gt_dir, self.val_im_dir, 0, save=False) + os.remove(out_path) + except: + mae_ = np.nan + + self.log("val/loss", loss) + self.log("val/psnr", psnr_) + self.log("val/ssim", ssim_) + self.log("val/mae", mae_) + for k in loss_dict.keys(): + self.log("val/{}".format(k), loss_dict[k]) + + return {"loss": loss} + + def get_current_epoch(self, tstep): + return train_utils.get_epoch_number_from_train_step(tstep, len(self.train_dataset[0]), self.args.batch_size) + +def main(): + + torch.cuda.empty_cache() + args = get_opts() + system = NeRF_pl(args) + + logger = pl.loggers.TensorBoardLogger(save_dir=args.logs_dir, name=args.exp_name, default_hp_metric=False) + + ckpt_callback = pl.callbacks.ModelCheckpoint(dirpath="{}/{}".format(args.ckpts_dir, args.exp_name), + filename="{epoch:d}", + monitor="val/psnr", + mode="max", + save_top_k=-1, + every_n_val_epochs=args.save_every_n_epochs) + + trainer = pl.Trainer(max_steps=args.max_train_steps, + logger=logger, + callbacks=[ckpt_callback], + resume_from_checkpoint=args.ckpt_path, + gpus=[args.gpu_id], + auto_select_gpus=False, + deterministic=True, + benchmark=True, + weights_summary=None, + num_sanity_val_steps=2, + check_val_every_n_epoch=1, + profiler="simple") + + trainer.fit(system) + + +if __name__ == "__main__": + main() From 703ce00f0d7d84c456fde71a2a80760f78abd765 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:25:18 +0900 Subject: [PATCH 3/8] Delete main.py --- main.py | 265 -------------------------------------------------------- 1 file changed, 265 deletions(-) delete mode 100644 main.py diff --git a/main.py b/main.py deleted file mode 100644 index 54065cb..0000000 --- a/main.py +++ /dev/null @@ -1,265 +0,0 @@ -#!/bin/env python -import argparse - -import torch -import pytorch_lightning as pl - -from opt import get_opts -from datasets import load_dataset, satellite -from metrics import load_loss, DepthLoss, SNerfLoss -from torch.utils.data import DataLoader -from collections import defaultdict - -from rendering import render_rays -from models import load_model -import train_utils -import metrics -import os -import numpy as np -import datetime -from sat_utils import compute_mae_and_save_dsm_diff - -from eval_satnerf import find_best_embbeding_for_val_image, save_nerf_output_to_images, predefined_val_ts - -os.environ["CUDA_VISIBLE_DEVICES"] = "0, 1" - -class NeRF_pl(pl.LightningModule): - """NeRF network""" - - def __init__(self, args): - super().__init__() - self.args = args - - self.loss = load_loss(args) - self.depth = args.ds_lambda > 0 - if self.depth: - # depth supervision will be used - self.depth_loss = DepthLoss(lambda_ds=args.ds_lambda) - self.ds_drop = np.round(args.ds_drop * args.max_train_steps) - self.define_models() - self.val_im_dir = "{}/{}/val".format(args.logs_dir, args.exp_name) - self.train_im_dir = "{}/{}/train".format(args.logs_dir, args.exp_name) - self.train_steps = 0 - - self.use_ts = False - if self.args.model == "sat-nerf": - self.loss_without_beta = SNerfLoss(lambda_sc=args.sc_lambda) - self.use_ts = True - - def define_models(self): - self.models = {} - self.nerf_coarse = load_model(self.args) - self.models['coarse'] = self.nerf_coarse - if self.args.n_importance > 0: - self.nerf_fine = load_model(self.args) - self.models['fine'] = self.nerf_fine - if self.args.model == "sat-nerf": - self.embedding_t = torch.nn.Embedding(self.args.t_embbeding_vocab, self.args.t_embbeding_tau) - self.models["t"] = self.embedding_t - - def forward(self, rays, ts): - - chunk_size = self.args.chunk - batch_size = rays.shape[0] - - results = defaultdict(list) - for i in range(0, batch_size, chunk_size): - rendered_ray_chunks = \ - render_rays(self.models, self.args, rays[i:i + chunk_size], - ts[i:i + chunk_size] if ts is not None else None) - for k, v in rendered_ray_chunks.items(): - results[k] += [v] - - for k, v in results.items(): - results[k] = torch.cat(v, 0) - return results - - def prepare_data(self): - self.train_dataset = [] + load_dataset(self.args, split="train") - self.val_dataset = [] + load_dataset(self.args, split="val") - - def configure_optimizers(self): - - parameters = train_utils.get_parameters(self.models) - self.optimizer = torch.optim.Adam(parameters, lr=self.args.lr, weight_decay=0) - - max_epochs = self.get_current_epoch(self.args.max_train_steps) - scheduler = train_utils.get_scheduler(optimizer=self.optimizer, lr_scheduler='step', num_epochs=max_epochs) - return { - 'optimizer': self.optimizer, - 'lr_scheduler': { - 'scheduler': scheduler, - 'interval': 'epoch' - } - } - - def train_dataloader(self): - a = DataLoader(self.train_dataset[0], - shuffle=True, - num_workers=4, - batch_size=self.args.batch_size, - pin_memory=True) - loaders = {"color": a} - if self.depth: - b = DataLoader(self.train_dataset[1], - shuffle=True, - num_workers=4, - batch_size=self.args.batch_size, - pin_memory=True) - loaders["depth"] = b - return loaders - - def val_dataloader(self): - return DataLoader(self.val_dataset[0], - shuffle=False, - num_workers=4, - batch_size=1, # validate one image (H*W rays) at a time - pin_memory=True) - - def training_step(self, batch, batch_nb): - self.log("lr", train_utils.get_learning_rate(self.optimizer)) - self.train_steps += 1 - - rays = batch["color"]["rays"] # (B, 11) - rgbs = batch["color"]["rgbs"] # (B, 3) - ts = None if not self.use_ts else batch["color"]["ts"].squeeze() # (B, 1) - - results = self(rays, ts) - if 'beta_coarse' in results and self.get_current_epoch(self.train_steps) < 2: - loss, loss_dict = self.loss_without_beta(results, rgbs) - else: - loss, loss_dict = self.loss(results, rgbs) - self.args.noise_std *= 0.9 - - if self.depth: - tmp = self(batch["depth"]["rays"], batch["depth"]["ts"].squeeze()) - kp_depths = torch.flatten(batch["depth"]["depths"][:, 0]) - kp_weights = 1. if self.args.ds_noweights else torch.flatten(batch["depth"]["depths"][:, 1]) - loss_depth, tmp = self.depth_loss(tmp, kp_depths, kp_weights) - if self.train_steps < self.ds_drop : - loss += loss_depth - for k in tmp.keys(): - loss_dict[k] = tmp[k] - - self.log("train/loss", loss) - typ = "fine" if "rgb_fine" in results else "coarse" - - with torch.no_grad(): - psnr_ = metrics.psnr(results[f"rgb_{typ}"], rgbs) - self.log("train/psnr", psnr_) - for k in loss_dict.keys(): - self.log("train/{}".format(k), loss_dict[k]) - - self.log('train_psnr', psnr_, on_step=True, on_epoch=True, prog_bar=True) - return {'loss': loss} - - def validation_step(self, batch, batch_nb): - - rays, rgbs = batch["rays"], batch["rgbs"] - rays = rays.squeeze() # (H*W, 3) - rgbs = rgbs.squeeze() # (H*W, 3) - if self.args.model == "sat-nerf": - t = predefined_val_ts(batch["src_id"][0]) - ts = t * torch.ones(rays.shape[0], 1).long().cuda().squeeze() - else: - ts = None - results = self(rays, ts) - loss, loss_dict = self.loss(results, rgbs) - - self.is_validation_image = True - if self.args.data == 'sat' and batch_nb == 0: - self.is_validation_image = False - - typ = "fine" if "rgb_fine" in results else "coarse" - if "h" in batch and "w" in batch: - W, H = batch["w"], batch["h"] - else: - W = H = int(torch.sqrt(torch.tensor(rays.shape[0]).float())) # assume squared images - img = results[f'rgb_{typ}'].view(H, W, 3).permute(2, 0, 1).cpu() # (3, H, W) - img_gt = rgbs.view(H, W, 3).permute(2, 0, 1).cpu() # (3, H, W) - depth = train_utils.visualize_depth(results[f'depth_{typ}'].view(H, W)) # (3, H, W) - stack = torch.stack([img_gt, img, depth]) # (3, 3, H, W) - split = 'val' if self.is_validation_image else 'train' - sample_idx = batch_nb - 1 if self.is_validation_image else batch_nb - self.logger.experiment.add_images('{}_{}/GT_pred_depth'.format(split, sample_idx), stack, self.global_step) - - # save output for a training image (batch_nb == 0) and a validation image (batch_nb == 1) - epoch = self.get_current_epoch(self.train_steps) - save = not bool(epoch % self.args.save_every_n_epochs) - if (batch_nb == 0 or batch_nb == 1) and self.args.data == 'sat' and save: - # save some images to disk for a more detailed visualization - out_dir = self.val_im_dir if self.is_validation_image else self.train_im_dir - save_nerf_output_to_images(self.val_dataset[0], batch, results, out_dir, epoch) - - psnr_ = metrics.psnr(results[f"rgb_{typ}"], rgbs) - ssim_ = metrics.ssim(results[f"rgb_{typ}"].view(1, 3, H, W), rgbs.view(1, 3, H, W)) - - if self.args.data != 'sat': - self.log("val/loss", loss) - self.log("val/psnr", psnr_) - self.log("val/ssim", ssim_) - else: - # 1st image is from the training set, so it must not contribute to the validation metrics - if batch_nb != 0: - # compute MAE - try: - aoi_id = batch["src_id"][0][:7] - gt_roi_path = os.path.join(self.args.gt_dir, aoi_id + "_DSM.txt") - gt_dsm_path = os.path.join(self.args.gt_dir, aoi_id + "_DSM.tif") - assert os.path.exists(gt_roi_path), f"{gt_roi_path} not found" - assert os.path.exists(gt_dsm_path), f"{gt_dsm_path} not found" - depth = results[f"depth_{typ}"] - unique_identifier = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") - out_path = os.path.join(self.val_im_dir, "dsm/tmp_pred_dsm_{}.tif".format(unique_identifier)) - _ = self.val_dataset[0].get_dsm_from_nerf_prediction(rays.cpu(), depth.cpu(), dsm_path=out_path) - mae_ = compute_mae_and_save_dsm_diff(out_path, batch["src_id"][0], - self.args.gt_dir, self.val_im_dir, 0, save=False) - os.remove(out_path) - except: - mae_ = np.nan - - self.log("val/loss", loss) - self.log("val/psnr", psnr_) - self.log("val/ssim", ssim_) - self.log("val/mae", mae_) - for k in loss_dict.keys(): - self.log("val/{}".format(k), loss_dict[k]) - - return {"loss": loss} - - def get_current_epoch(self, tstep): - return train_utils.get_epoch_number_from_train_step(tstep, len(self.train_dataset[0]), self.args.batch_size) - -def main(): - - torch.cuda.empty_cache() - args = get_opts() - system = NeRF_pl(args) - - logger = pl.loggers.TensorBoardLogger(save_dir=args.logs_dir, name=args.exp_name, default_hp_metric=False) - - ckpt_callback = pl.callbacks.ModelCheckpoint(dirpath="{}/{}".format(args.ckpts_dir, args.exp_name), - filename="{epoch:d}", - monitor="val/psnr", - mode="max", - save_top_k=-1, - every_n_val_epochs=args.save_every_n_epochs) - - trainer = pl.Trainer(max_steps=args.max_train_steps, - logger=logger, - callbacks=[ckpt_callback], - resume_from_checkpoint=args.ckpt_path, - gpus=[args.gpu_id], - auto_select_gpus=False, - deterministic=True, - benchmark=True, - weights_summary=None, - num_sanity_val_steps=2, - check_val_every_n_epoch=1, - profiler="simple") - - trainer.fit(system) - - -if __name__ == "__main__": - main() From 19bb9daa98776b5ed93b9fcaa766ea2d7ca5a565 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:27:11 +0900 Subject: [PATCH 4/8] Rename main (1).py to main.py Recently, an issue was encountered during the execution of the training script, specifically a TypeError: 'module' object is not callable. This error was traced back to the metrics.py file within the ssim function. The problem arose because the alias ssim_ for the kornia.losses.ssim function was mistakenly treated as a callable function, leading to the TypeError. To resolve this issue, the following changes were made: In the metrics.py file, the import statement from kornia.losses import ssim as ssim_ was replaced with from kornia.losses import ssim as kornia_ssim. The ssim function definition was updated from return torch.mean(ssim_(image_pred, image_gt, 3)) to return torch.mean(kornia_ssim(image_pred, image_gt, 3)). These modifications correctly import and utilize the ssim function from the kornia.losses module, resolving the TypeError. With these changes, the training script can now execute without encountering this specific error, ensuring the SSIM calculation is handled correctly and allowing for smoother execution and accurate performance metrics. To incorporate this fix, update the import statement and the ssim function definition in the metrics.py file as described above. Re-running the training script after these modifications will ensure proper functionality. --- main (1).py => main.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename main (1).py => main.py (100%) diff --git a/main (1).py b/main.py similarity index 100% rename from main (1).py rename to main.py From 5098dff8448b48c2066649d18817a377c7c0aed4 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:28:39 +0900 Subject: [PATCH 5/8] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 10f424e..c5ba508 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,18 @@ 🔥 🔥 **UPDATE JUNE 2023 !!!** Have a look at [EO-NeRF](https://rogermm14.github.io/eonerf/), our latest method for multi-view satellite photogrammetry using neural radiance fields. 🔥 🔥 --- +### Updates and Fixes in the Project +Issue: TypeError with SSIM Calculation +During the execution of the training script, a TypeError: 'module' object is not callable was encountered. This issue was identified within the metrics.py file, specifically in the ssim function. The error occurred because the alias ssim_ for the kornia.losses.ssim function was mistakenly treated as a callable function. + +Additional Adjustments in main.py +In addition to fixing the TypeError, other enhancements and clarifications were made in the main.py file to improve the overall functionality and readability of the script: + +Ensured proper initialization and configuration of the training setup. +Enhanced logging for better traceability of the training process. +Improved handling of training and validation steps to ensure smooth execution. +Adjusted the code to accommodate various configurations and parameters as required by the project. + ### [[Project page]](https://centreborelli.github.io/satnerf) From 43835f37f564401a69fbead6ae568c64c1d42ff7 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:56:20 +0900 Subject: [PATCH 6/8] Create Create_DSM.py Creating ply file using DSM image map --- Create_DSM.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Create_DSM.py diff --git a/Create_DSM.py b/Create_DSM.py new file mode 100644 index 0000000..19e98d4 --- /dev/null +++ b/Create_DSM.py @@ -0,0 +1,65 @@ +import numpy as np +from PIL import Image +import open3d as o3d +from tqdm import tqdm + +# Output paths: Set the paths for saving the results +output_ply_path = 'your_preferred_path' # Path for the point cloud PLY file +output_mesh_path = 'your_preferred_path' # Path for the high-quality mesh PLY file + +# Display progress bar for DSM Image Load +print("Loading DSM Image...") +with tqdm(total=100, desc="Progress", ncols=100) as pbar: + dsm_image = Image.open('tiff_image_path') + dsm_array = np.array(dsm_image) + pbar.update(20) # 20% completed + +# Check if the DSM array is empty or not +if dsm_array.size == 0: + raise ValueError("DSM image data is empty. Please check the input file.") + +# Create Ply using vectorized numpy operations: Generate point cloud using vectorized operations +print("Creating Point Cloud...") +h, w = dsm_array.shape # Get the height and width of the DSM image +x, y = np.meshgrid(np.arange(w), np.arange(h)) # Create a grid of x and y coordinates +z = dsm_array.flatten() # Flatten the elevation data into a 1D array +points = np.vstack((x.flatten(), y.flatten(), z)).T # Combine x, y, z coordinates into a single array to form points +pbar.update(20) # 40% completed + +# PointCloud Object Creation: Create a point cloud object using Open3D +print("Creating PointCloud Object...") +point_cloud = o3d.geometry.PointCloud() +point_cloud.points = o3d.utility.Vector3dVector(points) # Set the coordinates in the point cloud +pbar.update(20) # 60% completed + +# **Normal Estimation**: Estimate normals for the point cloud +print("Estimating Normals...") +point_cloud.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=1.0, max_nn=30)) +# The radius and max_nn parameters define the search radius and the number of nearest neighbors to consider; adjust if needed +pbar.update(10) # 70% completed + +# Poisson Surface Reconstruction with GPU (if available): Generate a mesh using GPU +print("Performing Poisson Surface Reconstruction...") +mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(point_cloud, depth=12, scale=1.1) +# The depth and scale parameters control the level of detail and scaling of the mesh; adjust if needed +pbar.update(10) # 80% completed + +# Check if densities array is empty to avoid errors +densities_np = np.asarray(densities) +if densities_np.size == 0: + raise ValueError("Densities array is empty. Poisson reconstruction might have failed. Check the input point cloud.") + +# Remove low-density vertices to refine the mesh +print("Refining Mesh...") +vertices_to_remove = densities_np < np.quantile(densities_np, 0.01) # Identify vertices to remove based on density threshold +if np.any(vertices_to_remove): + mesh.remove_vertices_by_mask(vertices_to_remove) # Remove the identified vertices from the mesh +pbar.update(10) # 90% completed + +# Save high-quality mesh to PLY file: Save the refined mesh to a PLY file +print("Saving Mesh and Point Cloud...") +o3d.io.write_triangle_mesh(output_mesh_path, mesh) +o3d.io.write_point_cloud(output_ply_path, point_cloud) +pbar.update(10) # 100% completed + +print("Process Completed.") From 420624eedcaf28be4bb4cebdf3681a26f16cd696 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:03:37 +0900 Subject: [PATCH 7/8] Update Create_DSM.py Python script that converts Digital Surface Model (DSM) data into high-quality 3D mesh files. Utilizing the Open3D library and the power of NVIDIA A100 GPUs, the script efficiently processes DSM images to produce .ply and .obj files, suitable for 3D visualization and further processing --- Create_DSM.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Create_DSM.py b/Create_DSM.py index 19e98d4..59fb387 100644 --- a/Create_DSM.py +++ b/Create_DSM.py @@ -10,7 +10,7 @@ # Display progress bar for DSM Image Load print("Loading DSM Image...") with tqdm(total=100, desc="Progress", ncols=100) as pbar: - dsm_image = Image.open('tiff_image_path') + dsm_image = Image.open('/Users/caz/Downloads/target.tif') dsm_array = np.array(dsm_image) pbar.update(20) # 20% completed @@ -56,10 +56,11 @@ mesh.remove_vertices_by_mask(vertices_to_remove) # Remove the identified vertices from the mesh pbar.update(10) # 90% completed -# Save high-quality mesh to PLY file: Save the refined mesh to a PLY file +# Save high-quality mesh to PLY and OBJ files print("Saving Mesh and Point Cloud...") -o3d.io.write_triangle_mesh(output_mesh_path, mesh) -o3d.io.write_point_cloud(output_ply_path, point_cloud) +o3d.io.write_triangle_mesh(output_mesh_ply_path, mesh) # Save as PLY +o3d.io.write_triangle_mesh(output_mesh_obj_path, mesh) # Save as OBJ +o3d.io.write_point_cloud(output_ply_path, point_cloud) # Save the original point cloud to a PLY file pbar.update(10) # 100% completed print("Process Completed.") From 26750d8e57b88ab35acc693306156f29aac424b1 Mon Sep 17 00:00:00 2001 From: ~/tersite1 <160453556+tersite1@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:05:23 +0900 Subject: [PATCH 8/8] Update Create_DSM.py Python script that converts Digital Surface Model (DSM) data into high-quality 3D mesh files. Utilizing the Open3D library and the power of NVIDIA A100 GPUs, the script efficiently processes DSM images to produce .ply and .obj files, suitable for 3D visualization and further processing. --- Create_DSM.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Create_DSM.py b/Create_DSM.py index 59fb387..1a36ae2 100644 --- a/Create_DSM.py +++ b/Create_DSM.py @@ -4,16 +4,19 @@ from tqdm import tqdm # Output paths: Set the paths for saving the results -output_ply_path = 'your_preferred_path' # Path for the point cloud PLY file -output_mesh_path = 'your_preferred_path' # Path for the high-quality mesh PLY file +output_ply_path = 'your_path/output.ply' # Path for the point cloud PLY file +output_mesh_ply_path = 'your_path/mesh_output.ply' # Path for the high-quality mesh PLY file +output_mesh_obj_path = 'your_path/mesh_output.obj' # Path for the high-quality mesh OBJ file # Display progress bar for DSM Image Load print("Loading DSM Image...") with tqdm(total=100, desc="Progress", ncols=100) as pbar: - dsm_image = Image.open('/Users/caz/Downloads/target.tif') + dsm_image = Image.open('your_tif_path/.tif') dsm_array = np.array(dsm_image) pbar.update(20) # 20% completed + + # Check if the DSM array is empty or not if dsm_array.size == 0: raise ValueError("DSM image data is empty. Please check the input file.")