Home > Back-end >  Detect if all pixels in an image are zero/black (Maya Python)
Detect if all pixels in an image are zero/black (Maya Python)

Time:08-11

Newbie. Using the following code to check if a grayscale image (a mask texture in Maya) has all black pixels in the RGB channels (meaning it is empty). This works, but is a bit slow on large images (2048x2048 is around 15 seconds). Looking for how I can speed this up / do this more efficiently.

EDIT: This is the original code

def all_black_pixels(image, width, height):
    img = PySide2.QtGui.QImage(width, height, PySide2.QtGui.QImage.Format.Format_Grayscale8)
    img.load(image)     
    for y in range(height):
        for x in range(width):
            color = PySide2.QtGui.QColor()
            color.setRgb(img.pixel(x,y))  
            black = False
           # print ( color.getRgb()[0] )
            if color.getRgb()[0] is not 0:
                black = True
   
    return black

EDIT: changing based on comments, for clarity and fixing:

import PySide2

def all_black_pixels(image):
    black = True
    img = PySide2.QtGui.QImage()
    img.load(image)
    TexSize = img.width()     
    for y in range(TexSize):
        for x in range(TexSize):
            color = PySide2.QtGui.QColor()
            color.setRgb(img.pixel(x,y))  
            print ( color.getRgb()[0] )
            if color.getRgb()[0] > 0:
                black = False
                break
   
    return black

all_black_pixels('/path/to/file/fileName.jpg', 20, 20)

CodePudding user response:

Assuming that image is an iterable byte object (bytes or bytearray), you can cycle through its values instead of making things more complex than they should: images are "collections of bytes", so, converting those collections to "actual" images and getting their pixel values makes very little sense.

Since you have to know if any of the pixels has a "non-black" color, you don't need to always iterate the whole image: yes, you have to iterate through the whole image because even the "last" pixel could be "non-black", but, as soon as any previous pixel isn't black, there's obviously no point in checking the next ones.

The assumption is:

  • 8-bit grayscale images always use a single byte for each pixel;
  • if the pixel is black, the value of the byte is 0;

Also, knowing the size of the image is useless.

So, just call the function only using the raw data alone:

def all_black_pixels(imageData):
    for pixel in imageData:
        if pixel:
            return False
    return True

Even simpler:

all_black_pixels = lambda imageData: not any(imageData)

Update

Since the OP has changed the question pointing out they start from an image file, the solution is similar, but it uses constBits(), which returns an array of the image data.

Consider that this is on the assumption that the image format is Format_Grayscale8, if it's not, it should be converted before with convertTo().

Also note that if you use PyQt, the returned type of constBits() is a sip pointer, so it must be converted to an actual array that can be accessed by python.

def all_black_pixels(path):
    img = QImage(path)
    if img.isNull():
        return False # or whatever you think appropriate

    if not img.format() == img.Format_Grayscale8:
        img.convertTo(img.Format_Grayscale8)

    # for PySide
    return not any(img.constBits())
    # for PyQt
    return not any(img.constBits().asarray(img.sizeInBytes()))
  • Related