news 2026/4/16 11:50:30

批量处理多张图的方法,我在脚本里加了循环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
批量处理多张图的方法,我在脚本里加了循环

批量处理多张图的方法,我在脚本里加了循环

本文是一篇面向实际工程落地的技术实践笔记,聚焦于如何将阿里开源的“万物识别-中文-通用领域”模型从单图推理升级为批量图像识别能力。不讲抽象原理,不堆砌参数,只说你真正需要的操作:怎么改几行代码,让脚本自动遍历文件夹里的几十张图、逐张识别、统一输出结果,并避免常见坑点。适合已成功运行过单图推理、正准备接入业务流程的开发者。

你可能已经照着教程跑通了第一张图——比如bailing.png,看到终端输出“动物”“人物”“植物”等中文标签,心里踏实了一半。但真实场景中,没人只传一张图:电商要扫千张商品图打标,内容平台要批量审核封面图,智能相册要自动归类几百张家庭照片。这时候,手动改路径、反复执行python 推理.py显然不可持续。本文就解决这个卡点:用最轻量的方式,在原生脚本基础上加入循环逻辑,零依赖、零重构、5分钟完成升级

核心思路非常朴素:把原来写死的一张图路径,换成一个图片列表;把单次推理封装成函数;再用for遍历列表。没有引入新框架,不改动模型加载逻辑,所有修改都在你熟悉的推理.py文件里,改完即用,结果可读、可存、可扩展。

1. 理解原始脚本的单图结构

在动手改之前,先看清原始推理.py的骨架。它本质是三段式结构:加载模型 → 加载单图 → 推理输出。我们不需要重写,只需在关键位置“插针”。

1.1 原始流程拆解(精简版)

# -*- coding: utf-8 -*- import torch from PIL import Image from transformers import AutoModel, AutoProcessor # 【阶段一】模型加载(只做一次) model_name = "bailian/wwts-visual-recognition-base" processor = AutoProcessor.from_pretrained(model_name) model = AutoModel.from_pretrained(model_name) device = "cuda" if torch.cuda.is_available() else "cpu" model.to(device) # 【阶段二】单图加载(当前是硬编码路径) image_path = "/root/workspace/bailing.png" # ← 这里是单点入口 image = Image.open(image_path).convert("RGB") # 【阶段三】单图推理与输出 inputs = processor(images=image, text=["动物", "人物", "交通工具"], return_tensors="pt").to(device) with torch.no_grad(): outputs = model(**inputs) probs = outputs.logits_per_image.softmax(dim=1)[0] top_probs, top_labels = probs.topk(3) class_names = ["动物", "人物", "交通工具"] for i in range(3): idx = top_labels[i].item() print(f"{image_path} → {class_names[idx]} ({top_probs[i].item():.3f})")

注意两个关键事实:

  • 模型加载(阶段一)耗时且占用显存,必须放在循环外,否则每张图都重载,速度暴跌、显存爆满;
  • 图像加载(阶段二)和推理(阶段三)是轻量操作,可以安全放入循环内

这决定了我们的改造边界:只动阶段二和三,阶段一原封不动。

2. 批量处理四步法:从路径到结果

批量不是魔法,是清晰的步骤链。以下四步严格对应你将在/root/workspace/推理.py中做的真实修改,每步附可直接粘贴的代码块和避坑提示。

2.1 第一步:导入必要模块并定义图片目录

在文件顶部import区域下方,添加两行:

import os from pathlib import Path

然后,在模型加载完成后(即model.to(device)下方),定义你要处理的图片所在文件夹:

# 【新增】指定图片所在目录(请按实际路径修改) image_dir = "/root/workspace/images" # ← 改成你的图片文件夹路径 # 【新增】获取该目录下所有支持的图片文件(.png/.jpg/.jpeg) supported_exts = {".png", ".jpg", ".jpeg", ".PNG", ".JPG", ".JPEG"} image_paths = [ str(p) for p in Path(image_dir).iterdir() if p.is_file() and p.suffix in supported_exts ] print(f"发现 {len(image_paths)} 张待识别图片") if not image_paths: print(" 警告:未找到任何图片,请检查路径是否正确、文件夹是否为空") exit(1)

