一、使用 pathlib 获取和拼接路径
推荐使用 Python 标准库 pathlib 处理文件路径,而不是手动拼接字符串。
可以通过 __file__ 获取当前文件所在目录:
from pathlib import Path
cur_dir = Path(__file__).resolve().parent
拼接路径时,直接使用 Path 对象的 / 运算符:
img_path = cur_dir.parent / "img" / "荷花.png"
注意:这里的 / 不是字符串意义上的路径分隔符,而是 pathlib.Path 重载的路径拼接运算符。
它会根据当前操作系统生成对应的路径,因此是跨平台的。例如:
Windows: project\img\荷花.png
Linux: project/img/荷花.png
macOS: project/img/荷花.png
不推荐手动拼接:
img_path = str(cur_dir.parent) + "/img/荷花.png"
也不推荐写成某个平台的固定路径分隔符:
img_path = "project\\img\\荷花.png"
如果调用方需要字符串形式的路径,使用 str() 转换即可:
img_str_path = str(img_path)
二、对文件进行检查
处理文件时,不要假设文件一定存在、一定能够正常读取。
使用 pathlib 时,可以先检查:
if not img_path.is_file():
raise FileNotFoundError(f"文件不存在: {img_path}")
OpenCV 的 cv2.imread() 有一个比较容易踩的坑:读取失败时通常不会直接抛出异常,而是返回 None。
因此可以显式检查:
img = cv2.imread(str(img_path))
if img is None:
raise ValueError(f"图片读取失败: {img_path}")
三、路径包含中文时,注意第三方库的兼容性
Python3 本身可以正常处理包含中文的 Unicode 路径。真正可能出现问题的,是第三方库在特定操作系统上的文件读取实现。
例如,部分 Windows + OpenCV 环境中,cv2.imread() 对包含中文等非 ASCII 字符的路径可能存在兼容性问题。
例如:
from pathlib import Path
import cv2
if __name__ == "__main__":
cur_dir = Path(__file__).resolve().parent
img_path = cur_dir.parent / "img" / "荷花.png"
img = cv2.imread(str(img_path))
在有路径兼容性问题的环境中,会出现类似的警告:
can't open/read file: check file path/integrity
这时建议避免使用 cv2.imread(),采用其他方法。
方法1:使用 Pillow(PIL)
from pathlib import Path
from PIL import Image
if __name__ == "__main__":
cur_dir = Path(__file__).resolve().parent
img_path = cur_dir.parent / "img" / "荷花.png"
img = Image.open(img_path)
方法2:先用 NumPy 读取文件,再用 OpenCV 解码
import cv2
import numpy as np
from pathlib import Path
if __name__ == "__main__":
cur_dir = Path(__file__).resolve().parent
img_path = cur_dir.parent / "img" / "荷花.png"
img_array = np.fromfile(img_path, dtype=np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
四、不要只通过扩展名判断图片格式
文件扩展名并不能保证文件实际采用的格式。
例如,一个 JPEG 文件完全可以被重命名为fake_png.png, 但修改文件名并不会改变文件本身的格式。
Pillow(PIL) 可以根据文件内容识别实际图片格式:
from pathlib import Path
from PIL import Image
if __name__ == "__main__":
cur_dir = Path(__file__).resolve().parent
img_path = cur_dir.parent / "img" / "fake_png.png"
img = Image.open(img_path)
print(img.format) # 输出: JPEG
在对图片格式有严格要求的场景中,不应该只根据 .png、.jpg 等扩展名判断文件类型,而应该进一步检查文件实际格式,更好的做法是提前用脚本筛选一遍。