Python使用Pillow與OpenCV進(jìn)行圖像處理實(shí)戰(zhàn)
前言
在日常開(kāi)發(fā)中,圖像處理是一個(gè)非常實(shí)用的技能。無(wú)論是給照片加水印、批量調(diào)整圖片尺寸,還是做人臉識(shí)別、圖像分類(lèi),Python 都有對(duì)應(yīng)的工具庫(kù)。
Python 圖像處理主要有兩大工具:

| 對(duì)比維度 | Pillow | OpenCV |
|---|---|---|
| 定位 | 通用圖像處理 | 計(jì)算機(jī)視覺(jué) |
| 優(yōu)勢(shì) | 簡(jiǎn)單易用、功能豐富 | 高性能、算法豐富 |
| 安裝 | pip install pillow | pip install opencv-python |
| 顏色順序 | RGB | BGR (注意!) |
| 視頻支持 | 弱 | 強(qiáng) |
| GPU加速 | 無(wú) | 有 |
| 學(xué)習(xí)難度 | 低 | 中高 |
本文將從 Pillow 開(kāi)始,循序漸進(jìn)地介紹圖像處理的方方面面。
第一章:Pillow —— Python 圖像處理入門(mén)
1.1 Pillow 是什么
Pillow 是 Python Imaging Library (PIL) 的一個(gè)活躍分支。PIL 原版已經(jīng)停止維護(hù),Pillow 繼承了 PIL 的所有功能并持續(xù)更新。
Pillow 支持:
- 讀寫(xiě) 30+ 種圖像格式(PNG、JPEG、BMP、GIF、TIFF、WebP 等)
- 圖像縮放、旋轉(zhuǎn)、裁剪、翻轉(zhuǎn)
- 色彩模式轉(zhuǎn)換(RGB、RGBA、灰度、L、1 等)
- 濾鏡效果(模糊、銳化、邊緣檢測(cè)、浮雕等)
- 圖像增強(qiáng)(亮度、對(duì)比度、色彩飽和度)
- 在圖像上繪制文字和圖形
- 圖像合成與疊加
pip install pillow
from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance
1.2 圖像基礎(chǔ)概念
在學(xué)習(xí)圖像處理之前,需要理解幾個(gè)核心概念:
像素(Pixel)
像素是圖像的最小單位。每張圖片都是由大量像素排列組成的網(wǎng)格:

顏色模式
| 模式 | 說(shuō)明 | 每像素字節(jié)數(shù) | 用途 |
|---|---|---|---|
1 | 黑白(1-bit) | 1/8 | 位圖 |
L | 灰度 | 1 | 黑白照片 |
RGB | 紅綠藍(lán)三通道 | 3 | 彩色 圖片 |
RGBA | RGB + 透明度 | 4 | 需要透明的圖片 |
CMYK | 印刷四色 | 4 | 印刷輸出 |
P | 調(diào)色板模式 | 1 | GIF 動(dòng)畫(huà) |
圖像尺寸與分辨率
# 圖片尺寸 = 寬 × 高 (單位:像素) # 1920 × 1080 = 2,073,600 像素 (約200萬(wàn)像素,即 2MP) # DPI (Dots Per Inch) = 每英寸的像素?cái)?shù) # 72 DPI: 屏幕顯示標(biāo)準(zhǔn) # 150 DPI: 普通打印 # 300 DPI: 高質(zhì)量打印
1.3 圖像的打開(kāi)與創(chuàng)建
打開(kāi)已有圖片
from PIL import Image
# 打開(kāi)圖片
img = Image.open('photo.jpg')
# 查看圖片信息
print(f"格式: {img.format}") # JPEG, PNG 等
print(f"模式: {img.mode}") # RGB, RGBA, L 等
print(f"尺寸: {img.size}") # (寬度, 高度)
print(f"寬度: {img.width} 像素")
print(f"高度: {img.height} 像素")
# 查看 EXIF 信息(相機(jī)參數(shù)等)
exif = img._getexif()
if exif:
for tag_id, value in exif.items():
print(f" {tag_id}: {value}")
創(chuàng)建新圖片
# 創(chuàng)建空白圖片
img = Image.new('RGB', (800, 400), color='#2c3e50')
# 創(chuàng)建透明圖片
img = Image.new('RGBA', (400, 300), (0, 0, 0, 0))
# 從像素?cái)?shù)據(jù)創(chuàng)建
pixels = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
img = Image.new('RGB', (3, 1))
img.putdata(pixels)
運(yùn)行效果 —— 創(chuàng)建自定義圖形:

