open_input_file函数调用结构图

本文介绍了FFmpeg中打开和解析媒体文件的过程,包括使用avformat_open_input打开输入流,avformat_find_stream_info获取流信息,以及相关配置选项的设置。

open_input_file函数调用结构图(有些重复的函数调用就略掉了,大致是按流程往下的)。


函数大致说明:

AVFormatContext *avformat_alloc_context(void);

函数介绍:
 Allocate an AVFormatContext.
 avformat_free_context() can be used to free the context and everything
 allocated by the framework within it.

说明:为AVFormatContext分配空间,并设置缺省值,申请的空间用avformat_free_context()释放。

int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags);

函数介绍:
Set the given entry in *pm, overwriting an existing entry.
 *
 * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set,
 * these arguments will be freed on error.
 *
 * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL
 * a dictionary struct is allocated and put in *pm.
 * @param key entry key to add to *pm (will be av_strduped depending on flags)
 * @param value entry value to add to *pm (will be av_strduped depending on flags).
 *        Passing a NULL value will cause an existing entry to be deleted.
 * @return >= 0 on success otherwise an error code <0

说明:设置给定的AVDictionary数组,会覆盖已经存在的数据。

static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)

函数说明:寻找编码器,找不到就退出程序。

AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags);

函数说明:根据key来查找AVDictionaryEntry。

int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);

函数介绍:
/**
 * Open an input stream and read the header. The codecs are not opened.
 * The stream must be closed with avformat_close_input().
 *
 * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
 *           May be a pointer to NULL, in which case an AVFormatContext is allocated by this
 *           function and written into ps.
 *           Note that a user-supplied AVFormatContext will be freed on failure.
 * @param filename Name of the stream to open.
 * @param fmt If non-NULL, this parameter forces a specific input format.
 *            Otherwise the format is autodetected.
 * @param options  A dictionary filled with AVFormatContext and demuxer-private options.
 *                 On return this parameter will be destroyed and replaced with a dict containing
 *                 options that were not found. May be NULL.
 *
 * @return 0 on success, a negative AVERROR on failure.
 *
 * @note If you want to use custom IO, preallocate the format context and set its pb field.
 */
说明:打开input流并读取头信息,打开的流必须用avformat_close_input()关闭。

static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)

函数说明:先调用MATCH_PER_STREAM_OPT匹配出codec_names若成功匹配,则调用find_codec_or_die查找解码器,若不成功则调用avcodec_find_decoder查找解码器。

AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts);

函数介绍:
/**
 * Setup AVCodecContext options for avformat_find_stream_info().
 *
 * Create an array of dictionaries, one dictionary for each stream
 * contained in s.
 * Each dictionary will contain the options from codec_opts which can
 * be applied to the corresponding stream codec context.
 *
 * @return pointer to the created array of dictionaries, NULL if it
 * cannot be created
 */
说明:为avformat_find_stream_info函数创建AVDictionary**。

int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

函数介绍:
/**
 * Read packets of a media file to get stream information. This
 * is useful for file formats with no headers such as MPEG. This
 * function also computes the real framerate in case of MPEG-2 repeat
 * frame mode.
 * The logical file position is not changed by this function;
 * examined packets may be buffered for later processing.
 *
 * @param ic media file handle
 * @param options  If non-NULL, an ic.nb_streams long array of pointers to
 *                 dictionaries, where i-th member contains options for
 *                 codec corresponding to i-th stream.
 *                 On return each dictionary will be filled with options that were not found.
 * @return >=0 if OK, AVERROR_xxx on error
 *
 * @note this function isn't guaranteed to open all the codecs, so
 *       options being non-empty at return is a perfectly normal behavior.
 *
 * @todo Let the user decide somehow what information is needed so that
 *       we do not waste time getting stuff the user does not need.
 */
说明:读取media的packets来获取stram info,可用于读取没有头的MPEG文件信息,也可以计算MPEG-2 repeat frame mode的实际framerate。

