news 2026/3/30 13:54:27

DAMO-YOLO入门教程:使用requests库编写Python客户端批量调用脚本

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DAMO-YOLO入门教程:使用requests库编写Python客户端批量调用脚本

DAMO-YOLO入门教程:使用requests库编写Python客户端批量调用脚本

1. 为什么需要写一个Python客户端?

你已经把DAMO-YOLO服务跑起来了,打开浏览器访问http://localhost:5000,上传一张图,几秒后看到霓虹绿的检测框——很酷。但如果你手头有300张监控截图要分析,或者每天要处理2000张商品图生成结构化标签,再一张张点上传就太折磨人了。

这时候,你需要的不是UI界面,而是一个能自动干活的“数字员工”。它不眨眼、不喊累、不嫌重复,只要给它指令,就能批量把图片发过去、拿回结果、保存数据。本文就带你从零开始,用最基础的requests库,写出一个真正能落地的Python调用脚本——不依赖任何额外框架,不改一行服务端代码,纯客户端实现,小白也能照着敲完立刻跑通。

你不需要懂TinyNAS怎么搜索网络,也不用研究赛博朋克UI的CSS滤镜怎么写的。你只需要知道三件事:服务地址在哪、图片怎么发、返回的数据长什么样。接下来的内容,全部围绕这三点展开。

2. 理解DAMO-YOLO的API通信逻辑

2.1 它不是一个RESTful API,而是一个表单式接口

先破除一个常见误解:很多新手会默认“Web服务=JSON API”,于是尝试用requests.post(url, json={...})发送数据。但DAMO-YOLO的前端是用HTML<form>提交图片的,后端Flask接收的是multipart/form-data类型的表单数据——就像你在网页上点“选择文件”再点“上传”那样。

你可以打开浏览器开发者工具(F12),切换到 Network 标签页,上传一张图,看抓到的请求:

  • Request URL:http://localhost:5000/upload
  • Request Method:POST
  • Content-Type:multipart/form-data; boundary=----WebKitFormBoundary...
  • Form Data里有一项叫file,值就是你选的图片二进制内容

这个file就是关键字段名。后端Flask代码里一定是类似这样写的:

file = request.files['file']

所以你的Python脚本,也必须模拟这个行为:构造一个带file字段的表单,把图片塞进去发出去。

2.2 返回结果是HTML页面?不,是JSON结构化数据

再看返回内容。界面上显示结果时,你以为它只是渲染了HTML?错。实际是前端用JavaScript解析了后端返回的JSON数据,再动态画框、填统计面板。

你可以在Network里点开刚那个POST请求,切换到 Response 标签页,会看到类似这样的内容:

{ "status": "success", "detections": [ {"label": "person", "score": 0.92, "bbox": [124, 87, 231, 412]}, {"label": "car", "score": 0.86, "bbox": [456, 210, 678, 395]} ], "image_url": "/static/results/20260126_142233_output.jpg" }

这才是你真正要拿的数据。它干净、结构化、可编程。你完全不用管那个炫酷的玻璃拟态UI,直接和这个JSON打交道就行。

3. 编写第一个单图调用脚本

3.1 最简可用版本(5行代码)

新建一个single_call.py,粘贴以下代码(请确保你已启动服务):

import requests url = "http://localhost:5000/upload" with open("test.jpg", "rb") as f: files = {"file": f} response = requests.post(url, files=files) print(response.status_code) print(response.json())

注意事项:

  • test.jpg必须和脚本在同一目录下,且是真实存在的图片文件
  • 不要改files字典的键名,必须是"file",这是后端约定的字段名
  • response.json()会自动解析返回的JSON;如果报错,说明返回的不是合法JSON(比如服务没起来、URL错了、图片格式不支持)

运行它,你应该看到类似这样的输出:

200 {'status': 'success', 'detections': [...], 'image_url': '/static/results/...'}

成功!你已经完成了第一次程序化调用。

3.2 加入错误处理和置信度控制