1.4 圖像的保存與格式轉(zhuǎn)換
Pillow 支持在不同格式之間自由轉(zhuǎn)換:
img = Image.open('source.png')
# 保存為不同格式
img.save('output.jpg', 'JPEG', quality=95) # JPEG, 質(zhì)量95%
img.save('output.bmp', 'BMP') # BMP 無(wú)損
img.save('output.webp', 'WEBP') # WebP 現(xiàn)代格式
img.save('output.gif', 'GIF') # GIF
img.save('output.tiff', 'TIFF') # TIFF 專(zhuān)業(yè)格式
各格式的文件大小對(duì)比(同一張圖片):
格式測(cè)試輸出: PNG: .png → 1.9 KB ← 無(wú)損壓縮,體積中等 JPEG: .jpg → 6.5 KB ← 有損壓縮,體積較大 BMP: .bmp → 351.6 KB ← 無(wú)壓縮,體積巨大 WEBP: .webp → 0.9 KB ← 新一代格式,體積最小
| 格式 | 特點(diǎn) | 適用場(chǎng)景 | 透明支持 |
|---|---|---|---|
| PNG | 無(wú)損壓縮 | 網(wǎng)頁(yè)圖標(biāo)、截圖 | 支持 |
| JPEG | 有損壓縮、高壓縮率 | 照片存儲(chǔ) | 不支持 |
| BMP | 無(wú)壓縮、原始數(shù)據(jù) | 需要無(wú)損的場(chǎng)景 | 不支持 |
| WebP | 高壓縮率、現(xiàn)代格式 | 網(wǎng)頁(yè)優(yōu)化 | 支持 |
| GIF | 動(dòng)畫(huà)、256色限制 | 表情包、動(dòng)畫(huà) | 支持 |
| TIFF | 無(wú)損、多頁(yè) | 印刷、醫(yī)療影像 | 支持 |
1.5 圖像裁剪與縮放
運(yùn)行效果:



裁剪
img = Image.open('photo.jpg')
# 裁剪區(qū)域: (左, 上, 右, 下)
cropped = img.crop((100, 50, 500, 350))
cropped.save('cropped.jpg')
裁剪坐標(biāo)示意:

縮放
# 指定尺寸縮放(可能變形) resized = img.resize((400, 300)) # 高質(zhì)量縮放(使用 LANCZOS 濾波器) resized = img.resize((400, 300), Image.LANCZOS) # 等比縮放(保持寬高比) img.thumbnail((800, 800)) # 最大邊不超過(guò)800 # 放大 2 倍 enlarged = img.resize((img.width * 2, img.height * 2), Image.LANCZOS)
縮放質(zhì)量對(duì)比:
| 方法 | 說(shuō)明 | 速度 | 質(zhì)量 |
|---|---|---|---|
NEAREST | 最近鄰插值 | 最快 | 最差(鋸齒) |
BILINEAR | 雙線性插值 | 較快 | 一般 |
BICUBIC | 雙三次插值 | 較慢 | 較好 |
LANCZOS | Lanczos 重采樣 | 最慢 | 最好 |
1.6 旋轉(zhuǎn)與翻轉(zhuǎn)
運(yùn)行效果:

img = Image.open('photo.jpg')
# 旋轉(zhuǎn)
rotated_45 = img.rotate(45) # 逆時(shí)針旋轉(zhuǎn)45度
rotated_90 = img.rotate(90, expand=True) # 旋轉(zhuǎn)90度,擴(kuò)展畫(huà)布
rotated_free = img.rotate(30, expand=True, fillcolor='#2c3e50') # 自定義背景色
# 翻轉(zhuǎn)
flipped_h = img.transpose(Image.FLIP_LEFT_RIGHT) # 水平翻轉(zhuǎn)
flipped_v = img.transpose(Image.FLIP_TOP_BOTTOM) # 垂直翻轉(zhuǎn)
1.7 繪圖與文字
Pillow 提供了 ImageDraw 模塊,可以在圖片上繪制各種圖形和文字:
from PIL import Image, ImageDraw, ImageFont
img = Image.new('RGB', (800, 400), '#ecf0f1')
draw = ImageDraw.Draw(img)
# 繪制矩形
draw.rectangle([50, 50, 200, 200], fill='#e74c3c', outline='white', width=3)
# 繪制橢圓
draw.ellipse([250, 50, 400, 200], fill='#3498db', outline='white', width=3)
# 繪制三角形
draw.polygon([(500, 200), (450, 50), (550, 50)], fill='#2ecc71', outline='white')
# 繪制圓角矩形
draw.rounded_rectangle([600, 50, 750, 200], radius=20, fill='#f39c12')
# 繪制線條
draw.line([(50, 250), (750, 250)], fill='#2c3e50', width=3)
# 繪制文字
font = ImageFont.truetype("msyh.ttc", 36) # 微軟雅黑36號(hào)
draw.text((200, 300), 'Hello Pillow!', fill='#2c3e50', font=font)
繪制函數(shù)速查:
| 方法 | 說(shuō)明 | 參數(shù) |
|---|---|---|
rectangle(xy, fill, outline, width) | 矩形 | (左,上,右,下) |
ellipse(xy, fill, outline, width) | 橢圓/圓 | (左,上,右,下) |
polygon(points, fill, outline) | 多邊形 | [(x1,y1), (x2,y2), ...] |
line(xy, fill, width) | 線段 | (x1,y1,x2,y2) |
text(xy, text, fill, font) | 文字 | (x,y), 文本, 字體 |
arc(xy, start, end, fill, width) | 弧線 | 角度(度) |
chord(xy, start, end, fill, outline) | 弦 | 角度 |
pieslice(xy, start, end, fill) | 扇形 | 角度 |
rounded_rectangle | 圓角矩形 | 半徑參數(shù) |
1.8 濾鏡效果大全
運(yùn)行效果:

Pillow 內(nèi)置了多種濾鏡:
from PIL import ImageFilter
img = Image.open('photo.jpg')
# 模糊
img_blur = img.filter(ImageFilter.GaussianBlur(radius=5))
img_blur = img.filter(ImageFilter.BLUR) # 默認(rèn)模糊
# 銳化
img_sharpen = img.filter(ImageFilter.SHARPEN)
img_sharpen = img.filter(ImageFilter.UnsharpMask(radius=2, percent=150))
# 邊緣檢測(cè)
img_edges = img.filter(ImageFilter.FIND_EDGES)
# 浮雕
img_emboss = img.filter(ImageFilter.EMBOSS)
# 輪廓
img_contour = img.filter(ImageFilter.CONTOUR)
# 細(xì)節(jié)增強(qiáng)
img_detail = img.filter(ImageFilter.DETAIL)
# 平滑
img_smooth = img.filter(ImageFilter.SMOOTH)
img_smooth_more = img.filter(ImageFilter.SMOOTH_MORE)
# 多重濾鏡疊加
result = img.filter(ImageFilter.GaussianBlur(2)).filter(ImageFilter.SHARPEN)
所有內(nèi)置濾鏡一覽:
| 濾鏡 | 效果 | 適用場(chǎng)景 |
|---|---|---|
BLUR | 模糊 | 背景虛化、隱私保護(hù) |
CONTOUR | 輪廓 | 素描效果 |
DETAIL | 細(xì)節(jié)增強(qiáng) | 照片銳化 |
EDGE_ENHANCE | 邊緣增強(qiáng) | 圖像增強(qiáng) |
EDGE_ENHANCE_MORE | 強(qiáng)邊緣增強(qiáng) | 更強(qiáng)的增強(qiáng) |
EMBOSS | 浮雕 | 藝術(shù)效果 |
FIND_EDGES | 邊緣檢測(cè) | 圖像分析 |
SHARPEN | 銳化 | 照片修復(fù) |
SMOOTH | 平滑 | 降噪 |
SMOOTH_MORE | 更強(qiáng)平滑 | 更強(qiáng)降噪 |
GaussianBlur(n) | 高斯模糊 | 可控模糊程度 |
UnsharpMask | 反銳化蒙版 | 專(zhuān)業(yè)銳化 |
1.9 顏色調(diào)整與增強(qiáng)
運(yùn)行效果:

