☰
Python调用百度AI识别花卉,自动分类整理照片实战
2026/10/7 8:43:21 网站建设 项目流程

简介:这是一份面向Python开发者与AI图像识别初学者的完整项目资源,聚焦“识别花卉种类并自动整理分类”的真实任务。项目借助Python脚本调用百度AI开放平台的图像识别接口,对花卉照片自动识别分类,再结合文件操作模块将照片移动到对应目录,内容覆盖图像预处理、API鉴权、结果解析与批量文件整理等关键环节。压缩包内共21个文件,包含1个Python主程序、15张png效果截图和5张jpg花卉样张,整体大小10.47MB;png直观展示运行过程和识别画面,jpg则为待分类的花卉样例,方便边看代码边对照验证。此资源发布在CSDN下载频道,已有1756人学习浏览,特别适合想快速上手第三方AI接口、并希望把图像识别落地到文件自动化整理的开发者。通过阅读源码与附带样例,可提升Python调用API、图像数据处理、文件批量整理以及简单项目部署方面的实践能力。

1. 识别花卉类型并自动整理:先搞清楚这套东西能解决什么

先说结论:这是一个用 Python 调百度 AI 接口识花、再把同一种花的照片自动归到同一个文件夹的小工具。别人拿它整理一大堆叫不出名字的花卉照片,你不用自己训练模型、不用攒数据集,只要有一个百度 AI 开放平台的账号,跑一个脚本就能把几十上百张图按品种分好。对经常拍花又懒得手动归档的人来说,这就是个省事的东西;对想学「Python + 第三方 AI 接口」怎么落地的人来说,它是一份很完整的参考实现,涉及接口鉴权、base64 编码、JSON 解析、文件遍历和移动,全是实际开发里要过的坎。下面我按自己拆包复现的顺序,把这个项目从头到尾捋一遍。

2. 环境与接入:密钥申请、依赖安装和资源包结构

2.1 先去百度 AI 开放平台创建应用,拿到 AK/SK

整个项目不依赖本地模型,识图工作全部发生在云端,所以第一步不是装深度学习框架,而是先拿到调用凭证。登录百度 AI 开放平台,在控制台里创建一个应用,服务类型勾选「图像识别」相关的项。创建完成后,控制台会给你一对字符串:API Key 和 Secret Key,后面所有请求都要靠它们换身份令牌。注意密文别随便贴到公开仓库里,脚本里写环境变量或者单独放一个 config.py 是我习惯的做法。

这一对 Key 本身不能直接调用接口,它换的是 Access Token,相当于临时通行证。百度返回的 token 有效期默认是 30 天,也就是说你不用每次调用都换,启动脚本时拿一次、存成全局变量复用就行。我见过有人每识别一张图就重新调一次 token 接口,白白把 QPS 额度浪费在鉴权上,完全没必要。

2.2 拆开下载的 ZIP,看清里面哪是代码哪是素材

下载下来的压缩包解开以后,文件其实分成三类。第一类是核心脚本,名字就叫「Python识别花卉种类,并自动整理分类.py」,整个项目的逻辑都在里面。第二类是「花卉合集」这个目录,里面放了一堆待识别的花卉图片,是拿来演示和测试用的。第三类是一批 QQ 截图和微信图片,仔细看能发现这些是作者调试脚本时留下的界面截图,比如识别结果弹窗、命令行输出之类的,它们不是程序运行的必要输入,只是过程记录。

这个区分很重要,因为很多人拆包后直接把所有图片扔进脚本的输入目录,结果把截图也送去识别,返回一堆乱七八糟的分类。正确做法是只把真实的花卉照片放进输入目录,截图留着当参照就行。我在复现时就是先在「花卉合集」里挑了几张单独测试,确认接口通了再整目录跑。

2.3 本地 Python 环境和第三方库

这个项目对 Python 版本没有苛刻要求,Python 3.8 以上跑起来都没问题。第三方库更简单,核心只依赖 requests,用来发 HTTP 请求;os 和 shutil 是标准库,负责遍历目录和移动文件;base64 和 json 也都是内置的,不需要额外装。如果你机器上连 requests 都没有,命令行里执行下面这条就行:

