使用Python/PIL检测图像是彩色,灰度还是黑白

Gep*_*eto 9 python opencv python-imaging-library python-2.7

我以jpeg格式从PDF文件中提取页面图像,我需要确定每个图像是否更灰度,颜色是黑色和白色(具有容差因子).

我找到了一些方法来处理PIL(这里和这里)的颜色检测,但我无法弄清楚如何回答这个简单的(视觉)问题:它是黑色和白色,彩色还是灰度图像?

我更喜欢使用Python和PIL这个部分,但如果有人有线索(或解决方案),我也可以使用OpenCV.

Noa*_*man 9

我尝试了Gepeto的解决方案,它有很多误报,因为颜色大变化可能只是偶然相似.这样做的正确方法是计算每个像素的方差.首先缩小图像,这样您就不必处理数百万像素.

默认情况下,此功能还使用平均颜色偏差调整,我发现这可以改善预测.这样做的一个副作用是它还会检测单色但非灰度图像(通常是棕褐色调的东西,模型似乎在检测到灰度偏差较大时会略微分解).您可以通过在色带上进行阈值处理将这些与真正的灰度分开.

我在一组13,000张摄影图像上进行了测试,得到的分类精度为99.1%,召回率为92.5%.通过使用非线性偏置调整可以进一步提高精度(例如,颜色值必须在0到255之间).也许看中间平方误差而不是MSE会更好地允许例如具有小颜色标记的灰度图像.

from PIL import Image, ImageStat
def detect_color_image(file, thumb_size=40, MSE_cutoff=22, adjust_color_bias=True):
    pil_img = Image.open(file)
    bands = pil_img.getbands()
    if bands == ('R','G','B') or bands== ('R','G','B','A'):
        thumb = pil_img.resize((thumb_size,thumb_size))
        SSE, bias = 0, [0,0,0]
        if adjust_color_bias:
            bias = ImageStat.Stat(thumb).mean[:3]
            bias = [b - sum(bias)/3 for b in bias ]
        for pixel in thumb.getdata():
            mu = sum(pixel)/3
            SSE += sum((pixel[i] - mu - bias[i])*(pixel[i] - mu - bias[i]) for i in [0,1,2])
        MSE = float(SSE)/(thumb_size*thumb_size)
        if MSE <= MSE_cutoff:
            print "grayscale\t",
        else:
            print "Color\t\t\t",
        print "( MSE=",MSE,")"
    elif len(bands)==1:
        print "Black and white", bands
    else:
        print "Don't know...", bands
Run Code Online (Sandbox Code Playgroud)

  • 嗨,谢谢你。我正在努力弄清楚这是如何工作的。“MSE”、“SSE”是什么意思?你能链接到一些文档吗? (2认同)

Tom*_*omB 8

我们使用这个简单的函数来确定图像的颜色因子.

# Iterate over all Pixels in the image (width * height times) and do this for every pixel:
{
    int rg = Math.abs(r - g);
    int rb = Math.abs(r - b);
    int gb = Math.abs(g - b);
    diff += rg + rb + gb;
}

return diff / (height * width) / (255f * 3f);
Run Code Online (Sandbox Code Playgroud)

由于灰度值为rg = 0且rb = 0且gb = 0,对于灰度图像,diff将接近0,对于彩色图像,diff将接近0.


sca*_*p3y -3

您可以使用cv::Mat::channels()运算符,它可以告诉您它是“灰度”(即 2 通道)还是“彩色”(即 3 通道)图像。对于黑白,您需要根据灰度设置更深入的测试,因为定义不同。