上面的脚本太“裸”了,实际使用中会遇到各种问题:图片打不开、网络超时、服务崩了、返回非200状态码……我们来加一层健壮性:

import requests import time def call_damoyolo(image_path, timeout=30): url = "http://localhost:5000/upload" # 构造带置信度参数的表单(如果后端支持) # 注意:DAMO-YOLO UI里滑块控制的是Confidence Threshold, # 但默认接口可能不接收该参数。我们先尝试加,失败再删。 data = {"confidence": "0.4"} # 设为0.4,比默认0.5更宽松 try: with open(image_path, "rb") as f: files = {"file": f} response = requests.post(url, files=files, data=data, timeout=timeout) if response.status_code == 200: result = response.json() if result.get("status") == "success": return result else: print(f"服务返回异常状态: {result.get('message', '未知错误')}") return None else: print(f"HTTP错误: {response.status_code} - {response.reason}") return None except FileNotFoundError: print(f"错误:找不到图片文件 '{image_path}'") return None except requests.exceptions.Timeout: print("错误:请求超时,请检查服务是否正常运行") return None except requests.exceptions.ConnectionError: print("错误:无法连接到服务,请确认 http://localhost:5000 是否可访问") return None except Exception as e: print(f"未知错误: {e}") return None # 调用示例 if __name__ == "__main__": result = call_damoyolo("test.jpg") if result: print(f"检测到 {len(result['detections'])} 个目标") for det in result["detections"][:3]: # 只打印前3个 print(f" {det['label']} ({det['score']:.2f}) @ {det['bbox']}")

