nerf-pytorch训练自己的数据集

GitHub - yenchenlin/nerf-pytorch: A PyTorch implementation of NeRF (Neural Radiance Fields) that reproduces the results.

pytorch 代码

NERF 自己数据集复现 完成步骤+遇到问题

完成步骤:


1 数据集跑colmap,生成相机位姿


在此不做赘述,参考我的另一篇文章colmap。步骤大致相同,值得注意的是:

在进行特征提取时候记得选择相机模型,最好不要使用默认的,选择SIMPLE——PINHOLE和PINHOLE均可

结束后点击Processing旁边的Reconstruction,选择Start Reconstruction,等待结束

在完成这一步后我们最好查看一下是否每一张图片都被匹配到了,可能会出现没重建上的情况,这些图片要留意,后面我们要删除。

结束后,点击File,选择Export model,这里一定注意不要直接保存,需要新建两个文件夹(sparse,0),请保持一致 nerf原代码中固定了sparse/0文件夹的名称

结束后检查文件夹中的东西:
sparse/0/有三个bin文件和一个project.ini即可。在根目录下还应该有一个.db文件,这是第一步你创建project时候就生成的。


2 将生成的bin文件通过llff数据集转化成.npz格式


接下来,将获取的位姿等数据转化为llff格式,需要下载llff脚本,(地址:GitHub - Fyusion/LLFF: Code release for Local Light Field Fusion at SIGGRAPH 2019
下载完成进入LLFF目录下,打开imgs2poses.py文件,新增如下内容,default=‘里面是sparse所在目录的绝对路径’,并将参数’scenedir’修改为是’–scenedir’。

存放照片的文件夹名称必须是images,否则会出错。
运行imgs2poses.py代码(bash):

# 要在imgs2poses.py所在目录执行命令
cd....(文件所在目录)
# 运行
python imgs2poses.py --scenedir D:\colmap.1\nerf\warplane

假如不增加default=‘’。

# 在运行imgs2poses.py代码时,即使有默认值也必须传入路径(与scenedir参数有关)
python imgs2poses.py "XXXX/XXXX/"

按理说在这一步结束后,就应该输出一个有关图像位姿的.npy文件。但在这一步我踩了很多坑:
问题·1
会出现need to run colmap的报错,这通常是因为没办法获取正确的相机参数。
有可能是因为没有正确的创建文件夹,也有可能是因为spares文件下的.bin文件没放对位置。
这些都没问题的话,那就是生成的有问题,很可能就是因为在位姿计算时候你没有处理好数据,参考上文我遇到的问题来看你的图片有问题,请仔细检查。
问题·2
会出现UTF-8编码错误:
在这里插入图片描述
这个问题真的是耗费了博主无数的心血,博主最开始以为是程序的问题,在寻找到了源码的camera.bin文件读取函数修改了其中的编码方式,后面确实是不报错了,但是在最终训练时,无法进行正常训练。
在后面博主排除了是训练文件的问题后又重新把目光聚焦于此,试图寻找是不是数据的问题,于是尝试了很多种相机模型,但还是没有解决。每跑一遍colmap都要耗费掉很长的时间,可以说是心力交瘁。
再后来博主怀疑是不是环境的问题,更换电脑,甚至试了更换系统,都没有解决。
直到去系统查询了几种编码格式的区别,才意识到这很有可能是跟汉字有关,因为如果是纯英文的话,一般不会出现格式的转化,只有出现其他符号,才会有字符编码的转换,比如记事本:
在这里插入图片描述
所以,很大概率是因为数据里面出现了非常规字符。首先,图片的特征也好位姿信息也好不可能出现汉语,那只剩下了一种就是图片的名字!果不其然,我的图片因为是从微信传输保存的,所以图片名称中均出现了汉字,再修改后,重新进行位姿计算,解决了问题。

总结一下:原始数据集images里面的图片名称不能有汉语出现,否则在进行后续处理运行imgs2poses时候会出现utf-8编码错误。

另外,因为说到了初始数据的一些问题,顺便提一下:

图片的尺寸必须也得保持一致,也就是分辨率,否则到后面最后一步训练时候就会出现报错信息。

这两点十分重要,可以说是让博主在上面耗费了十分多的心血才解决。

问题3:

这个问题就是前文所说的匹配的位姿和图片数目不同导致的,博主在这里解决这个问题。通过在 LLFF/llff/poses/pose_utils.py 文件的32行左右添加如下代码:

    #---------输出匹配到位姿的图片名---------
    for i in np.argsort(names):
       print(names[i],end=' ')
    #---------输出匹配到位姿的图片名---------

添加代码位置如下图所示:

显示出所有匹配到位姿的图片。

仔细查看,然后进入图像保存的目录,删除没有匹配到位姿的图像,再后重新进行 “位姿计算” 这一步骤。

解决所有问题后,执行结果如下图所示:

生成有关图像位姿的npy文件,格式转换步骤完毕。


3 迁移工作文件夹并设置配置文件


将工作文件夹完整迁移至nerf代码的/nerf-pytorch/data/nerf_llff_data/目录下。

复制/nerf-pytorch/configs目录下的fern.txt文件(因为fern同为LLFF格式的数据集),并重命名为自己测试数据的名称,修改如下内容:

至此,所有准备工作都已完成。


4 训练数据


完成后执行

python run_nerf.py --config configs/warplanes.txt(替换成你自己的配置文件)

正常情况
在这里插入图片描述
还是一样的,这最后一步也会出现很多问题,也踩了很多坑,我把我遇见的分享出来:
问题·1
如果你是360度环拍的数据集 执行

python run_nerf.py --config configs/warplanes.txt --spherify --no_ndc

否则无法得到正确的渲染的结果 (渲染的图像中会有黑色的线)

问题·2 imageio函数报错
在执行到 evaluate 时,输出图片出了下面的错误:

envs\NeRFlearning\Lib\site-packages\PIL\Image.py", line 3102, in fromarray raise TypeError(msg) from e TypeError: Cannot handle this data type: (1, 1, 3), <f4

查询后发现是因为 imageio.imwrite 函数需要接收的图像数据类型为 uint8 ,而原始的 pred_rgbgt_rgb 可能是浮点数类型的数据。因此,我们需要将它们乘以255(将范围从0-1转换为0-255),然后使用 astype 函数将它们转换为 uint8 类型

# 将数据类型转换为 uint8
pred_rgb = (pred_rgb * 255).astype(np.uint8)
gt_rgb = (gt_rgb * 255).astype(np.uint8)
# 需要添加以上两行,否则报错
imageio.imwrite(save_path, img_utils.horizon_concate(gt_rgb, pred_rgb))

这里还有一个问题,我发现在已经生成过一张图片后,再次执行到这里,输出的新图片无法覆盖之前的旧图片,所以我加上了时间和当前周期作为扩展名

now = datetime.datetime.now()
now_str = now.strftime('%Y-%m-%d_%Hh%Mm%Ss')
base_name, ext = os.path.splitext(save_path)
save_path = f"{base_name}_{now_str}_epoch_{cfg.train.epoch}{ext}"

这样就会以这样的 res_2024-03-18_09h09m40s_epoch_10.jpg 格式正确输出每次的图像了

问题·3 Evaluate 显存爆炸

在运行 evaluate 模块时,我用模型对一张图片进行推理,发现显存爆炸增长,经过一番寻找之后,找到了问题:

  • ~在运行 run.py 的 evaluate 模块时,evaluator.evaluate(output, batch)这句话没有在 torch.no_grad() 中导致的。修改只需要加一个缩进即可~

问题·4 训练中迭代到一定次数loss出现NaN
一般来说,出现NaN有以下几种情况:

1.如果在迭代的100轮以内,出现NaN,一般情况下的原因是因为学习率过高。但这个不太可能出现在本项目中,本项目迭代轮次都在两万次左右,在很少次数就出现NaN明显不符合常理。
2.不当的输入
输入中就含有NaN。
现象:每当学习的过程中碰到这个错误的输入,就会变成NaN。观察log的时候也许不能察觉任何异常,loss逐步的降低,但突然间就变成NaN了。
措施:提前进行下采样:

import cv2
import os


def downsample_images(input_dir, output_dir, downsample_factor):
    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 获取输入目录下的所有.jpg文件
    images = [f for f in os.listdir(input_dir) if f.endswith('.jpg')]

    # 初始化处理图片计数器和输出图片索引
    num = 0
    index = 0

    # 遍历每一张图片
    for image_name in images:
        # 构建完整的文件路径
        input_image_path = os.path.join(input_dir, image_name)

        # 读取原始图片
        original_image = cv2.imread(input_image_path)

        # 检查是否成功读取图片
        if original_image is None:
            print(f"警告: 无法读取图片 {input_image_path}")
            continue

        # 根据下采样因子进行下采样
        img_downsampled = original_image
        for _ in range(downsample_factor):
            img_downsampled = cv2.pyrDown(img_downsampled)

        # 构建输出图片的完整路径并保存
        output_image_path = os.path.join(output_dir, f"{index}.jpg")
        cv2.imwrite(output_image_path, img_downsampled)

        # 更新计数器
        num += 1
        index += 1
        print(f"正在为第{num}张图片采样......")


# 设置输入输出目录以及下采样因子
input_directory = r'D:\colmap.1\nerf2\warplane\images'
output_directory = r'D:\colmap.1\nerf2\warplane\images_4'
downsample_factor = 2  # 下采样倍数,例如8倍则设置为3(因为每次pyrDown都是2倍)

# 调用函数执行下采样
downsample_images(input_directory, output_directory, downsample_factor)

经过多次测试,最好是进行8倍和4倍的两次下采样,并将数据保存在images_8和images_4两个文件夹放入你的数据集data里,和images原图处于同一路径下。


5 存疑的问题


psnr 不上升

有时开始训练时的psnr从9左右开始就会导致 psnr 不上升一直徘徊在9左右,loss 正常下降。
image-20240430212144837

尝试了5000次的迭代(10个epoch),测试出来图片是纯黑色的:

目前猜测原因可能是初始化导致的。

2 out of the memory
修改txt文件中的N_rand N_samples N_importance

代表处理光束的数量,普通采样点数量(进入coarse网络的采样点个数),重要性采样点的数量(进入fine网络的采样点个数是sample+importance)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ajaxm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值