pip install requests

装完可以在 Python 里验证一下:

python -c "import requests; print(requests.__version__)"

能输出版本号就说明环境没问题。别一上来就装什么 tensorflow、opencv,这个项目用不到,装了一堆重库反而拖慢环境搭建。等以后你想自己从零训练花卉识别模型,再考虑那些也不迟。把依赖控制得越少,脚本换机器跑起来越省心。

2.4 写一个独立的 token 获取函数,先把鉴权跑通

在跑完整流程之前,我建议你先单独验证一下 token 能不能拿到,这样如果后面识别接口报鉴权错误,能立刻定位是哪一步出了问题。下面这个函数就是从百度鉴权接口换 token 的:

import requests API_KEY = "你的API Key" SECRET_KEY = "你的Secret Key" def get_access_token(): """从百度AI平台获取访问令牌,有效期约30天""" url = "https://aip.baidubce.com/oauth/2.0/token" params = { "grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY } resp = requests.post(url, params=params) result = resp.json() if "access_token" in result: print("token获取成功") return result["access_token"] else: print("鉴权失败:", result) return None token = get_access_token()

这段代码里需要注意两点。第一,接口用的是 POST 请求,但参数是放在 query string 里传的,requests 的 params 参数会自动拼到 URL 后面,不需要自己拼。第二,如果返回结果里没有 access_token,别急着改代码,先看看错误信息的 error_description,多半是 API Key 复制错了,或者密钥之间多了空格。token 拿到以后先打印出来确认一下,接下来所有识别请求都要带着它。

3. 核心代码:图片压缩编码、请求识别、结果解析与自动归档

3.1 单张图片识别的完整函数

鉴权通了以后,核心问题就变成:怎么把一张图片交给百度识花,再拿回一个可信的分类结果。百度的图像识别接口接受 base64 编码的图像数据,也就是说你得先把图片文件读出来、转成 base64 字符串,然后塞进 POST 请求的 body 里。

这里有一个容易被忽略的细节——图片体积。百度图像识别接口对请求图片大小有限制,通常要求编码后不超过 4MB,最好是压缩到 1MB 以内再传。我试过直接把手机原图发过去,结果接口返回图片过大错误。所以正规一点的写法是先把图片用 PIL 或者 OpenCV 压缩一下,不过为了不引入额外依赖,也可以用下面这个更轻的办法:先读文件,如果超过阈值就直接报错提示用户。下面是单张识别的核心函数:

import base64 import requests ACCESS_TOKEN = token # 上一步拿到的token def recognize_flower(image_path): """识别单张图片中的花卉种类,返回置信度最高的结果""" with open(image_path, "rb") as f: image_data = base64.b64encode(f.read()) url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant" + "?access_token=" + ACCESS_TOKEN params = {"image": image_data} # top_num表示返回前几个候选结果,我们这里取5个用于后续比对 params["top_num"] = 5 headers = {"Content-Type": "application/x-www-form-urlencoded"} resp = requests.post(url, data=params, headers=headers) result = resp.json() if "result" in result: top_result = result["result"][0] name = top_result["name"] score = top_result["score"] return name, score, result["result"] else: print("识别失败:", result) return None

这个函数做了三件事:读图并转 base64、带 token 调植物识别接口、解析返回结果取最高置信度的候选。代码里用到了植物识别接口(/plant),它返回的 result 是一个列表,每一项包含花卉名称 name 和置信度 score,列表顺序按置信度从高到低排。我特意把 top_num 设成 5,因为很多时候第一名不可信,比如置信度只有 0.55,第二名 0.44,这种时候就要怀疑图片拍得不清楚或者花形不典型。

3.2 遍历目录、处理同名冲突、移动文件到分类文件夹

单张识别跑通之后,批量整理的核心逻辑就是遍历。这里要处理的问题有两个:一是图片格式不统一,目录里可能有 .jpg、.png、.jpeg;二是最终移动文件时可能遇到重名,比如两个目录里各有一张叫 1.jpg 的图,都识别成月季,直接移动后一张会覆盖另一张。我一般用目标文件夹内添加时间戳的办法解决,保证文件名唯一。

import os import shutil from datetime import datetime def organize_photos(input_dir, output_dir, threshold=0.6): """遍历输入目录,识别每张图片并按结果移动到输出目录""" valid_ext = (".jpg", ".jpeg", ".png", ".bmp") files = [f for f in os.listdir(input_dir) if f.lower().endswith(valid_ext)] for idx, filename in enumerate(files): img_path = os.path.join(input_dir, filename) print(f"[{idx+1}/{len(files)}] 识别: {filename}") result = recognize_flower(img_path) if result is None: move_unknown(img_path, output_dir, filename) continue name, score, all_results = result if score < threshold: print(f" 置信度不足({score:.2f}),移入待人工确认文件夹") move_unknown(img_path, output_dir, filename) continue # 构建目标文件夹路径 target_dir = os.path.join(output_dir, name) os.makedirs(target_dir, exist_ok=True) # 加时间戳避免同名文件覆盖 ts = datetime.now().strftime("%Y%m%d%H%M%S") new_name = f"{ts}_{filename}" target_path = os.path.join(target_dir, new_name) shutil.move(img_path, target_path) print(f" 移动至 {name}/{new_name}") def move_unknown(img_path, output_dir, filename): """统一处理识别失败或置信度不足的图片""" unknown_dir = os.path.join(output_dir, "待人工确认") os.makedirs(unknown_dir, exist_ok=True) ts = datetime.now().strftime("%Y%m%d%H%M%S") new_name = f"{ts}_{filename}" shutil.move(img_path, os.path.join(unknown_dir, new_name))

这一段里两个设计值得说。第一,识别失败和置信度不足走了同一个分支——都塞进「待人工确认」文件夹,这个文件夹是最终整理的兜底方案,宁可多人工看几张,也别让分类错误越滚越大。第二,文件移动前先 os.makedirs(target_dir, exist_ok=True) 创建分类目录,不管分类名字多古怪都能建出来,比如「波斯菊」这种带特殊名词的目录名,Windows 下也没问题。

3.3 组合成完整脚本,跑通整个流程

把上面几个函数拼到一起,再加一个 main 入口,一个能直接运行的脚本就成型了:

if __name__ == "__main__": # 输入目录放待整理的花卉照片,输出目录按分类生成子文件夹 input_dir = "./花卉合集" output_dir = "./分类结果" if not os.path.exists(input_dir): print("输入目录不存在,请检查路径") exit(1) os.makedirs(output_dir, exist_ok=True) # 先确保token有效 global ACCESS_TOKEN ACCESS_TOKEN = get_access_token() if not ACCESS_TOKEN: print("无法获取访问令牌,程序终止") exit(1) organize_photos(input_dir, output_dir, threshold=0.6) print("全部处理完成")

运行方式在命令行里执行:

python 识别花卉.py

跑起来的预期效果是:控制台逐条打印当前识别的图片文件名、对应花卉名和置信度;「花卉合集」目录里的图片被搬空,按品种分到「分类结果」下的子目录里。脚本跑完后你打开「分类结果」,看到的应该是「月季」「波斯菊」「向日葵」这类目录名。如果图片本身比较杂,还会有一个「待人工确认」目录,里面全是置信度没过线的图。

3.4 关键参数的解释与调优建议

这个项目的参数不多,但每个都直接影响结果质量。第一个是 top_num,它的含义是返回前几个候选结果,建议保持 5 或更大。第二个是 threshold,也就是置信度阈值,这是最需要调的参数。百度返回的置信度范围是 0 到 1,但实际经验里,不同花卉种类的分数分布差异很大,常见花能到 0.9 以上,小众花或者角度刁钻的可能才 0.5 左右。我给出的 0.6 是保守值,适合第一批测试。

参数推荐值说明
top_num5返回候选结果数量,太小会影响比对
threshold0.6置信度阈值,低于此值进入待确认目录
输入目录./花卉合集放待整理图片的目录
输出目录./分类结果自动生成分类子目录的根目录

如果你发现识别结果明显不对,比如把菊花识别成向日葵,但置信度还挺高,这时候别急着降阈值,先检查图片本身——是不是把整盆花拍进去了,花形太小,模型看不到特征。阈值调得再低也救不回来。

4. 避坑:识别不准、限流、中文路径、文件覆盖,四个高频踩坑记录

4.1 图片主体太杂,接口把花和背景一起识别

现象:识别出来的名称和实际花卉对不上,置信度却高达 0.85。比如拍的是月季,结果返回「蔷薇」,或者返回一个让人摸不着头脑的品种名。

原因:百度识花识别的依据是整张图片的视觉特征。如果照片里月季花只占中间一小块,四周全是枝叶、天空、地面,模型会优先提取全局特征,把整棵植物甚至场景特征也纳入判断,导致结果偏向「看起来像的东西」。

解决:识别前先把图片裁剪到主体突出。我一般会给脚本加一个可选参数,让待识别图片先经过一次「居中裁剪」,只保留图片中央 70% 区域再编码发送。用 PIL 的话一行img.crop()就行。还有一个笨办法但有效——把阈值调高,识别结果置信度低于 0.8 的统统丢待确认目录,人眼再审一遍。

4.2 一次性提交太多图片,接口返回 QPS 超限错误

现象:跑批量整理时,前几张很顺利,十几张之后连续报错,返回的 JSON 里带QPS或者limit字样,后续图片全部识别失败。

原因:百度 AI 接口有并发限制,免费配额通常是每秒几次请求。脚本里for循环本身很快,图片转 base64 在本地瞬间完成,但接口处理需要时间,连续快速请求很快就触发了限流。

解决:在每次请求之间加延时,把速率压到安全范围:

import time # 在organize_photos函数循环内,每次识别后等待 time.sleep(1) # 每秒最多1张,适配免费配额

如果你有更高配额,可以把 sleep 间隔缩短到 0.2 秒。这个参数没有统一标准,依据你账号的实际配额来定。另外,识别和移动文件的逻辑耦合在一个循环里,如果中途出错,文件已经移动了,网络请求又失败,会导致目录里文件数量对不上。我会改成先识别完所有图片、把结果存进列表、再统一执行文件移动,这样即使中途断网也能从列表中恢复进度。

4.3 中文目录名在 Windows 下报找不到路径

现象:脚本明明就放在和目标文件夹同一个目录下,os.listdir也能列出来文件名,但拼好路径后shutil.move报文件不存在,或者识别完成后文件移到了错误的位置。

原因:Windows 控制台的默认编码和 Python 内部字符串编码不一致,尤其是中文目录名。os.listdir返回的文件名在内存里是 Unicode,打印到控制台正常,但拼接路径时如果用了错误的编码格式,传给文件系统的路径就乱套了。

解决:最省事的办法是给 Python 脚本开头加一句环境声明,让运行时的标准输出用 UTF-8 编码。另外,路径拼接统一用os.path.join,别手动用字符串加斜杠拼。如果问题依旧,就在运行前用chcp 65001把控制台切到 UTF-8 代码页。这个坑在 Windows 上几乎必踩,我换了三台机器测试,有两台都出现过类似的路径怪问题。

4.4 目标文件夹已经有同名文件,新文件覆盖了旧文件

现象:跑完整理后发现「月季」文件夹里图片数量比识别成功的少,日志里每张图都显示移动成功,但文件数对不上。

原因:不同来源的图片很多都叫1.jpg、2.jpg,移动到同一个分类目录时,shutil.move遇到目标已存在会直接覆盖,后面的图把前面的同名图顶掉了。

解决:这个问题我在前面的代码里已经处理过了——移动前先给新文件名加时间戳或序号前缀。这里再强调一遍,不只是整理花卉,任何批量移动文件的脚本都必须考虑重名。如果你不想在代码里拼时间戳,也可以用uuid.uuid4().hex[:8]生成随机前缀,效果一样。

4.5 识别结果出现多个完全不同的候选,到底取哪个

现象:top_num 返回了 5 个候选结果,第一名是「波斯菊」0.58,第二名「秋英」0.41,第三名「格桑花」0.39,名字看起来完全不像,让人怀疑接口是不是抽风了。

原因:这其实不是 bug,而是植物命名的常见现象。波斯菊的别名就是秋英、格桑花,同一个物种在不同地区叫法不同,百度训练数据里这些名字对应不同的类别标签,模型在特征空间里对它们的响应都很高。

解决:遇到这种情况,处理原则是「置信度明显领先才自动归档」。我建议在代码里加一道判断:第一名和第二名的差距小于 0.1,说明模型自己也很犹豫,直接送待确认。如果第一名领先很多,就直接用那个名字,哪怕它和第二名是别名关系也无所谓,反正人工复核时一眼就能看出来。

5. 进阶改造:给整理脚本加日志、加并发、加人工复核机制

这个脚本跑通只是起点,真正让它在日常使用中不翻车,还需要往下走三步。第一步是加日志。纸面上看每条识别结果都有 print 输出,但图片一多,控制台历史就滚没了。我习惯在每个识别节点追加写入一个classify_log.csv,字段包括原文件名、识别名称、置信度、是否被移动、移动后路径。这个 CSV 就是你的后悔药——如果哪张图被错误归档,直接按日志找到它原来的位置,改回来就行。

第二步是加并发。前面为了避开 QPS 限制,我让脚本每次请求后 sleep 1 秒,当时花 100 张图,跑大概两分钟。但实际上百度接口的免费配额虽然低,也没低到一次只能请求一张。可以用线程池把速率控制在三秒两请求,时间能压到 40 秒左右:

from concurrent.futures import ThreadPoolExecutor, as_completed def process_one(img_path, output_dir): """单张图片的识别+移动,交给线程池执行""" result = recognize_flower(img_path) if result is None or result[1] < 0.6: move_unknown(img_path, output_dir, os.path.basename(img_path)) else: name, score, _ = result target_dir = os.path.join(output_dir, name) os.makedirs(target_dir, exist_ok=True) ts = datetime.now().strtime("%Y%m%d%H%M%S") new_name = f"{ts}_{os.path.basename(img_path)}" shutil.move(img_path, os.path.join(target_dir, new_name)) return img_path, result with ThreadPoolExecutor(max_workers=3) as executor: futures = {executor.submit(process_one, os.path.join(input_dir, f), output_dir) for f in files} for future in as_completed(futures): img_path, result = future.result() print(f"完成: {img_path} -> {result[0] if result else '待确认'}")

并发这里有个边界必须说清楚:max_workers=3只意味着本地同时发 3 个请求,接口那边的 QPS 限制依然存在。如果你账号额度只有每秒一次,照样会超限。我的习惯是先在控制台看有没有 QPS 报错,有就调回单线程。线程池解决的不是接口额度问题,而是本地 CPU 编码和网络等待的并行利用。

第三步是人工复核机制的工程化。前面已经把所有低置信度图片丢进了「待人工确认」文件夹,但如果没有辅助信息,人工确认就是逐张看图再手动拖到对应目录。更好的做法是输出一份未分类图片带截图缩略图的 HTML 清单,或者简单点,把 CSV 里置信度排名第二、第三的结果也打出来,人工比对时有个参照系。你会发现很多花其实识别结果就在前三名里,只是第一名的分不够高,被阈值拦截了。这种图人工复核成本极低。

从那以后,我每次批量整理图片前都强制先跑一遍「十张测试」——抽取最多 10 张图片丢进脚本,观察置信度分布和输出日志,确认阈值设置合理、目录路径没问题,再全量跑。这套流程在用百度接口识花时救过我一次,后来做别的图像分类整理我也沿用同样的套路。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询