news 2026/3/9 10:52:56

批量识别多张图片?Python脚本扩展教程来了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
批量识别多张图片?Python脚本扩展教程来了

批量识别多张图片?Python脚本扩展教程来了

1. 为什么单张识别不够用:从“能跑通”到“真可用”的关键一步

你已经成功运行了推理.py,看到终端输出“白领女性”“办公室工作场景”这些中文标签时,心里一定很踏实——模型确实能工作。但很快你会发现,现实中的需求从来不是一张图、一次识别。

电商运营要审核上千张商品图;教育平台需自动标注学生上传的实验照片;内容社区每天收到数万张用户投稿……这些场景下,手动改一次路径、运行一次脚本,不仅效率低得让人抓狂,还极易出错:漏改路径、忘记保存、结果混在一起分不清哪张对应哪个输出。

真正的工程落地,不看“能不能识别一张”,而看“能不能稳稳识别一百张、一千张”。本文不重复讲环境怎么装、模型怎么加载——那些你已经会了。我们直接聚焦如何把单图识别脚本,变成一个可靠、可复用、能处理真实业务数据的批量识别工具

全程基于你已有的镜像环境(PyTorch 2.5 +py311wwtsconda 环境),无需额外安装复杂依赖,所有代码均可直接复制粘贴运行。你会学到:

  • 怎么让脚本自动扫描整个文件夹里的图片,不用再手动改路径
  • 怎么把每次识别的结果清晰记录下来,避免结果堆在终端里找不到
  • 怎么跳过损坏图片、跳过非支持格式,让批量任务不因一张坏图就中断
  • 怎么控制识别速度和显存占用,让老显卡也能扛住百图连跑

这不是理论推演,而是你明天就能用上的实操方案。

2. 批量识别核心改造:四步重构原脚本

推理.py是为单图设计的:硬编码路径、单次执行、结果只打印到屏幕。我们要让它“长大”,支撑真实工作流。改造不追求大动干戈,而是精准替换四个关键环节。

2.1 第一步:从固定路径到动态遍历

原脚本中这行代码是瓶颈:

image_path = "/root/workspace/bailing.png"

它把脚本锁死在一张图上。我们需要它能“自己找图”。

改造方案:使用glob模块匹配指定目录下所有常见图片格式,并加入容错检查:

import glob import os # 定义图片搜索目录(你可按需修改) input_dir = "/root/workspace/test_images" # 支持的图片格式(小写+大写都覆盖) supported_exts = ["*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tiff", "*.webp"] image_paths = [] for ext in supported_exts: image_paths.extend(glob.glob(os.path.join(input_dir, ext))) image_paths.extend(glob.glob(os.path.join(input_dir, ext.upper()))) # 去重并排序,确保顺序一致 image_paths = sorted(list(set(image_paths))) print(f"共找到 {len(image_paths)} 张待识别图片") if not image_paths: print(" 警告:未找到任何图片,请检查目录路径和文件格式") exit(1)

效果:脚本启动后自动列出/root/workspace/test_images下所有图片,无论你放1张还是100张,它都“看得见”。

2.2 第二步:从屏幕打印到结构化记录

原脚本把结果全打在终端里,100张图的输出就是一长串滚动文字,根本没法查。我们需要结果“落盘”,且格式清晰。

改造方案:用CSV文件记录每张图的Top-5结果,包含文件名、识别标签、置信度、处理时间:

import csv import time # 创建结果CSV文件 output_csv = "/root/workspace/batch_results.csv" with open(output_csv, "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) # 写入表头 writer.writerow(["文件名", "排名", "中文标签", "置信度(%)", "处理耗时(秒)"]) # 在循环处理每张图时,追加写入 for i, img_path in enumerate(image_paths): start_time = time.time() try: # 【此处插入原推理逻辑:加载图、预处理、模型推理、获取top5】 # (具体代码见2.4节完整脚本) # 记录结果 with open(output_csv, "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) for rank, (label, prob) in enumerate(zip(top5_labels, top5_probs), 1): writer.writerow([ os.path.basename(img_path), rank, label, f"{prob:.1f}", f"{time.time() - start_time:.2f}" ]) print(f" 已处理 {i+1}/{len(image_paths)}: {os.path.basename(img_path)}") except Exception as e: # 关键:单张失败不中断整体流程 error_msg = str(e)[:100] # 截断过长错误信息 print(f" 处理失败 {os.path.basename(img_path)}: {error_msg}") with open(output_csv, "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow([os.path.basename(img_path), "ERROR", str(e), "", ""])

效果:运行结束后,batch_results.csv里是一张清晰表格,Excel双击就能打开,按“文件名”筛选、按“置信度”排序,一目了然。

2.3 第三步:从硬编码标签到动态加载中文词表

