三维重建的步骤-1(采集的是环绕物体均匀旋转一圈的视频)

拿到手里的是环绕物体均匀旋转一圈的视频,这里使用Agisoft Metashape Professional进行处理。

一、抽帧

1、当下载的版本支持导入视频处理的话,就可以直接导入视频

这里的帧步骤计算可以参考下面这个方法:

复制代码
第1步:查视频帧率
右键点击你的视频文件 → 属性 → 详细信息 → 找到 "帧速率"(单位是 fps)
常见值:24、25、30、50、60
记下这个数字,比如 30

第2步:算总帧数
总帧数 = 视频总秒数 × 帧率
视频总秒数怎么算:
比如 2分33秒 = 2×60 + 33 = 153秒
举例:
153秒 × 30fps = 4590帧(总帧数)

第3步:算帧步骤
帧步骤 = 总帧数 ÷ 你想要的张数
举例:
4590帧 ÷ 37张 = 124
→ 在软件"帧步骤"里填 124

然后点击ok,软件就会自动进行抽帧。

2、当下载的版本或电脑本身不支持导入视频处理

使用代码将视频均分进行抽帧,别人建议的是抽37帧,但是我试过之后感觉效果不是很行,所以我这里抽了60帧,看着效果不好当然也可以自己调整(按角度或按时间,保证覆盖 360°)。参考代码如下,按照实际情况自行调整,自己不会调整可以问问ai有什么好建议:

python 复制代码
import cv2
import os
import sys
from pathlib import Path


def extract_frames(video_path, output_folder, num_frames=60):
    """
    从视频中抽取指定数量的帧
    """
    # 检查视频文件是否存在
    if not os.path.exists(video_path):
        print(f"错误: 视频文件 {video_path} 不存在")
        return

    # 创建输出文件夹
    os.makedirs(output_folder, exist_ok=True)

    # 获取视频文件名(不含扩展名)
    video_name = Path(video_path).stem

    # 打开视频
    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        print(f"错误: 无法打开视频文件 {video_path}")
        return

    # 获取视频总帧数
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    if total_frames == 0:
        print(f"错误: 视频 {video_name} 没有帧")
        cap.release()
        return

    print(f"视频 '{video_name}' 总帧数: {total_frames}")

    # 计算采样间隔
    if total_frames <= num_frames:
        frame_indices = list(range(total_frames))
    else:
        step = total_frames / num_frames
        frame_indices = [int(i * step) for i in range(num_frames)]

    extracted_count = 0

    for idx, frame_num in enumerate(frame_indices):
        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
        ret, frame = cap.read()

        if not ret:
            print(f"警告: 无法读取第 {frame_num} 帧")
            continue

        frame_filename = f"{video_name}_{extracted_count + 1:06d}.jpg"
        frame_path = os.path.join(output_folder, frame_filename)
        cv2.imwrite(frame_path, frame)
        extracted_count += 1

        print(f"已提取: {extracted_count}/{num_frames} 帧", end='\r')

    cap.release()
    print(f"\n完成! 从 '{video_name}' 提取了 {extracted_count} 帧到 {output_folder}")
    return extracted_count


def process_folder(input_folder, output_base_folder, num_frames=60):
    """
    处理指定文件夹中的所有MP4视频
    """
    # 检查输入路径是文件还是文件夹
    if os.path.isfile(input_folder):
        # 如果是单个文件,直接处理
        if input_folder.lower().endswith('.mp4'):
            output_folder = os.path.join(output_base_folder, Path(input_folder).stem)
            print(f"处理视频: {Path(input_folder).stem}")
            extract_frames(input_folder, output_folder, num_frames)
        else:
            print(f"错误: {input_folder} 不是MP4文件")
        return

    # 以下是文件夹处理逻辑
    if not os.path.exists(input_folder):
        print(f"错误: 输入文件夹 {input_folder} 不存在")
        return

    video_files = []
    for file in os.listdir(input_folder):
        if file.lower().endswith('.mp4'):
            video_files.append(os.path.join(input_folder, file))

    if not video_files:
        print(f"在 {input_folder} 中没有找到MP4文件")
        return

    print(f"找到 {len(video_files)} 个MP4视频文件")

    os.makedirs(output_base_folder, exist_ok=True)

    for video_path in video_files:
        video_name = Path(video_path).stem
        output_folder = os.path.join(output_base_folder, video_name)
        print(f"\n处理视频: {video_name}")
        extract_frames(video_path, output_folder, num_frames)


def main():
    # 配置参数
    input_path = r"E:\cotton2026\test\VID_20260703_142950.mp4"  # 修改为你的视频文件夹路径,也可以指定单个文件
    output_folder = r"E:\cotton2026\pic"  # 修改为输出文件夹路径
    frames_to_extract = 60  # 要抽取的帧数

    # 如果提供了命令行参数
    if len(sys.argv) > 1:
        input_path = sys.argv[1]
    if len(sys.argv) > 2:
        output_folder = sys.argv[2]
    if len(sys.argv) > 3:
        try:
            frames_to_extract = int(sys.argv[3])
        except ValueError:
            print("帧数必须是整数,使用默认值60")

    print(f"输入路径: {input_path}")
    print(f"输出文件夹: {output_folder}")
    print(f"每视频抽帧数: {frames_to_extract}")

    process_folder(input_path, output_folder, frames_to_extract)


if __name__ == "__main__":
    main()

二、对齐照片

工作流程-对齐照片

对齐之后就会看到下面这样的样子:

首先需要确保一圈都有一帧,这样才没有缺失,但是也不能保证它能重建完全,还需后续的调整。

生成这种小点之后,可以删除掉不需要的点:

出现上面的这种,帧也圈红了的情况就不行,这个应该是需要留着的。

删完之后,点击"工作流程-生成模型"

三、生成点云

"工作流程-生成点云"

看着能生成密集点云就可以。

至少生成的点云保证能看到茎和叶。

这个结果可以在下面这个里面找:

上面的这个是我还没删除完全生成的点云,效果也不是很好,只是作为一个使用软件的举例,但是最好是试试其他的帧数还能不能更全面。

ok,这个就先这样。

相关推荐
杨杨杨大侠16 分钟前
Jev、Kev、Laya:决策模型怎么选,什么时候需要微调?
人工智能·python·agent
LOVE️YOU1 小时前
Python 在定义函数时,究竟定义的是什么?
python
段一凡-华北理工大学1 小时前
大模型应用开发 100 天:Python + LLM 从入门到精通 day26~Prompt 调试与优化——A/B 测试与效果评估
windows·python·大模型·prompt·智能体·提示词工程·高炉智能化
Minecraft红客1 小时前
以撒的结合
python·游戏·电脑·娱乐
Circ.1 小时前
Python 调试 Litellm 本地大模型接口:模型列表与对话接口实操踩坑记录
开发语言·python
风早爽太2 小时前
用 ‌Render‌ 快速部署网站和常见问题解决
python·fastapi
李航19833 小时前
给自己的图形引擎,配上了AI渲染,做设计真是太方便了
人工智能·python·计算机视觉·ai·ai编程
L@ncor3 小时前
第六章 框架开发实践 · 学习笔记(AutoGen / AgentScope / CAMEL / LangGraph)
python·框架·autogen·langgraph·agentscope
Zhou1411363 小时前
SpringSecurity_02_授权与高级功能
开发语言·python
摇滚侠5 小时前
《On Java 中文版 基础卷》阅读笔记 对象无处不在 03
java·笔记·python