我尝试了 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