简体   繁体   中英

How to detect image is grayscale

I need to determine whether the image is grayscale (contains only black, white or shades of grey) or contains any color.

What libraries should I use for this?

This information is present in any CGImageRef object. You can get this object from any UIImage . In particular, the thing you would be interested in is CGImageGetColorSpace . Once you have that, you can call CGColorSpaceGetNumberOfComponents on the color space. There should only be three possibilities

CGColorSpaceGetNumberOfComponents returns 1: This image is grayscale, finished (one exception: It could be alpha-only, but I doubt you'll be sending any images like that. If you are, there is a way to determine whether an image is alpha only through its CGAlphaInfo )

CGColorSpaceGetNumberOfComponents returns 3: This image is RGB, and further analysis is needed to determine if it is grayscale or not (as the other answer states, loop over the pixels and if you find one where !(R == G == B) then it is not grayscale.

CGColorSpaceGetNumberOfComponents returns 4: This image is CMYK, and further analysis is needed. All grayscales in CMYK should be C == M == Y (usually they will be 0, as anything otherwise would be a waste of ink [this format was developed specifically with printers in mind]) with K equal to any value.

CGColorSpaceGetNumberOfComponents returns something else: ...well...cry

UPDATE

As pointed out in the comments, there is a more convenient function for figuring out the color model. CGColorSpaceGetModel will return values like kCGColorSpaceModelMonochrome or kCGColorSpaceModelRGB . This will take the ambiguity out of the above. After that you can check the same way for RGB or CMYK.

Here is @borrrden answer in code:

- (BOOL)isGrayScale{
    CGImageRef imageRef = [self CGImage];
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
    if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelRGB) {
        CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef);
        CFDataRef imageData = CGDataProviderCopyData(dataProvider);
        const UInt8 *rawData = CFDataGetBytePtr(imageData);

        size_t width = CGImageGetWidth(imageRef);
        size_t height = CGImageGetHeight(imageRef);

        int byteIndex = 0;
        BOOL allPixelsGrayScale = YES;
        for(int ii = 0 ; ii <width*height; ++ii)
        {
            int r = rawData[byteIndex];
            int g = rawData[byteIndex+1];
            int b = rawData[byteIndex+2];
            if (!((r == g)&&(g == b))) {
                allPixelsGrayScale = NO;
                break;
            }
            byteIndex += 4;
        }
        CFRelease(imageData);
        CGColorSpaceRelease(colorSpace);
        return allPixelsGrayScale;
    }
    else if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome){
        CGColorSpaceRelease(colorSpace); return YES;}
    else {CGColorSpaceRelease(colorSpace); return NO;}
}

The concept behind the grayscale is that for a pixel with Red, Green and Blue values, if the Amount of Red = Amount of Green = Amount of Blue , then you have an pixel with grayscale. If all pixels of your image is under this condition, it means you have a grayscale bitmap.

So, everything you gotta do is to loop over the RGB values of your bitmap. On iOS you can access the pixels of your image using the code below.

CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8 * data = CFDataGetBytePtr(pixelData);

Swift Version of approved answer

extension UIImage {
    func isGrayScale() -> Bool {
        let imageRef = self.cgImage
        let colorSpace = imageRef?.colorSpace
        if colorSpace?.model == .rgb {
            let dataProvider = imageRef?.dataProvider
            let imageData = dataProvider?.data
            let rawData = CFDataGetBytePtr(imageData!)
            let width = imageRef?.width
            let height = imageRef?.height

            var byteIndex = 0
            var allPixelsGrayScale = true
            for _ in 0...width!*height! {
                let red = rawData![byteIndex]
                let green = rawData![byteIndex + 1]
                let blue = rawData![byteIndex + 2]
                if !((red == green) && (green == blue)) {
                    allPixelsGrayScale = false
                    break
                }
                byteIndex += 4
            }
            return allPixelsGrayScale
        } else if colorSpace?.model == .monochrome {
            return true
        }
        return false
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM