检查图像是否全白的最佳性能方法?

时间:2015-06-09 12:47:44

标签: ios objective-c performance core-graphics

我正在尝试确定当前的图纸是否全白。我能想到的解决方案是缩小图像,然后逐像素地检查它是否为白色,并在找到非白色像素时立即返回NO。

它有效,但我有一种直觉,它可以以更高效的方式完成。这是代码:

- (BOOL)imageIsAllWhite:(UIImage *)image {
    CGSize size = CGSizeMake(100.0f, 100.0f);
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[image scaledImageWithSize:size]];


    unsigned char pixel[4 * (int)size.width * (int)size.height];

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef cgContext = CGBitmapContextCreate(
            pixel,
            (size_t)size.width,
            (size_t)size.height,
            8,
            (size_t)(size.width * 4),
            colorSpace,
            kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(cgContext, 0, 0);

    [imageView.layer renderInContext:cgContext];

    CGContextRelease(cgContext);

    CGColorSpaceRelease(colorSpace);

    for (int i = 0; i < sizeof(pixel); i = i + 4) {
        if(!(pixel[i] == 255 && pixel[i+1] == 255 && pixel[i+2] == 255)) {
            return NO;
        }
    }

    return YES;
}

有任何改进的想法吗?

2 个答案:

答案 0 :(得分:2)

请按照以下代码检查UIImage是否为白色

- (BOOL) checkIfImage:(UIImage *)someImage {
    CGImageRef image = someImage.CGImage;
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    GLubyte * imageData = malloc(width * height * 4);
    int bytesPerPixel = 4;
    int bytesPerRow = bytesPerPixel * width;
    int bitsPerComponent = 8;
    CGContextRef imageContext =
    CGBitmapContextCreate(
                          imageData, width, height, bitsPerComponent, bytesPerRow, CGImageGetColorSpace(image),
                          kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
                          );

    CGContextSetBlendMode(imageContext, kCGBlendModeCopy);
    CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), image);
    CGContextRelease(imageContext);

    int byteIndex = 0;

    BOOL imageExist = YES;
    for ( ; byteIndex < width*height*4; byteIndex += 4) {
        CGFloat red = ((GLubyte *)imageData)[byteIndex]/255.0f;
        CGFloat green = ((GLubyte *)imageData)[byteIndex + 1]/255.0f;
        CGFloat blue = ((GLubyte *)imageData)[byteIndex + 2]/255.0f;
        CGFloat alpha = ((GLubyte *)imageData)[byteIndex + 3]/255.0f;
        if( red != 1 || green != 1 || blue != 1 || alpha != 1 ){
            imageExist = NO;
            break;
        }
    }

    return imageExist;
}

调用函数

 UIImage *image = [UIImage imageNamed:@"demo1.png"];
    BOOL isImageFlag=[self checkIfImage:image];
    if (isImageFlag == YES) {
            NSLog(@"YES it's totally White");
    }else{
            NSLog(@"Nope it's not White");
    }

答案 1 :(得分:1)

感觉就像没有快速的路线可以进入GPU并再次返回所以答案实际上并不比采用统计方法和使用GCD确保多核利用更有趣。

在大多数图像中,颜色更可能接近其他类似颜色。因此,如果一个像素是白色,则其相邻像素更可能也是白色。因此,通过像素的严格线性进展不太可能比相距一定距离的采样点快速找到白色像素,然后采样更近的点等。理想情况下,有一些f(x)采用相关的整数范围作为输入并且仅返回它们中的每一个,使得f(x)f(x+1)之间的距离对于x = 0最大,然后单调减小。

如果图像相当大,如果您能够负担得起异步返回结果,那么将任务分配到多个核心的成本可能会被多个核心同时处理它的成本所抵消。

您正在将图像尺寸修正为100x100像素。我将采取自由并假设你可以升级到128x128因为它使f(x)变得容易 - 在这种情况下你可以做一点反转。

E.g。

static inline int convolution(int input) {
    // bit reverse a 14-bit number
    return ((input & 0x0001) << 13) |
           ((input & 0x0002) << 11) |
           ((input & 0x0004) << 9) |
           ((input & 0x0008) << 7) |
           ((input & 0x0010) << 5) |
           ((input & 0x0020) << 3) |
           ((input & 0x0040) << 1) |
           ((input & 0x0080) >> 1) |
           ((input & 0x0100) >> 3) |
           ((input & 0x0200) >> 5) |
           ((input & 0x0400) >> 7) |
           ((input & 0x0800) >> 9) |
           ((input & 0x1000) >> 11) |
           ((input & 0x2000) >> 13);
}

... elsewhere ...

__block BOOL hasFoundNonWhite = NO;

const int numberOfPixels = 128 * 128;
const int pixelsPerBatch = 128;
const int numberOfBatches = numberOfPixels / pixelsPerBatch;

dispatch_apply(numberOfBatches, 
               dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
               ^(size_t index) {

    if (hasFoundNonWhite) {
        return;
    }

    index *= pixelsPerBatch;
    for (int i = index; i < index + pixelsPerBack; i ++) {

        int indexToCheck = convolution(i);
        int arrayIndex = indexToCheck << 2;
        if (!(pixel[arrayIndex] == 255 && pixel[arrayIndex+1] == 255 && pixel[arrayIndex+2] == 255)) {
            hasFoundNonWhite = YES;
            return;
        }
    }
});

return !hasFoundNonWhite;

附录:在处理像这样的矢量处理任务时你要做的另一个下意识的事情是检查Accelerate框架,可能是vDSP。最终编译为使用CPU上的向量单元。在这种情况下,您可能将测试重新形成为“向量的总和必须等于向量的大小* 255”(如果您可以对alpha进行假设)。然而,没有积分和,转换为浮动可能不值得花费。