为什么这样写?

  • pathlib.Pathos.listdir()更安全,自动过滤子目录和隐藏文件;
  • 显式声明支持的后缀,避免.webp等格式报错中断;
  • 提前校验数量并退出,防止空列表导致后续循环异常。

2.2 第二步:封装单图推理为函数

把原始的“加载图→预处理→推理→打印”逻辑,提取成一个独立函数。将原脚本中从image_path = ...开始到print(...)结束的所有代码,整体剪切出来,替换成以下函数定义:

def recognize_single_image(image_path, class_names, top_k=3): """ 对单张图片执行识别 :param image_path: 图片绝对路径 :param class_names: 中文提示词列表,如 ["动物", "人物"] :param top_k: 返回前K个高置信度结果 :return: [(label, prob), ...] 列表 """ try: # 加载并转换图片 image = Image.open(image_path).convert("RGB") # 预处理(复用原逻辑) inputs = processor( images=image, text=class_names, return_tensors="pt", padding=True ).to(device) # 推理 with torch.no_grad(): outputs = model(**inputs) # 计算概率并取topk probs = outputs.logits_per_image.softmax(dim=1)[0] top_probs, top_labels = probs.topk(top_k) # 组装结果 results = [] for i in range(top_labels.shape[0]): label_idx = top_labels[i].item() results.append((class_names[label_idx], top_probs[i].item())) return results except Exception as e: print(f"❌ 处理 {image_path} 时出错: {str(e)}") return []

关键设计点:

  • 函数接收image_pathclass_names作为参数,解耦数据与逻辑;
  • 包裹try...except,单张图失败不影响其他图处理(真实场景必备);
  • 返回结构化结果[(label, prob), ...],为后续导出JSON或统计打基础。

2.3 第三步:编写主循环,调用函数处理每张图

在函数定义下方,添加主循环逻辑:

# 【新增】主批量处理循环 class_names = ["动物", "人物", "交通工具", "食物", "建筑", "植物"] # ← 保持与原逻辑一致 print("\n 开始批量识别...") for i, img_path in enumerate(image_paths, 1): print(f"\n--- 第 {i}/{len(image_paths)} 张:{os.path.basename(img_path)} ---") # 调用单图识别函数 results = recognize_single_image(img_path, class_names, top_k=3) # 输出结果(保持原有风格,易读) if results: for label, prob in results: print(f" → {label} (置信度: {prob:.3f})") else: print(" → 无有效识别结果")

为什么用enumerate(..., 1)

  • 让序号从1开始(非0),符合人类阅读习惯;
  • os.path.basename()只显示文件名,避免长路径刷屏;
  • 每张图用分隔线隔开,结果一目了然。

2.4 第四步:(可选)将结果保存为CSV便于分析

如果需要把结果存档或导入Excel,追加以下代码(放在循环之后):

# 【新增】导出为CSV(可选) import csv output_csv = "/root/workspace/recognition_results.csv" with open(output_csv, "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["图片文件名", "Top1标签", "Top1置信度", "Top2标签", "Top2置信度", "Top3标签", "Top3置信度"]) for img_path in image_paths: results = recognize_single_image(img_path, class_names, top_k=3) row = [os.path.basename(img_path)] for i in range(3): if i < len(results): row.extend([results[i][0], f"{results[i][1]:.3f}"]) else: row.extend(["", ""]) writer.writerow(row) print(f"\n 结果已保存至 {output_csv}")

优势说明:

  • CSV格式兼容Excel、Tableau等工具,方便业务同学查看;
  • 字段命名直白(“Top1标签”),无需额外文档解释;
  • 使用utf-8编码,确保中文不乱码。

3. 实操验证:三分钟跑通全流程

现在,你已完成了全部代码修改。接下来是验证环节,确保每一步都稳稳落地。

3.1 准备测试图片集

/root/workspace下创建images文件夹,并放入3-5张不同类型的图片(如猫、车、建筑、食物):

mkdir -p /root/workspace/images cp /root/workspace/bailing.png /root/workspace/images/ # 再上传2-4张其他图片(如 mydog.jpg, car.jpg)

ls确认:

ls /root/workspace/images/ # 应输出类似:bailing.png mydog.jpg car.jpg

3.2 执行批量脚本

进入工作目录并运行:

cd /root/workspace python 推理.py

你将看到类似输出:

发现 3 张待识别图片 开始批量识别... --- 第 1/3 张:bailing.png --- → 动物 (置信度: 0.967) → 人物 (置信度: 0.021) → 植物 (置信度: 0.008) --- 第 2/3 张:mydog.jpg --- → 动物 (置信度: 0.982) → 人物 (置信度: 0.011) → 食物 (置信度: 0.003) --- 第 3/3 张:car.jpg --- → 交通工具 (置信度: 0.945) → 建筑 (置信度: 0.032) → 动物 (置信度: 0.015) 结果已保存至 /root/workspace/recognition_results.csv

3.3 快速排查常见问题