原脚本示例里,labels是写死的列表:

labels = ["白领女性", "办公室工作场景", "..."]

这完全不可靠。真实模型的中文标签有上万个,必须从官方配套文件读取。

改造方案:检查镜像中是否存在label_map_zh.jsonlabel_map_zh.csv,优先加载JSON(更通用):

import json # 尝试加载中文标签映射文件 label_file = None for candidate in ["/root/label_map_zh.json", "/root/workspace/label_map_zh.json"]: if os.path.exists(candidate): label_file = candidate break if label_file: with open(label_file, "r", encoding="utf-8") as f: label_map = json.load(f) # 假设JSON结构为 { "0": "盆栽植物", "1": "笔记本电脑", ... } # 将数字ID转为中文标签 top5_labels = [label_map.get(str(idx.item()), f"未知类别{idx.item()}") for idx in top5_catid] else: print(" 未找到中文标签文件,将使用模型内置默认标签(可能为英文)") # 回退到模型自带方法(如 model.get_labels()) top5_labels = [model.get_label(idx.item()) for idx in top5_catid]

效果:你的结果永远是准确的中文,不会因为忘了更新硬编码列表而出现“potted plant”这种尴尬输出。

2.4 第四步:从单次执行到可控批量——添加实用开关

真实场景需要灵活性:有时只想试跑前10张,有时要跳过低置信度结果,有时显存紧张得降分辨率。

改造方案:在脚本开头添加配置区,用变量控制行为:

# ========== 批量识别配置区(按需修改)========== BATCH_SIZE = 1 # 每次送入模型的图片数(1=逐张,>1需改代码适配batch推理) MAX_IMAGES = 100 # 最多处理多少张(设为None则处理全部) MIN_CONFIDENCE = 0.5 # 低于此置信度的标签不写入结果(0.0~1.0) RESIZE_SHORTER_SIDE = 256 # 图像短边缩放尺寸(原256,显存紧可设128) # ================================================= # 在图像预处理部分应用缩放 preprocess = transforms.Compose([ transforms.Resize(RESIZE_SHORTER_SIDE), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ])

效果:只需改几个数字,就能适应不同硬件和业务需求,不用每次重写逻辑。

3. 完整可运行脚本:复制即用,开箱批量识别

下面是你可以直接保存为batch_inference.py并运行的完整代码。它整合了上述所有改造,已通过镜像环境实测。

# -*- coding: utf-8 -*- # batch_inference.py - 万物识别中文版批量处理脚本 import torch import glob import os import csv import time import json from PIL import Image from torchvision import transforms import numpy as np # ========== 批量识别配置区(按需修改)========== input_dir = "/root/workspace/test_images" # 待识别图片所在文件夹 output_csv = "/root/workspace/batch_results.csv" # 结果保存路径 BATCH_SIZE = 1 MAX_IMAGES = None # 设为数字如50,只处理前50张;设为None处理全部 MIN_CONFIDENCE = 0.3 RESIZE_SHORTER_SIDE = 256 # ================================================= def load_chinese_labels(): """尝试加载中文标签映射文件""" for candidate in [ "/root/label_map_zh.json", "/root/workspace/label_map_zh.json", "/root/label_map_zh.csv" ]: if os.path.exists(candidate): if candidate.endswith(".json"): with open(candidate, "r", encoding="utf-8") as f: return json.load(f) else: # CSV格式,假设第一列是ID,第二列是中文标签 import csv labels = {} with open(candidate, "r", encoding="utf-8") as f: reader = csv.reader(f) for row in reader: if len(row) >= 2: labels[row[0].strip()] = row[1].strip() return labels return None def main(): print(" 正在搜索图片...") supported_exts = ["*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tiff", "*.webp"] image_paths = [] for ext in supported_exts: image_paths.extend(glob.glob(os.path.join(input_dir, ext))) image_paths.extend(glob.glob(os.path.join(input_dir, ext.upper()))) image_paths = sorted(list(set(image_paths))) if not image_paths: print(" 错误:未在", input_dir, "中找到任何图片文件") return if MAX_IMAGES: image_paths = image_paths[:MAX_IMAGES] print(f" 共找到 {len(image_paths)} 张图片,开始批量识别...") # 加载模型 print("⏳ 正在加载模型...") device = torch.device("cuda" if torch.cuda.is_available() else "cpu") try: model = torch.hub.load('alibaba-damo-academy/vision', 'universal_image_recognition', source='github') model.to(device).eval() print(" 模型加载完成") except Exception as e: print(" 模型加载失败:", e) return # 加载中文标签 label_map = load_chinese_labels() if label_map is None: print(" 未找到中文标签文件,将使用模型内置标签(可能为英文)") # 创建CSV文件并写入表头 with open(output_csv, "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["文件名", "排名", "中文标签", "置信度(%)", "处理耗时(秒)"]) # 图像预处理 preprocess = transforms.Compose([ transforms.Resize(RESIZE_SHORTER_SIDE), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) # 逐张处理 for i, img_path in enumerate(image_paths): start_time = time.time() try: # 加载并预处理图像 image = Image.open(img_path).convert("RGB") input_tensor = preprocess(image) input_batch = input_tensor.unsqueeze(0).to(device) # 推理 with torch.no_grad(): output = model(input_batch) # 后处理 probabilities = torch.nn.functional.softmax(output[0], dim=0) top5_prob, top5_catid = torch.topk(probabilities, 5) # 获取中文标签 if label_map: top5_labels = [] for idx in top5_catid: key = str(idx.item()) label = label_map.get(key, f"未知类别{key}") top5_labels.append(label) else: # 回退:尝试用模型方法(若模型支持) try: top5_labels = [model.get_label(idx.item()) for idx in top5_catid] except: top5_labels = [f"类别{idx.item()}" for idx in top5_catid] # 写入CSV with open(output_csv, "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) for rank, (label, prob) in enumerate(zip(top5_labels, top5_prob), 1): if prob.item() >= MIN_CONFIDENCE: writer.writerow([ os.path.basename(img_path), rank, label, f"{prob.item()*100:.1f}", f"{time.time() - start_time:.2f}" ]) print(f" [{i+1}/{len(image_paths)}] {os.path.basename(img_path)} -> {top5_labels[0]} ({top5_prob[0].item()*100:.0f}%)") except Exception as e: error_msg = str(e)[:80] print(f" [{i+1}/{len(image_paths)}] {os.path.basename(img_path)} 处理失败: {error_msg}") with open(output_csv, "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow([os.path.basename(img_path), "ERROR", str(e), "", ""]) print(f"\n 批量识别完成!结果已保存至 {output_csv}") print(" 提示:用Excel打开CSV,按'文件名'列筛选可快速查看某张图的全部结果") if __name__ == "__main__": main()

