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 (2048×2048 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)
Advertisement
Answer
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()))