Pillow ImageStat 模块
下面给你一个 Pillow(PIL Fork)中 ImageStat 模块 的完整入门指南,包含所有统计功能、计算方法、代码示例、图像质量评估、批量分析、颜色分布可视化及高级应用。
(基于 Pillow ≥ 9.0,Python 3.8+)
1. 安装 Pillow
pip install --upgrade pillow
2. 基本导入
from PIL import Image, ImageStat
import matplotlib.pyplot as plt # 用于可视化(可选)
3. ImageStat.Stat 核心统计项
| 属性 | 说明 | 返回值 |
|---|---|---|
count | 像素总数 | int |
sum | 各通道像素和 | tuple |
sum2 | 各通道平方和 | tuple |
mean | 平均值 | tuple |
median | 中值 | tuple |
rms | 均方根(RMS) | tuple |
var | 方差 | tuple |
stddev | 标准差 | tuple |
extrema | 极值 (min, max) | tuple |
histogram | 直方图(可选) | list |
4. 基础用法:统计整张图
img = Image.open("photo.jpg").convert("RGB")
stat = ImageStat.Stat(img)
print(f"像素总数: {stat.count}")
print(f"平均值: {stat.mean}") # [R_avg, G_avg, B_avg]
print(f"标准差: {stat.stddev}")
print(f"极值: {stat.extrema}") # [(R_min,R_max), (G_min,G_max), ...]
5. 局部区域统计(bbox 参数)
# 统计左上角 200x200 区域
bbox = (0, 0, 200, 200)
stat = ImageStat.Stat(img, bbox)
print(f"局部平均亮度: {sum(stat.mean)/3:.1f}")
6. 常用图像质量评估指标
def image_quality_metrics(img):
stat = ImageStat.Stat(img.convert("L")) # 转灰度计算亮度
brightness = sum(stat.mean) / len(stat.mean) # 平均亮度
contrast = stat.stddev[0] # 标准差 ≈ 对比度
dynamic_range = stat.extrema[0][1] - stat.extrema[0][0]
return {
"brightness": brightness,
"contrast": contrast,
"dynamic_range": dynamic_range,
"is_dark": brightness < 50,
"is_low_contrast": contrast < 30,
}
img = Image.open("test.jpg")
metrics = image_quality_metrics(img)
print(metrics)
7. 直方图分析 + 可视化
def plot_histogram(img, title="Histogram"):
stat = ImageStat.Stat(img)
hist = stat.histogram
# 分通道绘制
channels = img.split() if img.mode in ("RGB", "RGBA") else [img]
colors = ("red", "green", "blue", "alpha")[:len(channels)]
plt.figure(figsize=(10, 4))
for i, (ch, color) in enumerate(zip(channels, colors)):
ch_hist = stat.histogram[i*256:(i+1)*256]
plt.plot(ch_hist, color=color, alpha=0.7, label=f"{color.upper()} channel")
plt.title(title)
plt.xlabel("Pixel Value")
plt.ylabel("Frequency")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 使用
plot_histogram(Image.open("flower.jpg"))
8. 高级应用
8.1 自动曝光评估(AE)
def auto_exposure_advice(img):
stat = ImageStat.Stat(img.convert("L"))
brightness = stat.mean[0]
if brightness < 60:
return "过暗,建议增加曝光"
elif brightness > 180:
return "过亮,建议减少曝光"
else:
return "曝光正常"
print(auto_exposure_advice(img))
8.2 批量图像质量报告
import os
import pandas as pd
def batch_quality_report(image_dir):
results = []
for fname in os.listdir(image_dir):
if fname.lower().endswith(('.jpg', '.png', '.jpeg')):
path = os.path.join(image_dir, fname)
img = Image.open(path)
stat = ImageStat.Stat(img.convert("L"))
results.append({
"filename": fname,
"width": img.width,
"height": img.height,
"brightness": round(stat.mean[0], 1),
"contrast": round(stat.stddev[0], 1),
"dynamic_range": stat.extrema[0][1] - stat.extrema[0][0],
})
df = pd.DataFrame(results)
df.to_csv("quality_report.csv", index=False)
print("报告已保存: quality_report.csv")
return df
batch_quality_report("photos/")
8.3 图像相似度比较(基于统计)
def stats_similarity(img1, img2):
s1 = ImageStat.Stat(img1.convert("RGB"))
s2 = ImageStat.Stat(img2.convert("RGB"))
# 平均值差异
mean_diff = sum(abs(a - b) for a, b in zip(s1.mean, s2.mean))
# 标准差差异
std_diff = sum(abs(a - b) for a, b in zip(s1.stddev, s2.stddev))
return mean_diff + std_diff # 值越小越相似
# 使用
img1 = Image.open("a.jpg")
img2 = Image.open("b.jpg").resize(img1.size)
print(f"统计差异: {stats_similarity(img1, img2):.1f}")
8.4 检测纯色/噪点图
def is_solid_color(img, threshold=5):
stat = ImageStat.Stat(img)
for i in range(len(stat.stddev)):
if stat.stddev[i] > threshold:
return False
return True
def is_noisy(img, threshold=50):
stat = ImageStat.Stat(img.convert("L"))
return stat.stddev[0] > threshold
print("纯色图:", is_solid_color(img))
print("噪点图:", is_noisy(img))
9. 完整示例:图像诊断工具
def diagnose_image(input_path):
img = Image.open(input_path)
gray = img.convert("L")
stat = ImageStat.Stat(gray)
print(f"=== {input_path} 诊断报告 ===")
print(f"尺寸: {img.width}×{img.height}")
print(f"模式: {img.mode}")
print(f"亮度: {stat.mean[0]:.1f} (建议 80~160)")
print(f"对比度: {stat.stddev[0]:.1f} (建议 >35)")
print(f"动态范围: {stat.extrema[0][1] - stat.extrema[0][0]}")
if stat.mean[0] < 60:
print("警告: 图像过暗")
if stat.stddev[0] < 25:
print("警告: 对比度过低")
if is_solid_color(img):
print("警告: 疑似纯色图")
# 可视化
plot_histogram(img, f"直方图 - {os.path.basename(input_path)}")
diagnose_image("sample.jpg")
10. 常见问题 & 解决方案
| 问题 | 原因 | 解决 |
|---|---|---|
AttributeError: 'Stat' object has no attribute 'xxx' | 属性名错误 | 检查文档:mean, stddev, extrema |
统计结果为 [0] | 图像是 1 模式(二值) | 先 .convert("L") 或 "RGB" |
| 局部统计无效 | bbox 超出图像 | 确保 0 ≤ x1 < x2 ≤ width |
| 性能慢 | 大图 + 直方图 | 避免频繁调用 histogram |
11. 官方文档
- https://pillow.readthedocs.io/en/stable/reference/ImageStat.html
一键诊断脚本:imgstat_tool.py
#!/usr/bin/env python3
import argparse
from PIL import Image, ImageStat
import json
def main():
parser = argparse.ArgumentParser(description="ImageStat 诊断工具")
parser.add_argument("image")
parser.add_argument("--json", action="store_true", help="输出 JSON")
parser.add_argument("--region", nargs=4, type=int, help="x1 y1 x2 y2")
args = parser.parse_args()
img = Image.open(args.image)
stat = ImageStat.Stat(img, bbox=args.region)
result = {
"filename": args.image,
"size": img.size,
"mode": img.mode,
"pixels": stat.count,
"mean": [round(x, 2) for x in stat.mean],
"stddev": [round(x, 2) for x in stat.stddev],
"extrema": stat.extrema,
"brightness": round(sum(stat.mean)/len(stat.mean), 2) if stat.mean else 0,
}
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
for k, v in result.items():
print(f"{k}: {v}")
if __name__ == "__main__":
main()
使用:
python imgstat_tool.py photo.jpg --json > report.json
python imgstat_tool.py dark.jpg --region 100 100 300 300
需要我帮你实现 自动图像增强建议、批量去重、曝光直方图均衡、智能裁剪建议、照片评分系统 等功能吗?直接说需求,我给你完整代码!