使用步骤

  1. 确保你的镜像已激活:conda activate py311wwts
  2. 创建测试图片文件夹:mkdir -p /root/workspace/test_images
  3. 将你要识别的图片(PNG/JPG等)放入该文件夹
  4. 将上面完整代码保存为/root/workspace/batch_inference.py
  5. 运行:cd /root/workspace && python batch_inference.py

预期输出

正在搜索图片... 共找到 42 张图片,开始批量识别... ⏳ 正在加载模型... 模型加载完成 [1/42] product_001.jpg -> 无线蓝牙耳机 (97%) [2/42] scene_002.png -> 城市街景 (94%) ... 批量识别完成!结果已保存至 /root/workspace/batch_results.csv

4. 实战技巧与避坑指南:让批量更稳、更快、更准

脚本跑通只是起点。在真实数据上长期使用,你会遇到各种“意料之外但情理之中”的问题。以下是基于镜像环境反复验证的实战经验。

4.1 图片损坏?自动跳过,不中断流程

网络下载或手机拍摄的图片常有损坏(如截断的JPG),原生PIL打开会直接报错退出。我们的脚本已内置防护:

try: image = Image.open(img_path).convert("RGB") except Exception as e: print(f" 跳过损坏图片 {os.path.basename(img_path)}: {e}") continue # 直接进入下一张,不终止整个批次

价值:100张图里哪怕有3张打不开,其余97张照常识别,结果CSV里会明确标记为ERROR,你一眼就能定位问题源。

4.2 显存爆了?一键切换CPU模式(不改代码)

当GPU显存不足(尤其处理高分辨率图时),不必重装环境或改脚本。只需在运行命令后加一个环境变量:

# 强制使用CPU(适合显存紧张或无GPU环境) CUDA_VISIBLE_DEVICES="" python batch_inference.py # 或者限制只用第一块GPU(如果有多卡) CUDA_VISIBLE_DEVICES="0" python batch_inference.py

脚本中的torch.device("cuda" if torch.cuda.is_available() else "cpu")会自动响应。

4.3 结果太多?用Excel快速分析Top-N

batch_results.csv导出后,在Excel里:

  • 筛选高频标签:对“中文标签”列使用“数据透视表”,看哪些标签出现最多,反推数据集共性
  • 定位低质结果:筛选“置信度(%)”< 60 的行,集中检查这些图片——是模糊?角度怪?还是模型真不擅长?
  • 统计处理效率:对“处理耗时(秒)”列求平均值,就知道你的硬件每秒能处理几张图

4.4 想加水印或自动归档?两行代码搞定

批量识别后,常需对原图做后续操作。利用Python的shutilPIL,轻松扩展:

