如何仅使用Python stdlib检查jpeg图像是彩色还是灰度

kad*_*ina 20 python image-processing python-2.6

我必须在python中编写一个测试用例来检查jpg图像是彩色还是灰度.任何人都可以告诉我,如果有任何方法可以安装额外的库,如opencv吗?

sup*_*ind 13

可以按如下方式完成:

from scipy.misc import imread, imsave, imresize
image = imread(f_name)
if(len(image.shape)<3):
      print 'gray'
elif len(image.shape)==3:
      print 'Color(RGB)'
else:
      print 'others'
Run Code Online (Sandbox Code Playgroud)

  • 请注意,3通道图像也可以是灰度图像。该答案仅适用于 2 通道灰度图像。 (5认同)
  • @orbit 这是一个理想的情况。但是,可以存在具有 3 通道图像 (RGB) 的灰度图像,其中 R == G == B,如其他评论中所述。输出在视觉上与灰度图像相同,但它在元数据中是 RGB,该答案不适用于这种情况。我的意思是说,只有当通道数少于三个时,答案才算作灰度。 (2认同)

Ale*_*nko 13

使用 numpy 功能和 opencv 有更多 pythonic 方式:

import cv2
def isgray(imgpath):
    img = cv2.imread(imgpath)
    if len(img.shape) < 3: return True
    if img.shape[2]  == 1: return True
    b,g,r = img[:,:,0], img[:,:,1], img[:,:,2]
    if (b==g).all() and (b==r).all(): return True
    return False
Run Code Online (Sandbox Code Playgroud)


joa*_*000 11

扩展@gat答案:

import Image

def is_grey_scale(img_path):
    img = Image.open(img_path).convert('RGB')
    w,h = img.size
    for i in range(w):
        for j in range(h):
            r,g,b = img.getpixel((i,j))
            if r != g != b: return False
    return True
Run Code Online (Sandbox Code Playgroud)

基本上,检查每个像素是否是灰度(R == G == B)


Kar*_*l K 8

为了更快地处理,最好使用ImageChops避免每个像素上的循环(但是为了确保图像是真正的灰度,我们需要比较每个像素上的颜色而不能仅使用总和):

from PIL import Image,ImageChops

def is_greyscale(im):
    """
    Check if image is monochrome (1 channel or 3 identical channels)
    """
    if im.mode not in ("L", "RGB"):
        raise ValueError("Unsuported image mode")

    if im.mode == "RGB":
        rgb = im.split()
        if ImageChops.difference(rgb[0],rgb[1]).getextrema()[1]!=0: 
            return False
        if ImageChops.difference(rgb[0],rgb[2]).getextrema()[1]!=0: 
            return False
    return True
Run Code Online (Sandbox Code Playgroud)


M.F*_*M.F 6

对于灰度图像,某一像素中的所有通道都是相等的(如果只有一个通道,那么就不会有问题)。因此基本上,您可以列出所有像素及其三个通道值,以检查每个像素的所有三个通道是否相等。

Image.getcolors()返回未排序的(计数、像素)值列表。

im = Image.open('path_to_image.whatever')
color_count = im.getcolors()
Run Code Online (Sandbox Code Playgroud)

如果len(color_count)超过 256(默认最大值),此函数返回 None,这意味着您的像素列表中有超过 256 种颜色选项,因此它是彩色图像(灰度只能有 256 种颜色(0,0,0)(255,255,255)

所以之后你只需要:

if color_count: 
    # your image is grayscale
else:
    # your images is colored
Run Code Online (Sandbox Code Playgroud)

请注意,这仅在使用默认参数值 时才有效getcolors()

文档:https ://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.getcolors


smc*_*mci 5

快速结果的性能增强:由于许多图像具有黑色或白色边框,您希望通过从 im 中采样一些随机 i,j 点并测试它们来更快地终止吗?或者使用模运算来遍历图像行。首先我们采样(-无替换)说 100 个随机 i,j 点;在不太确定的情况下,我们会对其进行线性扫描。

使用自定义迭代器 iterpixels(im)。我没有安装 PIL,所以我无法测试这个,这是大纲:

import Image

def isColor(r,g,b): # use tuple-unpacking to unpack pixel -> r,g,b
    return (r != g != b)

class Image_(Image):
    def __init__(pathname):
        self.im = Image.open(pathname)
        self.w, self.h = self.im.size
    def iterpixels(nrand=100, randseed=None):
        if randseed:
            random.seed(randseed) # For deterministic behavior in test
        # First, generate a few random pixels from entire image
        for randpix in random.choice(im, n_rand)
            yield randpix
        # Now traverse entire image (yes we will unwantedly revisit the nrand points once)
        #for pixel in im.getpixel(...): # you could traverse rows linearly, or modulo (say) (im.height * 2./3) -1
        #    yield pixel

    def is_grey_scale(img_path="lena.jpg"):
        im = Image_.(img_path)
        return (any(isColor(*pixel)) for pixel in im.iterpixels())
Run Code Online (Sandbox Code Playgroud)

(我的原话也是如此,首先你检查 JPEG 头,偏移量 6:分量数(1 = 灰度,3 = RGB)。如果它是 1 = 灰度,你已经知道答案,而无需检查单个像素。)


Sre*_*ran 5

我遇到了类似的情况,我尝试了以下方法:

  1. 使用IMREAD_UNCHANGED和检查 image.shape 进行读取
  2. 分割 B、G、R 通道并检查它们是否相等

这两种方法在我的数据集中只获得了 53% 的准确率。我必须放宽检查不同通道中像素的条件,并创建一个比率将其分类为灰色或彩色。通过这种方法,我的数据集准确率达到 87.3%。

这是对我有用的逻辑:

import cv2
import numpy as np

###test image
img=cv2.imread('test.jpg')

### splitting b,g,r channels
b,g,r=cv2.split(img)

### getting differences between (b,g), (r,g), (b,r) channel pixels
r_g=np.count_nonzero(abs(r-g))
r_b=np.count_nonzero(abs(r-b))
g_b=np.count_nonzero(abs(g-b))

### sum of differences
diff_sum=float(r_g+r_b+g_b)

### finding ratio of diff_sum with respect to size of image
ratio=diff_sum/img.size

if ratio>0.005:
    print("image is color")
else:
    print("image is greyscale")
Run Code Online (Sandbox Code Playgroud)