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
我们使用这个简单的函数来确定图像的颜色因子。
# 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);
对于灰度图像,由于灰度值的 r-g = 0、r-b = 0 和 g-b = 0,因此差异值将接近于 0;对于彩色图像,差异值将大于 0。
我已经找到了一个方法,可以使用 PIL.ImageStat
模块来猜测。感谢 这篇文章,对于图像单色的确定。
from PIL import Image, ImageStat
MONOCHROMATIC_MAX_VARIANCE = 0.005
COLOR = 1000
MAYBE_COLOR = 100
def detect_color_image(file):
v = ImageStat.Stat(Image.open(file)).var
is_monochromatic = reduce(lambda x, y: x and y < MONOCHROMATIC_MAX_VARIANCE, v, True)
print file, '-->\t',
if is_monochromatic:
print "Monochromatic image",
else:
if len(v)==3:
maxmin = abs(max(v) - min(v))
if maxmin > COLOR:
print "Color\t\t\t",
elif maxmin > MAYBE_COLOR:
print "Maybe color\t",
else:
print "grayscale\t\t",
print "(",maxmin,")"
elif len(v)==1:
print "Black and white"
else:
print "Don't know..."
< p > COLOR
和 MAYBE_COLOR
常量是快速切换查找彩色和灰度图像之间差异的方法,但这不安全。例如,我有几个JPEG图像,虽然看起来是彩色的,但实际上是灰度的,并且由于扫描过程中的一些颜色伪像而带有一些颜色元素。这就是为什么我需要另一种方法来确定真正的彩色图像和其他图像之间的区别。 < / p>
< p > 如果有更好的方法,请告诉我。 < / p>
我个人更喜欢TomB的答案。这不是一个新答案,我只是想发布Java版本:
private Mat calculateChannelDifference(Mat mat) {
// Create channel list:
List<Mat> channels = new ArrayList<>();
for (int i = 0; i < 3; i++) {
channels.add(new Mat());
}
// Split the channels of the input matrix:
Core.split(mat, channels);
Mat temp = new Mat();
Mat result = Mat.zeros(mat.size(), CvType.CV_8UC1);
for (int i = 0; i < channels.size(); i++) {
// Calculate difference between 2 successive channels:
Core.absdiff(channels.get(i), channels.get((i + 1) % channels.size()), temp);
// Add the difference to the result:
Core.add(temp, result, result);
}
return result;
}
Core.mean()
来完成。import numpy as np
import cv2
import imutils
def image_colorfulness(image):
(B, G, R) = cv2.split(image.astype("float"))
rg = np.absolute(R - G)
yb = np.absolute(0.5 * (R + G) - B)
(rbMean, rbStd) = (np.mean(rg), np.std(rg))
(ybMean, ybStd) = (np.mean(yb), np.std(yb))
stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))
return stdRoot + (0.3 * meanRoot)
image = cv2.imread('green.JPG')
image = imutils.resize(image, width=250)
C = image_colorfulness(image)
#set a threshold
print(C)
if C > 10:
print('its a color image...')
elif 8 < C <= 10:
print('Not Sure...')
else:
print('Black and white image...')
cv2.putText(image, "{:.2f}".format(C), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.4, (0, 255, 0), 3)
cv2.imshow('im',image)
cv2.waitKey(0)
这种解决方案是受到TomB的帖子启发的,有一点变化。 Tom的帖子基于RGB颜色空间,而我的基于LAB颜色空间。要了解有关LAB空间的更多信息,请阅读此帖子以及其中提到的链接。
使用LAB空间的优点
LAB和RGB一样具有3个通道。 但是只有2个通道具有颜色信息(A和B),而L通道表示亮度值。与必须分析所有三个通道的RGB不同,使用LAB,我们可以仅分析2个通道。 当需要分析大量图像时,此方法将受益良多。
方法:
该方法与Tom的帖子没有区别。 这里我们将:
代码
使用的图像:
灰度图像:
彩色图像:
einstein_img = cv2.imread('Einstein.jpg')
flower_img = cv2.imread('flower.jpg')
# convert to LAB space
elab = cv2.cvtColor(einstein_img, cv2.COLOR_BGR2LAB)
flab = cv2.cvtColor(flower_img, cv2.COLOR_BGR2LAB)
# split the channels
el, ea, eb = cv2.split(elab)
# obtain difference between A and B channel at every pixel location
de = abs(ea-eb)
# find the mean of this difference
mean_e = np.mean(de)
# same as above for the color image:
fl, fa, fb = cv2.split(flab)
df = abs(fa-fb)
mean_f = np.mean(df)
# for gray image
print(mean_e)
0.0
# for color image
print(mean_f)
83.5455
为什么这个工作?
这个方法有效是因为主要由白色、灰色和黑色组成的图像在LAB空间的双色通道中没有显示出太大的变化。它被设计用于很好地分割/隔离主导颜色。但对于少彩色的图像也可以很好地工作。
彩色flower
图像的A和B通道并排放置:
由于每个像素之间存在差异,我们得到了一个非零的平均值。
灰色Einstein
图像的A和B通道并排放置:
然而,在这里我们获得了零的平均值。
注意:尽管0是理想的平均值,但在灰度图像中可能会出现非零值的情况。该值不会像彩色图像那样大。在这种情况下,可以定义一个阈值。