Python OpenCV 实战图片批量缩放与加水印教程在日常工作中经常会遇到这样的图片处理需求商品图片上传前需要统一尺寸。活动照片需要批量压缩后再发送。资料截图需要加上公司名或项目名水印。文件夹里有几十张、几百张图片不适合一张张手工处理。这些任务非常适合用 Python 自动化完成。本文使用opencv-python库带你从图片读取、保存、缩放、添加文字水印开始逐步完成一个“批量缩放并加水印”的完整小项目。文章适合刚接触图像处理的 Python 初学者阅读不要求你提前掌握复杂的图像算法。1. OpenCV 是什么OpenCV 是一个常用的计算机视觉和图像处理库可以完成图片读取、图片保存、尺寸变换、颜色处理、绘图、视频处理、人脸检测、目标检测等任务。在 Python 中我们通常安装的是opencv-pythonpipinstallopencv-python安装完成后可以在 Python 中导入importcv2print(cv2.__version__)如果能正常打印版本号说明安装成功。2. 图片读取与保存OpenCV 读取图片使用cv2.imread()保存图片使用cv2.imwrite()。importcv2 imagecv2.imread(input.jpg)ifimageisNone:raiseFileNotFoundError(图片读取失败请检查文件路径)cv2.imwrite(output.jpg,image)需要注意的是OpenCV 读取到的图片是一个 NumPy 数组。它的形状通常是(高度, 宽度, 通道数)例如print(image.shape)输出可能是(1080, 1920, 3)这表示图片高度是 1080宽度是 1920通道数是 3。3. 图片缩放图片缩放使用cv2.resize()。3.1 按指定宽高缩放resizedcv2.resize(image,(800,600))cv2.imwrite(resized.jpg,resized)注意cv2.resize()的尺寸参数顺序是(宽度, 高度)不是(高度, 宽度)。3.2 按比例缩放如果希望图片按 50% 缩小resizedcv2.resize(image,None,fx0.5,fy0.5)其中fx表示宽度缩放比例。fy表示高度缩放比例。3.3 按目标宽度等比例缩放实际项目中更常见的是限制图片宽度同时保持原始宽高比height,widthimage.shape[:2]target_width1000scaletarget_width/width target_heightint(height*scale)resizedcv2.resize(image,(target_width,target_height))这样不会把图片拉伸变形。4. 添加文字水印OpenCV 可以使用cv2.putText()在图片上绘制文字。watermarkedimage.copy()cv2.putText(watermarked,textPython OpenCV,org(30,60),fontFacecv2.FONT_HERSHEY_SIMPLEX,fontScale1.2,color(255,255,255),thickness2,lineTypecv2.LINE_AA)cv2.imwrite(watermarked.jpg,watermarked)参数说明text水印文字。org文字左下角坐标格式是(x, y)。fontFace字体类型。fontScale字体大小。color文字颜色OpenCV 使用 BGR 顺序不是 RGB。thickness文字粗细。lineType抗锯齿方式cv2.LINE_AA会让文字边缘更平滑。5. 半透明文字水印直接把文字画到图片上会比较生硬。更常见的做法是使用一张透明图层再和原图混合。overlayimage.copy()outputimage.copy()cv2.putText(overlay,Python OpenCV,(30,60),cv2.FONT_HERSHEY_SIMPLEX,1.2,(255,255,255),2,cv2.LINE_AA)alpha0.35watermarkedcv2.addWeighted(overlay,alpha,output,1-alpha,0)这里的alpha表示水印透明度。值越大水印越明显值越小水印越淡。6. 批量处理整个文件夹图片批量处理的基本思路是遍历输入文件夹。找到所有图片文件。读取每张图片。缩放图片。添加水印。保存到输出文件夹。常见图片后缀包括IMAGE_EXTENSIONS{.jpg,.jpeg,.png,.bmp,.webp}遍历文件夹可以使用pathlibfrompathlibimportPath input_dirPath(input_images)forfile_pathininput_dir.iterdir():iffile_path.suffix.lower()inIMAGE_EXTENSIONS:print(file_path)7. 中文路径兼容处理很多初学者会遇到一个问题图片路径里有中文时cv2.imread()可能读取失败cv2.imwrite()也可能保存失败。为了更稳定地兼容中文路径可以使用numpy.fromfile()cv2.imdecode()读取图片用cv2.imencode()tofile()保存图片。7.1 兼容中文路径读取importcv2importnumpyasnpdefimread_unicode(file_path):datanp.fromfile(str(file_path),dtypenp.uint8)imagecv2.imdecode(data,cv2.IMREAD_COLOR)returnimage7.2 兼容中文路径保存defimwrite_unicode(file_path,image):extfile_path.suffix success,encoded_imagecv2.imencode(ext,image)ifnotsuccess:returnFalseencoded_image.tofile(str(file_path))returnTrue这两个函数在 Windows 中文目录、中文文件名场景下非常实用。8. 完整项目代码下面是完整可运行代码。建议保存为batch_resize_watermark.py。项目目录示例image_project/ ├─ batch_resize_watermark.py ├─ input_images/ │ ├─ 示例图片1.jpg │ ├─ 示例图片2.png │ └─ 示例图片3.webp └─ output_images/完整代码frompathlibimportPathimportcv2importnumpyasnp IMAGE_EXTENSIONS{.jpg,.jpeg,.png,.bmp,.webp}defimread_unicode(file_path:Path):兼容中文路径的图片读取。datanp.fromfile(str(file_path),dtypenp.uint8)imagecv2.imdecode(data,cv2.IMREAD_COLOR)returnimagedefimwrite_unicode(file_path:Path,image)-bool:兼容中文路径的图片保存。file_path.parent.mkdir(parentsTrue,exist_okTrue)extfile_path.suffix success,encoded_imagecv2.imencode(ext,image)ifnotsuccess:returnFalseencoded_image.tofile(str(file_path))returnTruedefresize_keep_ratio(image,max_width:int1200):按最大宽度等比例缩放图片。height,widthimage.shape[:2]ifwidthmax_width:returnimage.copy()scalemax_width/width target_heightint(height*scale)resizedcv2.resize(image,(max_width,target_height),interpolationcv2.INTER_AREA)returnresizeddefadd_text_watermark(image,text:str,alpha:float0.35,margin:int30):在图片右下角添加半透明文字水印。outputimage.copy()overlayimage.copy()height,widthimage.shape[:2]font_facecv2.FONT_HERSHEY_SIMPLEX font_scalemax(width/1200,0.7)thicknessmax(int(width/600),1)text_size,baselinecv2.getTextSize(text,font_face,font_scale,thickness)text_width,text_heighttext_size xmax(width-text_width-margin,margin)ymax(height-margin,text_heightmargin)# 先画一层深色阴影提高浅色背景下的可读性cv2.putText(overlay,text,(x2,y2),font_face,font_scale,(0,0,0),thickness1,cv2.LINE_AA)# 再画白色文字cv2.putText(overlay,text,(x,y),font_face,font_scale,(255,255,255),thickness,cv2.LINE_AA)watermarkedcv2.addWeighted(overlay,alpha,output,1-alpha,0)returnwatermarkeddefprocess_image(input_path:Path,output_path:Path,watermark_text:str,max_width:int)-bool:处理单张图片读取、缩放、加水印、保存。imageimread_unicode(input_path)ifimageisNone:print(f读取失败:{input_path})returnFalseresizedresize_keep_ratio(image,max_widthmax_width)watermarkedadd_text_watermark(resized,watermark_text)successimwrite_unicode(output_path,watermarked)ifnotsuccess:print(f保存失败:{output_path})returnFalsereturnTruedefbatch_process_images(input_dir:Path,output_dir:Path,watermark_text:strPython OpenCV,max_width:int1200)-None:批量处理文件夹中的图片。ifnotinput_dir.exists():raiseFileNotFoundError(f输入文件夹不存在:{input_dir})output_dir.mkdir(parentsTrue,exist_okTrue)image_files[file_pathforfile_pathininput_dir.iterdir()iffile_path.is_file()andfile_path.suffix.lower()inIMAGE_EXTENSIONS]ifnotimage_files:print(f没有找到可处理的图片:{input_dir})returnsuccess_count0forinput_pathinimage_files:output_pathoutput_dir/input_path.name successprocess_image(input_pathinput_path,output_pathoutput_path,watermark_textwatermark_text,max_widthmax_width)ifsuccess:success_count1print(f处理完成:{input_path.name})print(f批量处理结束成功{success_count}/{len(image_files)}张)print(f输出目录:{output_dir.resolve()})defmain():input_dirPath(input_images)output_dirPath(output_images)batch_process_images(input_dirinput_dir,output_diroutput_dir,watermark_textPython OpenCV,max_width1200)if__name____main__:main()运行脚本python batch_resize_watermark.py如果运行成功终端会输出类似信息处理完成: 示例图片1.jpg 处理完成: 示例图片2.png 处理完成: 示例图片3.webp 批量处理结束成功 3/3 张 输出目录: D:\image_project\output_images9. 效果演示说明运行前input_images文件夹中存放原始图片input_images/ ├─ 风景照片.jpg ├─ 商品主图.png └─ 活动现场.webp运行脚本后output_images文件夹会生成同名图片output_images/ ├─ 风景照片.jpg ├─ 商品主图.png └─ 活动现场.webp处理后的图片会有两个变化如果原图宽度超过max_width会被等比例缩放到指定最大宽度例如 1200 像素。图片右下角会添加半透明文字水印例如Python OpenCV。由于代码使用了中文路径兼容读写函数即使文件名是风景照片.jpg、目录名是测试图片也可以正常读取和保存。10. 常见问题10.1 为什么 OpenCV 的颜色是 BGROpenCV 默认使用 BGR 通道顺序而很多其他库使用 RGB。比如白色在 OpenCV 中是(255,255,255)红色不是(255, 0, 0)而是(0,0,255)10.2 PNG 透明背景会保留吗本文代码使用cv2.IMREAD_COLOR读取图片会把图片读成三通道 BGR透明通道不会保留。如果你需要保留透明背景可以使用cv2.IMREAD_UNCHANGED读取并额外处理 alpha 通道。10.3 水印位置如何调整代码中的水印位置由下面几行控制xmax(width-text_width-margin,margin)ymax(height-margin,text_heightmargin)这是右下角位置。如果想放到左上角可以改成xmargin ytext_heightmargin10.4 如何递归处理子文件夹当前代码只处理输入目录第一层图片。如果要递归处理子文件夹可以把input_dir.iterdir()改成input_dir.rglob(*)同时输出路径可以根据相对路径生成避免不同子目录下的同名图片互相覆盖。总结本文完成了一个适合图像处理初学者的 OpenCV 实战项目批量缩放文件夹图片并添加半透明文字水印。这个项目虽然不复杂但覆盖了图片自动化处理中的几个核心能力使用opencv-python读取和保存图片。使用cv2.resize()等比例缩放图片。使用cv2.putText()添加文字水印。使用cv2.addWeighted()实现半透明效果。使用pathlib批量遍历文件夹。使用imdecode和imencode兼容中文路径。掌握这些基础之后你可以继续扩展更多功能例如图片压缩、格式转换、添加 Logo 水印、递归处理子目录、生成处理日志等把它变成真正适合日常工作的图片批处理工具。