Подтвердить что ты не робот

Luma Key (создать альфа-маску из изображения) для iOS

Я создаю приложение, которое позволяет людям загружать изображение себя на белом фоне, и приложение создаст силуэт человека.

Мне сложно найти фона. Я использую рамки GPUImage, а GPUImageChromaKeyBlendFilter отлично подходит для цветов, но если вы добираетесь до белого/черного, очень сложно выделить один из этих цветов. Если я установил ключ в белый или черный, он будет одинаковым.

Любые советы?

4b9b3361

Ответ 1

Существует причина, по которой типичные синие или зеленые экраны используются в производстве фильмов для обработки цветности, вместо белого. Все может быть белым или достаточно близко к белому на фотографии, особенно глаза или блики или только части кожи. Кроме того, довольно сложно найти сплошную белую стену без теней, на которую, по крайней мере, наносится ваш предмет. Я бы рекомендовал построить гистограмму, найдя наиболее часто используемый цвет среди самых ярких, а затем поиск самой большой области этого цвета с использованием определенного порога. Затем заливайте заливку из этой области до тех пор, пока не будут встречены достаточно разные цвета. Все это можно легко сделать в программном обеспечении, если вы не хотите видеопотока в реальном времени.

Ответ 2

Итак, чтобы изменить белый на прозрачный, мы можем использовать этот метод:

-(UIImage *)changeWhiteColorTransparent: (UIImage *)image {
    CGImageRef rawImageRef=image.CGImage;

    const float colorMasking[6] = {222, 255, 222, 255, 222, 255};

    UIGraphicsBeginImageContext(image.size);
    CGImageRef maskedImageRef=CGImageCreateWithMaskingColors(rawImageRef, colorMasking);
    {
        //if in iphone
        CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0.0, image.size.height);
        CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0); 
    }

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, image.size.width, image.size.height), maskedImageRef);
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    CGImageRelease(maskedImageRef);
    UIGraphicsEndImageContext();    
    return result;
}

и для замены непрозрачных пикселей на черный, мы можем использовать:

- (UIImage *) changeColor: (UIImage *)image {
    UIGraphicsBeginImageContext(image.size);

    CGRect contextRect;
    contextRect.origin.x = 0.0f;
    contextRect.origin.y = 0.0f;
    contextRect.size = [image size];
    // Retrieve source image and begin image context
    CGSize itemImageSize = [image size];
    CGPoint itemImagePosition;
    itemImagePosition.x = ceilf((contextRect.size.width - itemImageSize.width) / 2);
    itemImagePosition.y = ceilf((contextRect.size.height - itemImageSize.height) );

    UIGraphicsBeginImageContext(contextRect.size);

    CGContextRef c = UIGraphicsGetCurrentContext();
    // Setup shadow
    // Setup transparency layer and clip to mask
    CGContextBeginTransparencyLayer(c, NULL);
    CGContextScaleCTM(c, 1.0, -1.0);
    CGContextClipToMask(c, CGRectMake(itemImagePosition.x, -itemImagePosition.y, itemImageSize.width, -itemImageSize.height), [image CGImage]);

    CGContextSetFillColorWithColor(c, [UIColor blackColor].CGColor);


    contextRect.size.height = -contextRect.size.height;
    contextRect.size.height -= 15;
    // Fill and end the transparency layer
    CGContextFillRect(c, contextRect);
    CGContextEndTransparencyLayer(c);

    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}

поэтому на практике это будет:

-(UIImage *)silhouetteForImage:(UIImage *)img {
    return [self changeColour:[self changeWhiteColorTransparent:img]];
}

Очевидно, вы бы назвали это в фоновом потоке, чтобы все работало плавно.

Ответ 3

Игра с композитором Quartz и фильтрами CoreImage может вам помочь. Я считаю, что этот код должен сделать вам силуэт:

- (CGImageRef)silhouetteOfImage:(UIImage *)input
{
  CIContext *ciContext = [CIContext contextWithOptions:nil];
  CIImage *ciInput = [CIImage imageWithCGImage:[input CGImage]];
  CIFilter *filter = [CIFilter filterWithName:@"CIFalseColor"];
  [filter setValue:[CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0] forKey:@"inputColor0"];
  [filter setValue:[CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0] [email protected]"inputColor1"];
  [filter setValue:ciInput forKey:kCIInputImageKey];
  CIImage *outImage = [filter valueForKey:kCIOutputImageKey];
  CGImageRef result = [ciContext createCGImage:outImage fromRect:[ciInput extent]];
  return result;
}

Ответ 4

Иногда разъяснение того, чего вы пытаетесь достичь, а затем понимание различий может помочь. Вы говорите о том, что я собираю прозрачность и прозрачность.

Прозрачность учитывает альфа, позволяя смешивать фон с передним планом на основе значения альфа для пикселей изображения и вида оценки, выполняемой в фоновом буфере.

Прозрачность позволяет "замаскировать" изображение на участках с жесткой альфой и порогом и позволяет фон просматриваться через маску без смешивания. Пороговое значение позволяет ограничить смешивание на основе значения альфа до порога.

Chromokeying похож на прозрачность, поскольку позволяет вам устанавливать жестко закодированный цвет в качестве цвета маски (или альфа-порога для смешанной клавиатуры), что позволяет видеть фон через части переднего плана, которые обладают этим цветом.

Если ваш формат изображения поддерживает тип данных или pixelformat для альфа-значений, довольно просто вычислить:

Альфа на основе светимости = (R + G + B)/3;

Альфа на основе допущения канала = Макс (R, G, B);

Смешанная прозрачность с альфа-порогом 127 означает, что каждый пиксель, который прошел альфа-тест со значением 127 или ниже, будет смешан, а те, что выше 127, будут жестко маскироваться.

Я надеюсь, что это поможет прояснить немного, на случай, если это не ясно. Удивительные кодовые парни.