from PIL import ImageEnhance
img = Image.open('photo.jpg')
# 亮度調(diào)整 (1.0=原始, >1增強(qiáng), <1減弱)
enhancer = ImageEnhance.Brightness(img)
bright = enhancer.enhance(1.5) # 亮度提高50%
# 對(duì)比度調(diào)整
enhancer = ImageEnhance.Contrast(img)
contrast = enhancer.enhance(1.8) # 對(duì)比度提高80%
# 色彩飽和度調(diào)整
enhancer = ImageEnhance.Color(img)
color = enhancer.enhance(2.0) # 飽和度翻倍
# 銳度調(diào)整
enhancer = ImageEnhance.Sharpness(img)
sharp = enhancer.enhance(2.0) # 銳度翻倍
# 綜合調(diào)整
from PIL import ImageOps
img_auto = ImageOps.autocontrast(img) # 自動(dòng)對(duì)比度
img_equalize = ImageOps.equalize(img) # 直方圖均衡化
img_invert = ImageOps.invert(img.convert('RGB')) # 反色
img_gray = ImageOps.grayscale(img) # 轉(zhuǎn)灰度
顏色調(diào)整效果表:
| 方法 | 調(diào)整值范圍 | 效果 | 典型值 |
|---|---|---|---|
Brightness | 0.0 ~ ∞ | 明暗 | 1.2~1.5 |
Contrast | 0.0 ~ ∞ | 對(duì)比 | 1.3~1.8 |
Color | 0.0 ~ ∞ | 飽和度 | 1.5~2.5 |
Sharpness | 0.0 ~ ∞ | 清晰度 | 1.5~3.0 |
1.10 水印與合成
運(yùn)行效果:

文字水印
from PIL import Image, ImageDraw, ImageFont
def add_text_watermark(image_path, text, output_path, opacity=128):
img = Image.open(image_path).convert('RGBA')
watermark = Image.new('RGBA', img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
font = ImageFont.truetype("msyh.ttc", 36)
# 在右下角添加水印
bbox = draw.textbbox((0, 0), text, font=font)
x = img.width - bbox[2] - 20
y = img.height - bbox[3] - 20
draw.text((x, y), text, fill=(128, 128, 128, opacity), font=font)
result = Image.alpha_composite(img, watermark)
result.convert('RGB').save(output_path)
圖片水印
def add_image_watermark(image_path, watermark_path, output_path, position='bottom-right'):
img = Image.open(image_path).convert('RGBA')
watermark = Image.open(watermark_path).convert('RGBA')
# 縮放水印
wm_size = (img.width // 5, img.height // 5)
watermark = watermark.resize(wm_size, Image.LANCZOS)
# 計(jì)算位置
if position == 'bottom-right':
x = img.width - wm_size[0] - 20
y = img.height - wm_size[1] - 20
elif position == 'center':
x = (img.width - wm_size[0]) // 2
y = (img.height - wm_size[1]) // 2
# 調(diào)整透明度
watermark.putalpha(watermark.split()[3])
# 合成
img.paste(watermark, (x, y), watermark)
img.convert('RGB').save(output_path)
圖片拼接
def combine_images(images, cols=2, padding=10, bg_color='#2c3e50'):
rows_count = (len(images) + cols - 1) // cols
max_w = max(img.width for img in images)
max_h = max(img.height for img in images)
combined_w = cols * max_w + (cols + 1) * padding
combined_h = rows_count * max_h + (rows_count + 1) * padding
combined = Image.new('RGB', (combined_w, combined_h), bg_color)
for i, img in enumerate(images):
row = i // cols
col = i % cols
x = padding + col * (max_w + padding)
y = padding + row * (max_h + padding)
combined.paste(img, (x, y))
return combined
1.11 實(shí)戰(zhàn)案例:批量處理圖片
將前面學(xué)的技術(shù)組合起來(lái),做一個(gè)實(shí)用的批量處理腳本:
"""
批量處理圖片:調(diào)整大小 + 加水印 + 轉(zhuǎn)換格式
"""
from PIL import Image, ImageDraw, ImageFont, ImageEnhance, ImageFilter
import os
def batch_process(input_dir, output_dir, max_size=(1920, 1080),
watermark_text=None, output_format='JPEG'):
"""批量處理圖片"""
os.makedirs(output_dir, exist_ok=True)
supported = {'.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff'}
for filename in os.listdir(input_dir):
ext = os.path.splitext(filename)[1].lower()
if ext not in supported:
continue
filepath = os.path.join(input_dir, filename)
try:
img = Image.open(filepath)
except Exception:
print(f"跳過(guò)無(wú)法打開(kāi)的文件: {filename}")
continue
# 1. 轉(zhuǎn)為 RGB(去除透明通道)
if img.mode in ('RGBA', 'P'):
img = img.convert('RGB')
# 2. 縮放到最大尺寸
img.thumbnail(max_size, Image.LANCZOS)
# 3. 輕微銳化
img = img.filter(ImageFilter.SHARPEN)
# 4. 自動(dòng)對(duì)比度
from PIL import ImageOps
img = ImageOps.autocontrast(img)
# 5. 添加水印
if watermark_text:
draw = ImageDraw.Draw(img)
try:
font = ImageFont.truetype("msyh.ttc", max(20, img.width // 30))
except:
font = ImageFont.load_default()
text = watermark_text
bbox = draw.textbbox((0, 0), text, font=font)
x = img.width - (bbox[2] - bbox[0]) - 20
y = img.height - (bbox[3] - bbox[1]) - 20
draw.text((x, y), text, fill=(255, 255, 255), font=font)
# 6. 保存
name = os.path.splitext(filename)[0]
output_path = os.path.join(output_dir, f"{name}.{output_format.lower()}")
img.save(output_path, output_format, quality=90)
print(f"已處理: {filename} → {output_path}")
# 使用
batch_process(
input_dir='./photos',
output_dir='./photos_processed',
max_size=(1920, 1080),
watermark_text='? 2025 MyBlog'
)
第二章:OpenCV —— 計(jì)算機(jī)視覺(jué)利器
2.1 OpenCV 簡(jiǎn)介
OpenCV(Open Source Computer Vision Library)是世界上最大的計(jì)算機(jī)視覺(jué)庫(kù),支持 2500+ 種算法,覆蓋圖像處理、物體檢測(cè)、人臉識(shí)別、OCR、姿態(tài)估計(jì)等領(lǐng)域。
pip install opencv-python pip install opencv-contrib-python # 包含額外模塊
import cv2 import numpy as np
重要區(qū)別:OpenCV 使用 BGR 順序(藍(lán)-綠-紅),而不是 PIL 的 RGB 順序。這是一個(gè)常見(jiàn)的坑!
2.2 圖像讀取與基本操作
import cv2
# 讀取圖片 (BGR 格式)
img = cv2.imread('photo.jpg')
img_color = cv2.imread('photo.jpg', cv2.IMREAD_COLOR) # 彩色(默認(rèn))
img_gray = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE) # 灰度
# 查看信息
print(f"形狀: {img.shape}") # (高度, 寬度, 通道數(shù))
print(f"數(shù)據(jù)類(lèi)型: {img.dtype}") # uint8
print(f"像素總數(shù): {img.size}") # 高 × 寬 × 通道
# 顯示圖片
cv2.imshow('Image', img)
cv2.waitKey(0) # 按任意鍵關(guān)閉
cv2.destroyAllWindows()
# 保存圖片
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
像素操作
# 讀取單個(gè)像素 (BGR) pixel = img[100, 200] # [B, G, R] 值 # 修改像素 img[100, 200] = [255, 0, 0] # 藍(lán)色 # ROI(感興趣區(qū)域) roi = img[50:200, 100:300] # (y1:y2, x1:x2) img[50:200, 100:300] = 0 # 將該區(qū)域涂黑 # 使用掩碼 mask = np.zeros(img.shape[:2], dtype=np.uint8) mask[50:200, 100:300] = 255 result = cv2.bitwise_and(img, img, mask=mask)
2.3 圖像變換
import cv2
import numpy as np
img = cv2.imread('photo.jpg')
# 縮放
resized = cv2.resize(img, (400, 300)) # 指定尺寸
scaled = cv2.resize(img, None, fx=0.5, fy=0.5) # 按比例
# 旋轉(zhuǎn)
h, w = img.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, angle=45, scale=1.0)
rotated = cv2.warpAffine(img, matrix, (w, h))
# 仿射變換
pts1 = np.float32([[0, 0], [w-1, 0], [0, h-1]]) # 原始3個(gè)點(diǎn)
pts2 = np.float32([[0, 0], [w-1, 0], [int(w*0.33), h-1]]) # 目標(biāo)3個(gè)點(diǎn)
matrix = cv2.getAffineTransform(pts1, pts2)
warped = cv2.warpAffine(img, matrix, (w, h))
# 透視變換
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])
matrix = cv2.getPerspectiveTransform(pts1, pts2)
perspective = cv2.warpPerspective(img, matrix, (300, 300))
2.4 圖像濾波
img = cv2.imread('photo.jpg')
# 均值模糊
blur = cv2.blur(img, (5, 5))
# 高斯模糊(更自然的模糊效果)
gaussian = cv2.GaussianBlur(img, (5, 5), 0)
# 中值濾波(去除椒鹽噪聲效果最好)
median = cv2.medianBlur(img, 5)
# 雙邊濾波(保邊去噪)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
濾波效果對(duì)比:
| 方法 | 效果 | 噪聲類(lèi)型 | 邊緣保留 |
|---|---|---|---|
| 均值模糊 | 整體模糊 | 高斯噪聲 | 差 |
| 高斯模糊 | 平滑模糊 | 高斯噪聲 | 一般 |
| 中值濾波 | 清晰保留細(xì)節(jié) | 椒鹽噪聲 | 好 |
| 雙邊濾波 | 邊緣清晰 | 所有噪聲 | 最好 |
2.5 邊緣檢測(cè)
img = cv2.imread('photo.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Canny 邊緣檢測(cè)(最常用)
edges = cv2.Canny(gray, threshold1=50, threshold2=150)
# Sobel 算子
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
sobel = cv2.magnitude(sobel_x, sobel_y)
# Laplacian 算子
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
# 邊緣檢測(cè) + 二值化
_, binary = cv2.threshold(edges, 127, 255, cv2.THRESH_BINARY)
Canny 邊緣檢測(cè)的兩個(gè)閾值參數(shù):
threshold1: 低閾值 —— 弱邊緣threshold2: 高閾值 —— 強(qiáng)邊緣- 兩者之間的像素如果與強(qiáng)邊緣相連,也會(huì)被保留
2.6 顏色空間轉(zhuǎn)換
img = cv2.imread('photo.jpg')
# BGR → 灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# BGR → RGB(與PIL互轉(zhuǎn)時(shí)需要)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# BGR → HSV(色相-飽和度-明度,顏色分割常用)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# BGR → LAB(感知均勻的顏色空間)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# HSV 顏色分割示例
lower_red = np.array([0, 100, 100])
upper_red = np.array([10, 255, 255])
mask = cv2.inRange(hsv, lower_red, upper_red)
red_only = cv2.bitwise_and(img, img, mask=mask)
常用顏色空間:
| 顏色空間 | 組成 | 優(yōu)勢(shì) | 適用場(chǎng)景 |
|---|---|---|---|
| BGR | 藍(lán)-綠-紅 | OpenCV 默認(rèn) | 通用 |
| RGB | 紅-綠-藍(lán) | 通用標(biāo)準(zhǔn) | PIL/Web 互轉(zhuǎn) |
| HSV | 色相-飽和度-明值 | 顏色分割方便 | 顏色檢測(cè) |
| Grayscale | 灰度 | 單通道、計(jì)算快 | 邊緣檢測(cè)、OCR |
| LAB | 明度-紅綠-藍(lán)黃 | 感知均勻 | 顏色對(duì)比 |
| YCrCb | 亮度-紅差-藍(lán)差 | 膚色檢測(cè) | 人臉識(shí)別 |
2.7 形態(tài)學(xué)操作
形態(tài)學(xué)操作基于數(shù)學(xué)形態(tài)學(xué)理論,常用于二值圖像處理:
import cv2 import numpy as np # 先二值化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 定義結(jié)構(gòu)元素 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 也可用圓形: cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) # 腐蝕 —— 收縮白色區(qū)域 eroded = cv2.erode(binary, kernel, iterations=1) # 膨脹 —— 擴(kuò)張白色區(qū)域 dilated = cv2.dilate(binary, kernel, iterations=1) # 開(kāi)運(yùn)算 —— 先腐蝕后膨脹(去噪點(diǎn)) opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 閉運(yùn)算 —— 先膨脹后腐蝕(填孔洞) closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) # 形態(tài)學(xué)梯度 —— 膨脹 - 腐蝕(提取邊緣) gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel) # 頂帽 —— 原圖 - 開(kāi)運(yùn)算(提取小亮區(qū)域) tophat = cv2.morphologyEx(binary, cv2.MORPH_TOPHAT, kernel) # 黑帽 —— 閉運(yùn)算 - 原圖(提取小暗區(qū)域) blackhat = cv2.morphologyEx(binary, cv2.MORPH_BLACKHAT, kernel)
形態(tài)學(xué)操作效果圖解:

2.8 輪廓檢測(cè)
import cv2
img = cv2.imread('shapes.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找輪廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
# 繪制所有輪廓
result = img.copy()
cv2.drawContours(result, contours, -1, (0, 255, 0), 2)
# 分析每個(gè)輪廓
for i, contour in enumerate(contours):
# 面積
area = cv2.contourArea(contour)
# 周長(zhǎng)
perimeter = cv2.arcLength(contour, True)
# 多邊形近似
epsilon = 0.02 * perimeter
approx = cv2.approxPolyDP(contour, epsilon, True)
# 外接矩形
x, y, w, h = cv2.boundingRect(contour)
# 外接圓
(cx, cy), radius = cv2.minEnclosingCircle(contour)
print(f"輪廓 {i}: 面積={area:.0f}, 周長(zhǎng)={perimeter:.0f}, "
f"頂點(diǎn)數(shù)={len(approx)}, 類(lèi)形={'矩形' if len(approx)==4 else '其他'}")
# 繪制外接矩形和圓
cv2.rectangle(result, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.circle(result, (int(cx), int(cy)), int(radius), (0, 0, 255), 2)
輪廓分析速查:
| 函數(shù) | 說(shuō)明 | 返回值 |
|---|---|---|
contourArea(c) | 輪廓面積 | float |
arcLength(c, True) | 輪廓周長(zhǎng) | float |
approxPolyDP(c, e, True) | 多邊形近似 | 頂點(diǎn)數(shù)組 |
boundingRect(c) | 外接矩形 | (x, y, w, h) |
minEnclosingCircle(c) | 外接圓 | (center, radius) |
moments(c) | 圖像矩 | 字典 |
isContourConvex(c) | 是否凸多邊形 | bool |
選擇指南
| 你的需求 | 推薦工具 | 原因 |
|---|---|---|
| 給圖片加水印 | Pillow | 簡(jiǎn)單幾行代碼 |
| 批量調(diào)整圖片大小 | Pillow | API 簡(jiǎn)潔、速度快 |
| 圖片格式轉(zhuǎn)換 | Pillow | 支持 30+ 格式 |
| 給圖片加文字/圖形 | Pillow | ImageDraw 完美支持 |
| 圖片加濾鏡效果 | Pillow | 內(nèi)置豐富濾鏡 |
| 人臉識(shí)別/檢測(cè) | OpenCV | 內(nèi)置 Haar/DNN 模型 |
| 實(shí)時(shí)視頻處理 | OpenCV | VideoCapture 支持 |
| 邊緣檢測(cè)/輪廓 | OpenCV | Canny/輪廓檢測(cè)算法 |
| 圖像分類(lèi)/目標(biāo)檢測(cè) | OpenCV + 深度學(xué)習(xí) | DNN 模塊支持模型推理 |
| OCR 文字識(shí)別 | OpenCV + Tesseract | 預(yù)處理 + OCR |
兩者互轉(zhuǎn)
在實(shí)際項(xiàng)目中,經(jīng)常需要在 Pillow 和 OpenCV 之間轉(zhuǎn)換:
from PIL import Image
import cv2
import numpy as np
# Pillow → OpenCV
pil_img = Image.open('photo.jpg')
cv_img = np.array(pil_img)[:, :, ::-1] # RGB → BGR
# OpenCV → Pillow
cv_img = cv2.imread('photo.jpg')
pil_img = Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))
以上就是Python使用Pillow與OpenCV進(jìn)行圖像處理實(shí)戰(zhàn)的詳細(xì)內(nèi)容,更多關(guān)于Python Pillow與OpenCV圖像處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入淺析pycharm中 Make available to all projects的含義
這篇文章主要介紹了pycharm中 Make available to all projects的含義,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Python .py生成.pyd文件并打包.exe 的注意事項(xiàng)說(shuō)明
這篇文章主要介紹了Python .py生成.pyd文件并打包.exe 的注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
python執(zhí)行系統(tǒng)命令4種方法與比較
這篇文章主要介紹了python執(zhí)行系統(tǒng)命令4種方法與比較,需要的朋友可以參考下2021-04-04
python實(shí)現(xiàn)二維數(shù)組的對(duì)角線遍歷
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)二維數(shù)組的對(duì)角線遍歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
request基本使用及各種請(qǐng)求方式參數(shù)的示例
這篇文章主要為大家介紹了request的基本使用及各種請(qǐng)求方式參數(shù)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
python如何實(shí)現(xiàn)遞歸轉(zhuǎn)非遞歸
這篇文章主要介紹了python如何實(shí)現(xiàn)遞歸轉(zhuǎn)非遞歸,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-02-02
用Flask實(shí)現(xiàn)token登錄校驗(yàn)的解決方案
網(wǎng)站、小程序、APP 是否已經(jīng)登錄所代表的狀態(tài),代表一個(gè)概念是登錄態(tài), 我們常用的登錄態(tài)驗(yàn)證方式有cookie,session,token,token提供了另外一種不需要緩存賬戶和密碼的登錄狀態(tài)驗(yàn)證方式,本文給大家介紹了用Flask實(shí)現(xiàn)token登錄校驗(yàn)的解決方案,需要的朋友可以參考下2024-03-03