这段代码做了四件事:

  • 把调用逻辑封装成函数,方便复用
  • 加入try/except捕获常见异常(文件不存在、超时、连接失败)
  • 检查HTTP状态码和业务状态码(status: success
  • 对返回结果做基础校验,避免后续处理空数据出错

4. 批量处理:一次调用多张图片

4.1 基础批量循环(顺序执行)

现在把单图脚本升级为批量版。假设你有一个images/文件夹,里面全是.jpg.png图片:

import os import glob import time def batch_process_folder(folder_path, output_file="results.json"): """批量处理指定文件夹下的所有图片""" # 支持的图片格式 image_extensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp"] image_files = [] for ext in image_extensions: image_files.extend(glob.glob(os.path.join(folder_path, ext))) image_files.extend(glob.glob(os.path.join(folder_path, ext.upper()))) if not image_files: print(f"警告:在 '{folder_path}' 中未找到任何图片文件") return print(f"发现 {len(image_files)} 张图片,开始批量处理...") all_results = [] start_time = time.time() for i, img_path in enumerate(image_files, 1): print(f"[{i}/{len(image_files)}] 正在处理: {os.path.basename(img_path)}") result = call_damoyolo(img_path) if result: # 添加原始文件名便于追溯 result["source_image"] = os.path.basename(img_path) all_results.append(result) else: # 记录失败项 all_results.append({ "source_image": os.path.basename(img_path), "status": "failed", "error": "调用失败" }) # 避免请求过于密集,加个小小延迟(可选) time.sleep(0.1) # 保存所有结果到JSON文件 import json with open(output_file, "w", encoding="utf-8") as f: json.dump(all_results, f, ensure_ascii=False, indent=2) end_time = time.time() print(f"\n 批量处理完成!共处理 {len(image_files)} 张,耗时 {end_time - start_time:.1f} 秒") print(f"结果已保存至: {output_file}") # 使用示例 if __name__ == "__main__": batch_process_folder("images/", "batch_results.json")

这个脚本会:

  • 自动扫描images/目录下所有常见图片格式
  • 逐张调用call_damoyolo()函数
  • 把每张图的结果(包括成功和失败)都存进一个大列表
  • 最终导出为batch_results.json,结构清晰,方便后续用Pandas分析或导入数据库

4.2 进阶:并发加速(使用ThreadPoolExecutor)

顺序处理100张图可能要等十几秒。我们可以用线程池并发发送请求,把时间压缩到3-5秒(取决于你的CPU和网络)。注意:这不是“多进程”,因为IO等待是瓶颈,线程足够:

from concurrent.futures import ThreadPoolExecutor, as_completed import threading def batch_process_concurrent(folder_path, max_workers=5, output_file="results_concurrent.json"): """并发批量处理,max_workers 控制同时请求数""" image_extensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp"] image_files = [] for ext in image_extensions: image_files.extend(glob.glob(os.path.join(folder_path, ext))) image_files.extend(glob.glob(os.path.join(folder_path, ext.upper()))) if not image_files: print(f"警告:在 '{folder_path}' 中未找到任何图片文件") return print(f"发现 {len(image_files)} 张图片,启用 {max_workers} 线程并发处理...") # 用线程安全的列表收集结果 results_lock = threading.Lock() all_results = [] def process_single(img_path): result = call_damoyolo(img_path) if result: result["source_image"] = os.path.basename(img_path) else: result = { "source_image": os.path.basename(img_path), "status": "failed", "error": "调用失败" } with results_lock: all_results.append(result) return result start_time = time.time() with ThreadPoolExecutor(max_workers=max_workers) as executor: # 提交所有任务 future_to_img = {executor.submit(process_single, img): img for img in image_files} # 实时打印进度(可选) completed = 0 for future in as_completed(future_to_img): completed += 1 print(f"\r 已完成 {completed}/{len(image_files)}", end="", flush=True) end_time = time.time() # 保存结果 import json with open(output_file, "w", encoding="utf-8") as f: json.dump(all_results, f, ensure_ascii=False, indent=2) print(f"\n\n 并发处理完成!耗时 {end_time - start_time:.1f} 秒") print(f"结果已保存至: {output_file}") # 使用示例(取消注释下面这行来运行) # batch_process_concurrent("images/", max_workers=8)

关键点说明:

  • max_workers=5是推荐起始值。设太高(如20)反而可能因服务端连接数限制导致失败
  • as_completed()让你按完成顺序获取结果,配合\r实现进度条效果
  • threading.Lock()保证多线程写入all_results列表时线程安全

5. 结果解析与实用技巧

5.1 把JSON结果转成Excel报表(一行代码)

你拿到results.json后,想快速看统计?用Pandas两行搞定:

import pandas as pd # 读取结果 df = pd.read_json("batch_results.json") # 展开detections列表,每行一个检测框 rows = [] for _, row in df.iterrows(): if row.get("status") == "success": for det in row["detections"]: rows.append({ "image": row["source_image"], "label": det["label"], "score": det["score"], "x1": det["bbox"][0], "y1": det["bbox"][1], "x2": det["bbox"][2], "y2": det["bbox"][3] }) result_df = pd.DataFrame(rows) result_df.to_excel("detection_summary.xlsx", index=False) print(" Excel报表已生成!")

生成的Excel里,每行是一个检测框,你可以轻松用Excel筛选:“只看person”、“score>0.8的car”、“所有图片中出现最多的类别”。

5.2 保存带框图(可选增强)

DAMO-YOLO返回的image_url是服务端生成的带框图路径(如/static/results/xxx.jpg)。你可以在本地用requests.get()下载它:

def download_annotated_image(result, save_dir="annotated"): """下载带检测框的图片到本地""" if not os.path.exists(save_dir): os.makedirs(save_dir) image_url = result.get("image_url") if not image_url or not image_url.startswith("/static/"): return False # 构造完整URL full_url = f"http://localhost:5000{image_url}" try: response = requests.get(full_url, timeout=10) if response.status_code == 200: filename = os.path.join(save_dir, result["source_image"]) with open(filename, "wb") as f: f.write(response.content) return True except Exception as e: print(f"下载失败 {result['source_image']}: {e}") return False # 在 batch_process_folder 循环里调用 # download_annotated_image(result)

这样你就能得到一份“原始图 + 带框图 + JSON数据”三位一体的交付包。

6. 常见问题与避坑指南

6.1 “Connection refused” 错误

  • 检查服务是否真的在运行:ps aux | grep flaskcurl http://localhost:5000看能否返回HTML
  • 确认启动命令是bash /root/build/start.sh,不是streamlit run app.py
  • 如果你在Docker里运行,确保端口映射正确:-p 5000:5000

6.2 “Unsupported image format”

  • DAMO-YOLO后端用OpenCV/Pillow加载图片,只支持常见格式(JPG/PNG/BMP)
  • 检查图片是否损坏:用系统看图软件能打开吗?
  • 避免使用WebP、HEIC等新格式,先用Photoshop或在线工具转成JPG

6.3 返回的JSON里没有detections字段

  • 先确认图片里确实有目标(用UI界面试传同一张图)
  • 检查置信度阈值是否设得太高(比如传了{"confidence": "0.9"},但图中目标置信度只有0.7)
  • 查看服务端日志:tail -f /root/build/logs/app.log,找报错信息

6.4 批量时部分请求失败,但其他成功

  • 这是正常现象。网络抖动、瞬时负载高都可能导致个别请求失败
  • 我们的脚本已记录失败项,你可以单独重试这些图片
  • 不要盲目加大max_workers,5-8 是大多数场景的甜点值

7. 总结:你已经掌握的核心能力

1. 理清了通信本质

你不再把DAMO-YOLO当成一个“黑盒网页”,而是清楚知道:它接收multipart/form-data表单,返回标准JSON,file是唯一必需字段。

2. 写出了生产级调用函数

call_damoyolo()函数具备完整的异常捕获、超时控制、状态校验,可直接集成进你的项目。

3. 实现了两种批量模式

顺序版脚本适合调试和小批量;并发版脚本让你处理千张图片只需几秒,效率提升立竿见影。

4. 掌握了结果后处理方法

从JSON解析、Excel导出,到带框图下载,你已具备端到端的数据闭环能力。

下一步,你可以:

  • 把这个脚本包装成命令行工具(用argparse
  • 接入定时任务(Linux cron / Windows Task Scheduler),每天凌晨自动处理昨日监控图
  • 把结果推送到企业微信/钉钉机器人,关键目标出现时实时告警

技术的价值,从来不在炫酷的UI,而在于它能不能安静地、可靠地,帮你把重复的事做完。


获取更多AI镜像

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

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

Glyph vs 传统LLM:谁更适合长文本?

Glyph vs 传统LLM&#xff1a;谁更适合长文本&#xff1f; 在处理小说、法律合同、科研论文、财报年报这类动辄数十万字的长文本时&#xff0c;你是否也遇到过这些困扰&#xff1f; ——模型直接截断后半部分&#xff0c;关键信息永远在“被砍掉的30%”里&#xff1b; ——等预…

作者头像 李华
网站建设 2026/3/26 15:13:33

PasteMD开箱体验:一键复制功能的Markdown转换利器

PasteMD开箱体验&#xff1a;一键复制功能的Markdown转换利器 你有没有过这样的经历&#xff1a;刚开完一场头脑风暴会议&#xff0c;手速跟不上思维&#xff0c;记下的笔记全是碎片化短句&#xff1b;或者从网页上复制了一大段技术文档&#xff0c;结果格式混乱、标题层级错乱…

作者头像 李华
网站建设 2026/3/15 10:45:31

GLM-4V-9B部署案例:在RTX 3090上实现4-bit量化推理的完整步骤

GLM-4V-9B部署案例&#xff1a;在RTX 3090上实现4-bit量化推理的完整步骤 1. 为什么是GLM-4V-9B&#xff1f;多模态能力与轻量落地的平衡点 GLM-4V-9B是智谱AI推出的开源多模态大模型&#xff0c;它不是简单地把文本模型和视觉模型拼在一起&#xff0c;而是真正实现了图文联合…

作者头像 李华
网站建设 2026/3/24 14:46:21

碧蓝航线智能托管系统使用指南

碧蓝航线智能托管系统使用指南 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 您是否曾遇到这样的情况&#xff1a;每天花费…

作者头像 李华