现象原因解决方案
ModuleNotFoundError: No module named 'pathlib'Python版本过低确认已激活py311wwts环境(conda activate py311wwts
FileNotFoundError: [Errno 2] No such file or directory: '/root/workspace/images'image_dir路径错误ls /root/workspace/检查文件夹是否存在,注意大小写和斜杠
OSError: cannot identify image file图片损坏或格式不支持file /root/workspace/images/*查看文件类型,删除非图片文件
循环只处理1张图就停止image_paths列表为空检查supported_exts是否包含你的图片后缀(如.JPG是大写)

4. 进阶技巧:让批量更聪明、更省心

基础循环已能工作,但真实业务需要更多“小心思”。以下是三个经实战验证的轻量级增强技巧,全部基于现有代码微调,无需额外依赖。

4.1 技巧一:动态提示词——按文件夹名自动切换识别重点

假设你有/root/workspace/images/food/(美食图)和/root/workspace/images/product/(商品图),希望前者重点识别“火锅”“寿司”,后者识别“手机”“耳机”。只需修改主循环中的class_names定义:

# 替换原主循环中的 class_names 定义 img_folder = os.path.dirname(img_path) if "food" in img_folder.lower(): class_names = ["火锅", "寿司", "披萨", "蛋糕", "水果"] elif "product" in img_folder.lower(): class_names = ["手机", "耳机", "笔记本电脑", "手表", "充电宝"] else: class_names = ["动物", "人物", "交通工具", "食物", "建筑", "植物"] # 默认

效果:同一脚本,自动适配不同业务场景,无需维护多个版本。

4.2 技巧二:阈值过滤——只保留高置信度结果

避免低质量输出干扰判断。在recognize_single_image函数返回前,添加过滤:

# 在函数末尾,results组装完成后,插入: min_confidence = 0.3 # ← 设定最低置信度阈值 results = [(label, prob) for label, prob in results if prob >= min_confidence]

效果:若某张图所有结果置信度都低于0.3,results为空,输出“无有效识别结果”,干净利落。

4.3 技巧三:进度条可视化——告别黑屏等待

对大量图片(>100张),加一行进度提示提升体验:

# 在主循环开头,import区添加: from tqdm import tqdm # 将主循环改为: for img_path in tqdm(image_paths, desc="识别中", unit="图"): # ... 原有循环体 ...

注意:tqdm未预装,需先执行pip install tqdm。若不想装包,可用更轻量的print(f"\r处理中: {i}/{len(image_paths)}", end="")替代。

5. 总结:批量不是终点,而是业务集成的起点

你刚刚完成的,远不止是“加了个循环”。你构建了一个可立即投入业务使用的图像识别流水线雏形:它稳定、可调试、可扩展、结果可追溯。更重要的是,所有改动都扎根于你已掌握的原始脚本,没有引入陌生概念,学习成本趋近于零。

回顾整个过程,核心经验只有三点:

  • 模型加载永远在外层:这是性能的生命线,也是显存管理的铁律;
  • 单图逻辑必须可复用:封装成函数,是应对未来需求变化(如加日志、加缓存、加API)的基石;
  • 批量的本质是数据驱动:路径、提示词、阈值、输出格式——这些变量才是你真正需要配置的业务参数,代码只是执行容器。

下一步,你可以轻松延伸:

  • 把CSV结果喂给数据库,构建带搜索的图片资产库;
  • Flask包一层,提供POST /recognize接口,供前端上传图片实时识别;
  • class_names从硬编码改为读取配置文件,实现运营人员自助配置识别维度。

技术的价值,从来不在炫技,而在让复杂的事变简单。当你不再为每张图手动改路径,当结果自动归档进表格,当业务同学指着Excel说“这准确率真高”,你就知道:那个“加了循环”的脚本,已经真正活了起来。


获取更多AI镜像

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

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

AI智能文档扫描仪快速部署:5分钟搭建私有化扫描服务

AI智能文档扫描仪快速部署&#xff1a;5分钟搭建私有化扫描服务 1. 为什么你需要一个私有化文档扫描工具&#xff1f; 你有没有过这样的经历&#xff1a; 拍了一张发票照片&#xff0c;发给财务却被告知“太歪了看不清”&#xff1b;会议白板内容拍完全是阴影和反光&#xf…

作者头像 李华
网站建设 2026/4/16 12:42:05

LangChain Agent 架构演进深度解析:从 AgentExecutor 到 LangGraph 与 LCEL

在过去的两三年中&#xff0c;LangChain 的 Agent 架构经历了翻天覆地的变化。对于许多开发者来说&#xff0c;从 create_openai_tools_agent 和 AgentExecutor 迁移到现代化的架构不仅是 API 的替换&#xff0c;更是思维模式的根本转变。 本文将以极其详尽的代码实例&#xff…

作者头像 李华
网站建设 2026/4/16 10:40:41

微电网两阶段鲁棒优化经济调度方法 针对微电网内可再生能源和负荷的不确定性,建立了min-max...

微电网两阶段鲁棒优化经济调度方法 针对微电网内可再生能源和负荷的不确定性&#xff0c;建立了min-max-min 结构的两阶段鲁棒优化模型&#xff0c;可得到最恶劣场景下运行成本最低的调度方案。 模型中考虑了储能、需求侧负荷及可控分布式电源等的运行约束和协调控制&#xff0…

作者头像 李华
网站建设 2026/4/16 9:22:54

企业培训资料转化,科哥镜像实现知识沉淀

企业培训资料转化&#xff0c;科哥镜像实现知识沉淀 在企业内部&#xff0c;大量有价值的培训内容长期沉睡在会议录音、讲师口述、现场研讨等非结构化音频中。传统人工转录耗时耗力&#xff0c;外包成本高&#xff0c;且难以保证专业术语准确率&#xff1b;而通用语音识别工具…

作者头像 李华
网站建设 2026/4/15 23:14:18

跨城市地址标准化挑战:MGeo模型适应性调参与部署指南

跨城市地址标准化挑战&#xff1a;MGeo模型适应性调参与部署指南 1. 为什么地址标准化成了城市间数据流动的“卡点” 你有没有遇到过这样的情况&#xff1a;同一栋写字楼&#xff0c;在不同系统里被写成“北京市朝阳区建国路8号SOHO现代城A座”“北京朝阳建国路SOHO A座”“朝…

作者头像 李华