static void add_input_streams(OptionsContext *o, AVFormatContext *ic)

函数介绍:
/* Add all the streams from the given input file to the global
 * list of input streams. */
说明:把给定的输入文件中的流加入全局输入流list里去。可以从函数调用图里看到,此函数用流的数目来做循环。

void av_dump_format(AVFormatContext *ic, int index, const char *url,  int is_output);

函数介绍:
/**
 * Print detailed information about the input or output format, such as
 * duration, bitrate, streams, container, programs, metadata, side data,
 * codec and time base.
 *
 * @param ic        the context to analyze
 * @param index     index of the stream to dump information about
 * @param url       the URL to print, such as source or destination file
 * @param is_output Select whether the specified context is an input(0) or output(1)
 */
说明:打印信息,如:duration, bitrate, streams, container, programs, metadata, side data, codec and time base。

static AVDictionary *strip_specifiers(AVDictionary *dict)

函数介绍:
/* return a copy of the input with the stream specifiers removed from the keys */
说明:拷贝dict。


<think>我们正在处理用户在使用mmdet3d进行三维目标检测可视化时遇到的断言错误:`AssertionError: assert 'img' in data_input`。这个错误发生在调用`visualizer.add_datasample()`方法时,因为`data_input`(即`Det3DDataSample`对象)中缺少必需的`'img'`字段。 根据引用[1]和引用[3]的信息,我们知道在数据集中,图像信息通常包含在类似`images`的字段中,其中包含图像的文件名、尺寸等。而在mmdet3d中,`Det3DDataSample`对象需要包含`img`属性(存储图像数据)和`metainfo`(存储元数据,如相机参数)等。 ### 问题原因 1. **缺失图像数据**:`Det3DDataSample`对象中必须包含`img`属性,该属性应是一个`numpy.ndarray`,形状为`(H, W, 3)`,表示RGB图像。 2. **元数据不完整**:`metainfo`中必须包含相机参数,特别是`'cam2img'`(相机内参矩阵)和`'lidar2cam'`(激光雷达到相机的变换矩阵),用于将3D检测框投影到2D图像上。 3. **预测实例缺失**:`pred_instances_3d`属性(存储3D检测结果)也必须存在。 ### 解决方案 #### 步骤1:验证并修复数据样本 确保你的`Det3DDataSample`对象包含以下字段: - `img`:图像数据(numpy数组) - `metainfo`:包含`'cam2img'`和`'lidar2cam'`等关键元数据的字典 - `pred_instances_3d`:包含`bboxes_3d`(3D边界框)和`scores_3d`(置信度分数)的`InstanceData`对象 如果从模型推理得到的`data_sample`缺少`img`,你需要手动添加: ```python # 假设data_sample是模型输出的Det3DDataSample对象 # 从文件加载图像 import mmcv img = mmcv.imread('path/to/image.jpg') # 返回numpy数组,形状为(H, W, 3) # 将图像添加到data_sample data_sample.img = img # 确保metainfo包含必要的相机参数 data_sample.set_metainfo({ 'cam2img': camera_intrinsic_matrix, # 4x4相机内参矩阵 'lidar2cam': lidar_to_camera_matrix # 4x4变换矩阵 }) ``` #### 步骤2:正确调用可视化函数 在调用`visualizer.add_datasample()`时,确保传递了正确的参数: ```python # 创建可视化器 from mmdet3d.apis import Det3DInferencer visualizer = Det3DInferencer.get_visualizer() # 添加数据样本进行可视化 visualizer.add_datasample( name='demo', # 样本名称 image=data_sample.img, # 图像数据(也可以不传,但data_sample中必须有img) data_sample=data_sample, # 包含预测结果和元数据的Det3DDataSample draw_gt=False, # 是否绘制真实标注 draw_pred=True, # 是否绘制预测结果 show=True, # 是否显示图像 wait_time=0, # 显示时间(0表示手动关闭) out_file='result.jpg' # 输出文件路径 ) ``` #### 步骤3:验证数据结构 在调用可视化之前,检查`data_sample`是否包含必需的字段: ```python assert hasattr(data_sample, 'img'), "缺少img属性" assert 'cam2img' in data_sample.metainfo, "metainfo缺少cam2img" assert 'lidar2cam' in data_sample.metainfo, "metainfo缺少lidar2cam" assert hasattr(data_sample, 'pred_instances_3d'), "缺少预测结果" ``` ### 完整示例代码 以下是一个完整的示例,展示如何准备数据并调用可视化函数: ```python import numpy as np import mmcv from mmdet3d.structures import Det3DDataSample, LiDARInstance3DBoxes from mmengine.structures import InstanceData # 1. 创建模拟数据 # 图像数据 img = mmcv.imread('demo/image.jpg') # 替换为你的图像路径 # 模拟3D检测结果:10个边界框,每个边界框7个参数(x, y, z, l, w, h, yaw) bboxes_3d = np.random.rand(10, 7).astype(np.float32) scores_3d = np.random.rand(10).astype(np.float32) # 2. 构建Det3DDataSample data_sample = Det3DDataSample() data_sample.img = img # 设置图像 data_sample.pred_instances_3d = InstanceData() data_sample.pred_instances_3d.bboxes_3d = LiDARInstance3DBoxes(bboxes_3d) # 注意转换为LiDARInstance3DBoxes data_sample.pred_instances_3d.scores_3d = scores_3d # 3. 设置元数据(关键!) # 相机内参矩阵(4x4,这里用单位矩阵示例) cam2img = np.eye(4) # 激光雷达到相机的变换矩阵(4x4) lidar2cam = np.eye(4) data_sample.set_metainfo({ 'cam2img': cam2img, 'lidar2cam': lidar2cam, 'img_path': 'demo/image.jpg' # 可选的图像路径 }) # 4. 可视化 from mmdet3d.apis import Det3DInferencer visualizer = Det3DInferencer.get_visualizer() visualizer.add_datasample( '3d_detection', image=data_sample.img, data_sample=data_sample, out_file='output.jpg' ) ``` ### 常见问题及解决方法 1. **`AssertionError: assert 'img' in data_input`**: - 确保`data_sample`有`img`属性,且是numpy数组。 2. **`KeyError: 'cam2img'`**: - 在`metainfo`中添加`'cam2img'`矩阵。 3. **3D框投影错误**: - 检查`lidar2cam`矩阵是否正确,确保坐标变换正确。 4. **图像显示空白**: - 检查图像数据是否损坏,确保`img`是有效的RGB图像数组。 ### 相关问题 1. 如何将KITTI格式的3D检测结果转换为`Det3DDataSample`对象? 2. 当处理多模态数据时如何设置`Det3DDataSample`的相机/雷达参数? 3. 如何解决3D框投影到2D图像时的坐标转换错误? 4. 在自定义数据集上如何正确配置`metainfo`字段? 5. `InstanceData`与`Det3DDataSample`如何协同工作?</think>### 解决 `AssertionError: assert 'img' in data_input` 错误 在使用 mmdet3d 进行三维实例可视化时,遇到 `AssertionError: assert 'img' in data_input` 错误表明您的 `Det3DDataSample` 对象缺少必需的 `img` 属性。以下是系统化的解决方案: #### 问题原因分析 1. **核心缺失字段**: - `Det3DDataSample` 必须包含 `img` 字段(存储图像数据) - 必须包含 `metainfo` 字典(存储相机参数等元数据) - 需要 `pred_instances_3d` 或 `gt_instances_3d`(存储检测结果) 2. **典型错误场景**: ```python # ❌ 错误调用:缺少img字段 visualizer.add_datasample( name="demo", data_sample=data # Det3DDataSample对象 ) ``` #### 完整解决方案 ##### 步骤1:验证数据结构 ```python # ✅ 检查关键字段是否存在 assert hasattr(data, 'img'), "缺少img字段" assert hasattr(data, 'metainfo'), "缺少metainfo字典" assert 'cam2img' in data.metainfo, "metainfo缺少cam2img参数" assert hasattr(data, 'pred_instances_3d'), "缺少预测结果" ``` ##### 步骤2:修复数据样本 ```python from mmdet3d.structures import Det3DDataSample from mmengine.structures import InstanceData # ✅ 重建有效数据样本 fixed_data = Det3DDataSample() fixed_data.img = your_image_data # 形状为 (H, W, 3) 的numpy数组 fixed_data.pred_instances_3d = InstanceData( bboxes_3d=pred_boxes, # 3D边界框 scores_3d=pred_scores # 置信度分数 ) fixed_data.metainfo = { 'cam2img': camera_intrinsic, # 相机内参矩阵(4x4) 'lidar2cam': lidar_to_cam, # 激光雷达到相机的变换 'img_path': image_path # 原始图像路径 } ``` ##### 步骤3:正确调用可视化函数 ```python # ✅ 完整调用示例 visualizer.add_datasample( name="3d_det_result", image=fixed_data.img, # 显式传递图像数据 data_sample=fixed_data, draw_gt=False, # 是否绘制真实标注 draw_pred=True, # 是否绘制预测结果 show=True, # 是否显示图像 wait_time=0, # 显示时间(0=手动关闭) out_file="result.jpg" # 输出文件路径 ) ``` #### 关键参数说明 | 参数 | 必需 | 格式要求 | 获取方式 | |------|------|----------|----------| | `img` | ✓ | `np.ndarray` (H, W, 3) | `mmcv.imread()` | | `metainfo['cam2img']` | ✓ | `np.array` (4x4) | 数据集校准文件 | | `pred_instances_3d` | ✓ | `InstanceData` | 模型输出转换 | | `metainfo['lidar2cam']` | ✓ | `np.array` (4x4) | 坐标变换矩阵 | #### 常见错误处理表 | 错误类型 | 解决方案 | |---------|---------| | `KeyError: 'cam2img'` | 添加相机内参到`metainfo` | | `AttributeError: img` | 显式传递`image`参数 | | `TypeError: bboxes_3d` | 转换为`BaseInstance3DBoxes`类型 | | `AssertionError: scale` | 检查坐标系统一致性(LiDAR/Camera)[^3] | #### 完整工作流示例 ```python # 1. 加载图像和点云 img = mmcv.imread("demo/image.jpg") pcd = np.fromfile("demo/pointcloud.bin", dtype=np.float32) # 2. 模型推理 result, data_sample = inference_detector(model, pcd) # 3. 修复数据样本 data_sample.img = img # 添加图像数据 data_sample.metainfo.update({ 'cam2img': np.array([[720,0,600],[0,720,180],[0,0,1]]), 'lidar2cam': np.load("calib/lidar2cam.npy") }) # 4. 可视化 visualizer.add_datasample( "result", image=img, data_sample=data_sample, out_file="output.jpg" ) ``` > **关键验证点**:确保在调用前执行 `print(data_sample.keys())` 应包含 `['img', 'metainfo', 'pred_instances_3d']` 等关键字段[^3]。 ### 相关问题 1. 如何将KITTI格式的3D检测结果转换为`Det3DDataSample`对象? 2. 当处理多模态数据时如何设置`Det3DDataSample`的相机/雷达参数? 3. 如何解决3D框投影到2D图像时的坐标转换错误? 4. 在自定义数据集上如何正确配置`metainfo`字段? 5. `InstanceData`与`Det3DDataSample`如何协同工作?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dancing_night

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

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

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

打赏作者

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

抵扣说明:

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

余额充值