ofa_image-caption代码实例:扩展支持WebP格式与EXIF元数据保留功能
ofa_image-caption代码实例:扩展支持WebP格式与EXIF元数据保留功能
1. 引言
你有没有遇到过这种情况?从手机或相机里导出一堆照片,想快速整理归档,却要一张张手动写描述,费时又费力。或者,在做内容创作时,需要为大量图片配上精准的英文说明,人工处理效率极低。
今天要介绍的这个工具,就是来解决这个痛点的。它叫 ofa_image-caption,是一个纯本地运行的图像描述生成工具。简单来说,你给它一张图,它就能用英文告诉你这张图里有什么。
这个工具的核心是基于一个叫 OFA 的模型,这个模型在图像描述生成领域表现很不错。我们之前发布的版本已经能很好地处理 JPG、PNG 这些常见格式了。但最近,越来越多的用户开始使用 WebP 这种更高效的图片格式,同时,很多摄影师和内容创作者也希望生成的描述能保留图片拍摄时的原始信息(比如拍摄时间、相机型号)。
所以,我们对这个工具进行了一次重要的升级。这篇文章,我就带你手把手看看,我们是如何在原有代码基础上,扩展了对 WebP 格式的支持,并实现了 EXIF 元数据的保留功能。整个过程就像给一个工具加上了两个非常实用的“配件”,让它能适应更多场景,更好用。
2. 项目回顾与升级目标
在开始动手改代码之前,我们先快速回顾一下这个工具原本是干什么的,以及我们这次想让它变得多能干。
2.1 原有工具的核心功能
这个工具本质上是一个本地化的“看图说话”小助手。它的工作流程非常清晰:
- 你上传一张图片(之前支持 JPG, PNG, JPEG)。
- 工具在后台调用 OFA 模型,这个模型是专门在 COCO 英文数据集上训练过的,所以它“说”的是英文。
- 工具把模型生成的英文描述,通过一个简洁的网页界面展示给你看。
整个工具基于 ModelScope 和 Streamlit 搭建,最大的优点就是纯本地运行,你的图片数据不会上传到任何服务器,隐私有保障,而且如果电脑有独立显卡(GPU),推理速度会非常快。
2.2 本次升级要解决的两个问题
随着用户增多,我们收到了两类反馈:
- 格式支持问题:“我有很多网站截图和素材是 WebP 格式的,上传不了,还得先转换,太麻烦了。”
- 信息关联问题:“生成的描述很好,但如果能和我照片自带的拍摄信息(EXIF)一起保存下来,对我后续整理和归档就太有帮助了。”
因此,我们这次代码升级的目标非常明确:
- 目标一:让工具能直接读取和处理 WebP 格式的图片。
- 目标二:在生成描述的同时,把图片原始的 EXIF 元数据(如果有的话)提取并保留下来,方便后续使用。
下面,我们就进入实战环节,看看代码具体是怎么改的。
3. 代码实战:扩展WebP格式支持
原来工具里,限制图片格式的代码可能长这样(在文件上传组件处):
uploaded_file = st.file_uploader( " 上传图片", type=['jpg', 'jpeg', 'png'] # 这里只定义了三种格式 ) 看到问题了吗?type 列表里没有 webp。所以用户上传 WebP 文件时,会被直接过滤掉,根本选不中。
解决方案非常简单,只需要加一个后缀名:
uploaded_file = st.file_uploader( " 上传图片", type=['jpg', 'jpeg', 'png', 'webp'] # 新增 ‘webp’ ) 但是,故事还没完。 Streamlit 的 file_uploader 只是前端的“门卫”,它放行了 WebP 文件。文件传到后台 Python 代码里,我们需要用 PIL(Python 图像处理库)来打开它。如果 PIL 版本太旧,可能不认识 WebP。
所以,我们需要确保开发环境和部署环境里的 PIL(或其社区维护的活跃分支 Pillow)支持 WebP。这通常不是大问题,因为现代版本的 Pillow 基本都支持。不过,为了万无一失,我们可以在项目的依赖文件(如 requirements.txt)里明确一下 Pillow 的版本。
# requirements.txt 示例 streamlit>=1.28.0 modelscope>=1.9.0 pillow>=9.0.0 # 确保使用一个较新且稳定支持WebP的版本 这样一来,从上传到打开,整个通路就对 WebP 格式畅通无阻了。用户现在可以直接上传 .webp 文件,工具会像处理 JPG 一样处理它。
4. 代码实战:提取与保留EXIF元数据
EXIF 是嵌入在图片文件里的一串信息,就像图片的“身份证”,记录着拍摄设备、时间、光圈、快门甚至 GPS 位置等。保留这些信息对摄影爱好者、内容管理非常有价值。
4.1 如何提取EXIF信息
我们继续使用 Pillow 库。一张图片被 PIL 打开后,我们可以通过 _getexif() 方法来尝试获取其 EXIF 数据。
下面是一个简单的函数示例,我们把它加到工具的核心代码里:
from PIL import Image import PIL.ExifTags def extract_exif(image_path): """ 提取图片的EXIF元数据。 参数: image_path: 图片文件的路径。 返回: 一个字典,包含可读的EXIF标签和值;如果无EXIF或读取失败,返回空字典。 """ exif_data = {} try: img = Image.open(image_path) # 获取原始的EXIF数据 info = img._getexif() if info: # 将数字标签码转换为可读的字符串标签 for tag, value in info.items(): decoded_tag = PIL.ExifTags.TAGS.get(tag, tag) exif_data[decoded_tag] = value except Exception as e: # 记录错误或忽略(对于没有EXIF的图片是正常的) print(f"读取EXIF时出错: {e}") return exif_data 这个函数做了几件事:
- 尝试用 PIL 打开图片。
- 调用
_getexif()获取原始数据。 - 将枯燥的数字标签(如 36867)转换成我们能看懂的文字(如
DateTimeOriginal)。 - 把所有信息存到一个字典里返回。
4.2 如何与描述结果一起展示
光提取出来还不够,我们需要让用户看到它。一个直观的做法是,在 Streamlit 界面上生成描述后,新增一个展示区域来显示 EXIF。
假设我们原来的结果显示是这样的:
if caption: st.success("生成成功!") st.markdown(f"**生成描述:** {caption}") 现在我们可以升级一下:
if caption: st.success("生成成功!") st.markdown(f"**生成描述:** {caption}") # 新增:提取并显示EXIF信息 exif_info = extract_exif(temp_image_path) # temp_image_path是工具保存的临时图片路径 if exif_info: with st.expander("📸 查看图片EXIF元数据"): # 用一个可折叠区域,保持界面整洁 # 展示一些最常见、最有用的EXIF字段 if 'DateTimeOriginal' in exif_info: st.text(f"拍摄时间: {exif_info['DateTimeOriginal']}") if 'Make' in exif_info and 'Model' in exif_info: st.text(f"拍摄设备: {exif_info['Make']} {exif_info['Model']}") if 'ExposureTime' in exif_info: st.text(f"曝光时间: {exif_info['ExposureTime']} 秒") if 'FNumber' in exif_info: st.text(f"光圈值: f/{exif_info['FNumber']}") if 'ISOSpeedRatings' in exif_info: st.text(f"ISO感光度: {exif_info['ISOSpeedRatings']}") # 用户可以选择查看所有EXIF数据 if st.checkbox("显示全部EXIF信息"): st.json(exif_info) # 用JSON格式美观地展示 else: st.info("此图片未包含EXIF元数据。") 这样一来,工具在生成英文描述后,如果图片有 EXIF,用户就能一目了然地看到关键的拍摄信息,并且可以展开查看全部详情。这对于需要根据拍摄信息来分类或描述图片的用户来说,功能就完整多了。
5. 完整功能演示与效果
让我们把上面所有的代码片段组合起来,看看升级后的工具实际运行效果如何。
5.1 操作流程演示
- 启动工具:在命令行运行
streamlit run app.py,打开浏览器。 - 上传混合格式图片:你可以同时尝试上传
test.jpg,screenshot.png, 和photo.webp。你会发现,现在所有格式都能被成功选中并上传。 - 生成描述与查看EXIF:
- 上传一张用单反或手机拍摄的、带有EXIF的JPG照片(比如你相机里的原图)。
- 点击“生成描述”。稍等片刻,界面首先会弹出绿色的成功提示,并显示生成的英文描述,例如 “生成描述: a person is riding a skateboard on a street.”
- 在描述下方,会出现一个写着 “📸 查看图片EXIF元数据” 的可点击区域。点击展开,你就能看到拍摄时间、相机型号等具体信息。
- 如果上传的是一张从网络下载的、已剥离EXIF的PNG图片,或者是一张简单的截图,那么工具会友好地提示“此图片未包含EXIF元数据”。
5.2 升级带来的价值
通过这两项看似不大的升级,这个本地图像描述工具的能力边界得到了有效拓展:
- 格式兼容性更强:无缝支持WebP,覆盖了更广泛的图片来源,特别是互联网内容。
- 信息维度更丰富:从单一的“视觉内容描述”升级为“视觉内容+拍摄元数据”的复合信息输出。这使得生成的结果不再是孤立的文本,而是能与原始资产(照片)紧密关联的结构化信息。
- 应用场景更广:对于摄影师,可以快速批量为照片库生成描述并附带拍摄参数;对于内容管理者,可以更好地对图片素材进行自动化打标和归档。
6. 总结
回顾一下我们这次对 ofa_image-caption 工具的升级之旅。整个过程就像是一次精准的“外科手术”:
- 诊断需求:我们发现了用户在处理 WebP 格式和需要 EXIF 信息时的痛点。
- 实施改造:
- 通过修改
file_uploader的type列表,轻松扩展了 WebP 格式支持。 - 通过编写
extract_exif函数并集成到结果展示界面,优雅地实现了 EXIF 元数据的提取与展示。
- 通过修改
- 验证效果:升级后的工具,在保持原有核心功能(快速、本地、英文描述)的同时,显著提升了实用性和用户体验。
这个案例也告诉我们,一个好的工具并非一成不变。围绕用户真实的使用场景,通过一些针对性的、轻量级的代码改进,就能让工具焕发新的活力,解决更实际的问题。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 ZEEKLOG星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。