基于Python+OpenCV實現(xiàn)圖片批量縮放與加水印功能
在日常工作中,經(jīng)常會遇到這樣的圖片處理需求:
- 商品圖片上傳前需要統(tǒng)一尺寸。
- 活動照片需要批量壓縮后再發(fā)送。
- 資料截圖需要加上公司名或項目名水印。
- 文件夾里有幾十張、幾百張圖片,不適合一張張手工處理。
這些任務非常適合用 Python 自動化完成。本文使用 opencv-python 庫,帶你從圖片讀取、保存、縮放、添加文字水印開始,逐步完成一個“批量縮放并加水印”的完整小項目。
文章適合剛接觸圖像處理的 Python 初學者閱讀,不要求你提前掌握復雜的圖像算法。
1. OpenCV 是什么
OpenCV 是一個常用的計算機視覺和圖像處理庫,可以完成圖片讀取、圖片保存、尺寸變換、顏色處理、繪圖、視頻處理、人臉檢測、目標檢測等任務。
在 Python 中,我們通常安裝的是 opencv-python:
pip install opencv-python
安裝完成后,可以在 Python 中導入:
import cv2 print(cv2.__version__)
如果能正常打印版本號,說明安裝成功。
2. 圖片讀取與保存
OpenCV 讀取圖片使用 cv2.imread(),保存圖片使用 cv2.imwrite()。
import cv2
image = cv2.imread("input.jpg")
if image is None:
raise FileNotFoundError("圖片讀取失敗,請檢查文件路徑")
cv2.imwrite("output.jpg", image)
需要注意的是,OpenCV 讀取到的圖片是一個 NumPy 數(shù)組。它的形狀通常是:
(高度, 寬度, 通道數(shù))
例如:
print(image.shape)
輸出可能是:
(1080, 1920, 3)
這表示圖片高度是 1080,寬度是 1920,通道數(shù)是 3。
3. 圖片縮放
圖片縮放使用 cv2.resize()。
3.1 按指定寬高縮放
resized = cv2.resize(image, (800, 600))
cv2.imwrite("resized.jpg", resized)
注意:cv2.resize() 的尺寸參數(shù)順序是 (寬度, 高度),不是 (高度, 寬度)。
3.2 按比例縮放
如果希望圖片按 50% 縮?。?/p>
resized = cv2.resize(image, None, fx=0.5, fy=0.5)
其中:
fx表示寬度縮放比例。fy表示高度縮放比例。
3.3 按目標寬度等比例縮放
實際項目中,更常見的是限制圖片寬度,同時保持原始寬高比:
height, width = image.shape[:2] target_width = 1000 scale = target_width / width target_height = int(height * scale) resized = cv2.resize(image, (target_width, target_height))
這樣不會把圖片拉伸變形。
4. 添加文字水印
OpenCV 可以使用 cv2.putText() 在圖片上繪制文字。
watermarked = image.copy()
cv2.putText(
watermarked,
text="Python OpenCV",
org=(30, 60),
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=1.2,
color=(255, 255, 255),
thickness=2,
lineType=cv2.LINE_AA
)
cv2.imwrite("watermarked.jpg", watermarked)
參數(shù)說明:
text:水印文字。org:文字左下角坐標,格式是(x, y)。fontFace:字體類型。fontScale:字體大小。color:文字顏色,OpenCV 使用 BGR 順序,不是 RGB。thickness:文字粗細。lineType:抗鋸齒方式,cv2.LINE_AA會讓文字邊緣更平滑。
5. 半透明文字水印
直接把文字畫到圖片上會比較生硬。更常見的做法是使用一張透明圖層,再和原圖混合。
overlay = image.copy()
output = image.copy()
cv2.putText(
overlay,
"Python OpenCV",
(30, 60),
cv2.FONT_HERSHEY_SIMPLEX,
1.2,
(255, 255, 255),
2,
cv2.LINE_AA
)
alpha = 0.35
watermarked = cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0)
這里的 alpha 表示水印透明度。值越大,水印越明顯;值越小,水印越淡。
6. 批量處理整個文件夾圖片
批量處理的基本思路是:
- 遍歷輸入文件夾。
- 找到所有圖片文件。
- 讀取每張圖片。
- 縮放圖片。
- 添加水印。
- 保存到輸出文件夾。
常見圖片后綴包括:
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
遍歷文件夾可以使用 pathlib:
from pathlib import Path
input_dir = Path("input_images")
for file_path in input_dir.iterdir():
if file_path.suffix.lower() in IMAGE_EXTENSIONS:
print(file_path)
7. 中文路徑兼容處理
很多初學者會遇到一個問題:圖片路徑里有中文時,cv2.imread() 可能讀取失敗,cv2.imwrite() 也可能保存失敗。
為了更穩(wěn)定地兼容中文路徑,可以使用 numpy.fromfile() + cv2.imdecode() 讀取圖片,用 cv2.imencode() + tofile() 保存圖片。
7.1 兼容中文路徑讀取
import cv2
import numpy as np
def imread_unicode(file_path):
data = np.fromfile(str(file_path), dtype=np.uint8)
image = cv2.imdecode(data, cv2.IMREAD_COLOR)
return image
7.2 兼容中文路徑保存
def imwrite_unicode(file_path, image):
ext = file_path.suffix
success, encoded_image = cv2.imencode(ext, image)
if not success:
return False
encoded_image.tofile(str(file_path))
return True
這兩個函數(shù)在 Windows 中文目錄、中文文件名場景下非常實用。
8. 完整項目代碼
下面是完整可運行代碼。建議保存為 batch_resize_watermark.py。
項目目錄示例:
image_project/ ├─ batch_resize_watermark.py ├─ input_images/ │ ├─ 示例圖片1.jpg │ ├─ 示例圖片2.png │ └─ 示例圖片3.webp └─ output_images/
完整代碼:
from pathlib import Path
import cv2
import numpy as np
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
def imread_unicode(file_path: Path):
"""兼容中文路徑的圖片讀取。"""
data = np.fromfile(str(file_path), dtype=np.uint8)
image = cv2.imdecode(data, cv2.IMREAD_COLOR)
return image
def imwrite_unicode(file_path: Path, image) -> bool:
"""兼容中文路徑的圖片保存。"""
file_path.parent.mkdir(parents=True, exist_ok=True)
ext = file_path.suffix
success, encoded_image = cv2.imencode(ext, image)
if not success:
return False
encoded_image.tofile(str(file_path))
return True
def resize_keep_ratio(image, max_width: int = 1200):
"""按最大寬度等比例縮放圖片。"""
height, width = image.shape[:2]
if width <= max_width:
return image.copy()
scale = max_width / width
target_height = int(height * scale)
resized = cv2.resize(
image,
(max_width, target_height),
interpolation=cv2.INTER_AREA
)
return resized
def add_text_watermark(
image,
text: str,
alpha: float = 0.35,
margin: int = 30
):
"""在圖片右下角添加半透明文字水印。"""
output = image.copy()
overlay = image.copy()
height, width = image.shape[:2]
font_face = cv2.FONT_HERSHEY_SIMPLEX
font_scale = max(width / 1200, 0.7)
thickness = max(int(width / 600), 1)
text_size, baseline = cv2.getTextSize(
text,
font_face,
font_scale,
thickness
)
text_width, text_height = text_size
x = max(width - text_width - margin, margin)
y = max(height - margin, text_height + margin)
# 先畫一層深色陰影,提高淺色背景下的可讀性
cv2.putText(
overlay,
text,
(x + 2, y + 2),
font_face,
font_scale,
(0, 0, 0),
thickness + 1,
cv2.LINE_AA
)
# 再畫白色文字
cv2.putText(
overlay,
text,
(x, y),
font_face,
font_scale,
(255, 255, 255),
thickness,
cv2.LINE_AA
)
watermarked = cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0)
return watermarked
def process_image(
input_path: Path,
output_path: Path,
watermark_text: str,
max_width: int
) -> bool:
"""處理單張圖片:讀取、縮放、加水印、保存。"""
image = imread_unicode(input_path)
if image is None:
print(f"讀取失敗: {input_path}")
return False
resized = resize_keep_ratio(image, max_width=max_width)
watermarked = add_text_watermark(resized, watermark_text)
success = imwrite_unicode(output_path, watermarked)
if not success:
print(f"保存失敗: {output_path}")
return False
return True
def batch_process_images(
input_dir: Path,
output_dir: Path,
watermark_text: str = "Python OpenCV",
max_width: int = 1200
) -> None:
"""批量處理文件夾中的圖片。"""
if not input_dir.exists():
raise FileNotFoundError(f"輸入文件夾不存在: {input_dir}")
output_dir.mkdir(parents=True, exist_ok=True)
image_files = [
file_path
for file_path in input_dir.iterdir()
if file_path.is_file() and file_path.suffix.lower() in IMAGE_EXTENSIONS
]
if not image_files:
print(f"沒有找到可處理的圖片: {input_dir}")
return
success_count = 0
for input_path in image_files:
output_path = output_dir / input_path.name
success = process_image(
input_path=input_path,
output_path=output_path,
watermark_text=watermark_text,
max_width=max_width
)
if success:
success_count += 1
print(f"處理完成: {input_path.name}")
print(f"批量處理結(jié)束,成功 {success_count}/{len(image_files)} 張")
print(f"輸出目錄: {output_dir.resolve()}")
def main():
input_dir = Path("input_images")
output_dir = Path("output_images")
batch_process_images(
input_dir=input_dir,
output_dir=output_dir,
watermark_text="Python OpenCV",
max_width=1200
)
if __name__ == "__main__":
main()
運行腳本:
python batch_resize_watermark.py
如果運行成功,終端會輸出類似信息:
處理完成: 示例圖片1.jpg 處理完成: 示例圖片2.png 處理完成: 示例圖片3.webp 批量處理結(jié)束,成功 3/3 張 輸出目錄: D:\image_project\output_images
9. 效果演示說明
運行前,input_images 文件夾中存放原始圖片:
input_images/ ├─ 風景照片.jpg ├─ 商品主圖.png └─ 活動現(xiàn)場.webp
運行腳本后,output_images 文件夾會生成同名圖片:
output_images/ ├─ 風景照片.jpg ├─ 商品主圖.png └─ 活動現(xiàn)場.webp
處理后的圖片會有兩個變化:
- 如果原圖寬度超過
max_width,會被等比例縮放到指定最大寬度,例如 1200 像素。 - 圖片右下角會添加半透明文字水印,例如
Python OpenCV。
由于代碼使用了中文路徑兼容讀寫函數(shù),即使文件名是 風景照片.jpg、目錄名是 測試圖片,也可以正常讀取和保存。
10. 常見問題
10.1 為什么 OpenCV 的顏色是 BGR
OpenCV 默認使用 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 水印位置如何調(diào)整
代碼中的水印位置由下面幾行控制:
x = max(width - text_width - margin, margin) y = max(height - margin, text_height + margin)
這是右下角位置。如果想放到左上角,可以改成:
x = margin y = text_height + margin
10.4 如何遞歸處理子文件夾
當前代碼只處理輸入目錄第一層圖片。如果要遞歸處理子文件夾,可以把:
input_dir.iterdir()
改成:
input_dir.rglob("*")
同時輸出路徑可以根據(jù)相對路徑生成,避免不同子目錄下的同名圖片互相覆蓋。
總結(jié)
本文完成了一個適合圖像處理初學者的 OpenCV 實戰(zhàn)項目:批量縮放文件夾圖片,并添加半透明文字水印。這個項目雖然不復雜,但覆蓋了圖片自動化處理中的幾個核心能力:
- 使用
opencv-python讀取和保存圖片。 - 使用
cv2.resize()等比例縮放圖片。 - 使用
cv2.putText()添加文字水印。 - 使用
cv2.addWeighted()實現(xiàn)半透明效果。 - 使用
pathlib批量遍歷文件夾。 - 使用
imdecode和imencode兼容中文路徑。
掌握這些基礎(chǔ)之后,你可以繼續(xù)擴展更多功能,例如圖片壓縮、格式轉(zhuǎn)換、添加 Logo 水印、遞歸處理子目錄、生成處理日志等,把它變成真正適合日常工作的圖片批處理工具。
以上就是基于Python+OpenCV實現(xiàn)圖片批量縮放與加水印功能的詳細內(nèi)容,更多關(guān)于Python OpenCV圖片批量縮放與加水印的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python?return函數(shù)返回值類型和幫助函數(shù)使用教程
這篇文章主要為大家介紹了Python?return函數(shù)返回值類型和幫助函數(shù)使用教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
python使用tkinter實現(xiàn)屏幕中間倒計時
這篇文章主要為大家詳細介紹了python使用tkinter實現(xiàn)屏幕中間倒計時,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-03-03
5道關(guān)于python基礎(chǔ) while循環(huán)練習題
這篇文章主要給大家分享的是5道關(guān)于python基礎(chǔ) while循環(huán)練習題,無論學習什么語言,練習都是必不可少的,下面文章的練習題挺精湛的,需要的朋友可以參考一下2021-11-11
PyCharm:method may be static問題及解決
這篇文章主要介紹了PyCharm:method may be static問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07