# 在识别成功后,自动复制原图到"high_conf"文件夹 if top5_prob[0].item() >= 0.8: # 置信度>80% import shutil shutil.copy2(img_path, "/root/workspace/high_conf/") # 或者给原图加识别结果水印(需安装PIL) from PIL import ImageDraw, ImageFont draw = ImageDraw.Draw(image) font = ImageFont.load_default() draw.text((10, 10), f"{top5_labels[0]} ({top5_prob[0].item()*100:.0f}%)", fill="red") image.save("/root/workspace/annotated/" + os.path.basename(img_path))

5. 总结:批量不是功能,而是生产就绪的标志

当你能把一个单图识别脚本,稳稳地扩展成处理上百张真实业务图片的工具时,你就跨过了从“技术验证”到“工程落地”的关键门槛。

本文没有教你新模型、新算法,而是聚焦于如何让已有的强大能力,在真实场景中真正发挥价值。你掌握的不仅是几行代码,更是:

  • 鲁棒性思维:不假设数据完美,主动处理异常
  • 工程化习惯:结果必须可追溯、可分析、可集成
  • 用户视角:CSV比终端打印友好,配置变量比改代码安全

现在,你的batch_inference.py已经就位。下一步,就是把它用起来:

  • 把竞品官网的商品图扒下来,批量识别看他们主打什么品类
  • 上传自己手机相册里的100张生活照,看看AI眼中的你是什么标签
  • 和同事共享这个脚本,让他也试试识别他收藏的宠物图

技术的温度,不在参数多高,而在它是否伸手可及、触手可用。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/9 3:39:22

ViGEmBus内核驱动创新方案:游戏控制器模拟的跨平台兼容架构解析

ViGEmBus内核驱动创新方案&#xff1a;游戏控制器模拟的跨平台兼容架构解析 【免费下载链接】ViGEmBus 项目地址: https://gitcode.com/gh_mirrors/vig/ViGEmBus 需求分析&#xff1a;破解游戏控制器模拟的三大核心痛点 当你尝试在PC上畅玩主机独占游戏时&#xff0c;…

作者头像 李华
网站建设 2026/3/8 22:26:02

LongCat-Image-Editn镜像使用详解:start.sh脚本原理与服务健康检查方法

LongCat-Image-Edit镜像使用详解&#xff1a;start.sh脚本原理与服务健康检查方法 1. 镜像基础认知与核心能力定位 LongCat-Image-Edit&#xff08;内置模型版&#xff09;V2 是一个开箱即用的图像编辑推理环境&#xff0c;它把美团 LongCat 团队开源的「文本驱动图像编辑」模…

作者头像 李华
网站建设 2026/3/4 13:16:45

Pi0机器人控制中心快速入门:三视角图像+自然语言指令实战

Pi0机器人控制中心快速入门&#xff1a;三视角图像自然语言指令实战 1. 为什么你需要这个控制中心&#xff1f; 你有没有试过对着机器人说“把桌上的蓝色杯子拿过来”&#xff0c;结果它一动不动&#xff1f;或者上传一张图片&#xff0c;却要写几十行代码才能让机器人理解环…

作者头像 李华
网站建设 2026/3/6 3:26:03

5步构建智能任务管理中心:TaskMaster高效办公全攻略

5步构建智能任务管理中心&#xff1a;TaskMaster高效办公全攻略 【免费下载链接】WeChatRedEnvelopesHelper iOS版微信抢红包插件,支持后台抢红包 项目地址: https://gitcode.com/gh_mirrors/we/WeChatRedEnvelopesHelper 你是否也曾遇到过这样的困境&#xff1a;每天被…

作者头像 李华
网站建设 2026/3/7 9:33:45

Pi0 Robot Control Center免配置环境:Docker镜像封装Gradio+LeRobot+Pi0模型

Pi0 Robot Control Center免配置环境&#xff1a;Docker镜像封装GradioLeRobotPi0模型 1. 什么是Pi0机器人控制中心 你有没有想过&#xff0c;让机器人听懂你的一句话&#xff0c;再看懂三张不同角度的照片&#xff0c;然后直接算出下一步该怎样移动六个关节&#xff1f;这不…

作者头像 李华
网站建设 2026/3/8 5:22:51

MedGemma-X效果实测:在低质量X光片(过曝/欠曝/运动伪影)下鲁棒性

MedGemma-X效果实测&#xff1a;在低质量X光片&#xff08;过曝/欠曝/运动伪影&#xff09;下鲁棒性 1. 为什么低质量X光片是临床AI真正的“压力测试” 你有没有遇到过这样的情况&#xff1a;一张刚拍完的胸部X光片&#xff0c;明明患者配合得很好&#xff0c;但图像却一片发…

作者头像 李华