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

需要我帮你实现 自动图像增强建议、批量去重、曝光直方图均衡、智能裁剪建议、照片评分系统 等功能吗?直接说需求,我给你完整代码!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注