2016-08-07 94 views
0

So habe ich viele JPG-Bilder mit weißem Hintergrund, die ich in meine App laden, und ich möchte die weißen Hintergründe programmgesteuert entfernen. Ich habe eine Funktion, die das tut, aber es verursacht einige gezackte Ränder um jedes Bild. Gibt es eine Möglichkeit, diese Kanten zu mischen, um glatte Kanten zu erzielen?Ziel C: Wie man einen weißen Hintergrund aus einem JPG-Bild entfernt, ohne Kantenqualität zu verlieren

Meine aktuelle Methode:

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

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

    UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale); 
    CGImageRef maskedImageRef=CGImageCreateWithMaskingColors(rawImageRef, colorMasking); 

    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; 
} 

Ich weiß, dass ich die Farbe Maskierungswert ändern kann, aber ich glaube nicht, jede Kombination ein glattes Bild ohne weißen Hintergrund produzieren.

Heres ein Beispiel:

Diese Methode entfernt auch zusätzliche Pixel innerhalb der Bilder, die auf weißen Nähe sind:

enter image description here

Ich denke, die ideale Methode, um die Alpha ändern würde von weißen Pixeln, je nachdem, wie nahe an reinem Weiß sie sind, anstatt sie alle nur zu entfernen. Irgendwelche Ideen würden geschätzt werden.

+2

wird, um den Beispielcode herunterladen genannt. Es kann einfacher sein, einen Kernel-Verarbeitungsalgorithmus zu verwenden als pro Pixel-Berechnungen. Die Dokumentation zu CIFilter enthält ein [Beispiel] (https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_filer_recipes/ci_filter_recipes.html). GPUImage hat auch Beispiele. –

Antwort

2

#import "UIImage+FloodFill.h" 
 
//https://github.com/Chintan-Dave/UIImageScanlineFloodfill 
 

 
#define Mask8(x) ((x) & 0xFF) 
 
#define R(x) (Mask8(x)) 
 
#define G(x) (Mask8(x >> 8)) 
 
#define B(x) (Mask8(x >> 16)) 
 
#define A(x) (Mask8(x >> 24)) 
 
#define RGBAMake(r, g, b, a) (Mask8(r) | Mask8(g) << 8 | Mask8(b) << 16 | Mask8(a) << 24) 
 

 
@interface UIImage (BackgroundRemoval) 
 
//Simple Removal 
 
- (UIImage *)floodFillRemoveBackgroundColor; 
 
@end 
 

 
@implementation UIImage (BackgroundRemoval) 
 
- (UIImage*) maskImageWithMask:(UIImage *)maskImage { 
 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
 

 
    CGImageRef maskImageRef = [maskImage CGImage]; 
 

 
    // create a bitmap graphics context the size of the image 
 
    CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast); 
 
    CGColorSpaceRelease(colorSpace); 
 

 
    if (mainViewContentContext==NULL) 
 
    return NULL; 
 

 
    CGFloat ratio = 0; 
 

 
    ratio = maskImage.size.width/ self.size.width; 
 

 
    if(ratio * self.size.height < maskImage.size.height) { 
 
    ratio = maskImage.size.height/ self.size.height; 
 
    } 
 

 
    CGRect rect1 = { {0, 0}, {maskImage.size.width, maskImage.size.height} }; 
 
    CGRect rect2 = { {-((self.size.width*ratio)-maskImage.size.width)/2 , -((self.size.height*ratio)-maskImage.size.height)/2}, {self.size.width*ratio, self.size.height*ratio} }; 
 

 

 
    CGContextClipToMask(mainViewContentContext, rect1, maskImageRef); 
 
    CGContextDrawImage(mainViewContentContext, rect2, self.CGImage); 
 

 

 
    // Create CGImageRef of the main view bitmap content, and then 
 
    // release that bitmap context 
 
    CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext); 
 
    CGContextRelease(mainViewContentContext); 
 

 
    UIImage *theImage = [UIImage imageWithCGImage:newImage]; 
 

 
    CGImageRelease(newImage); 
 

 
    // return the image 
 
    return theImage; 
 
} 
 

 
- (UIImage *)floodFillRemove{ 
 
    //1 
 
    UIImage *processedImage = [self floodFillFromPoint:CGPointMake(0, 0) withColor:[UIColor magentaColor] andTolerance:0]; 
 

 
    CGImageRef inputCGImage=processedImage.CGImage; 
 
    UInt32 * inputPixels; 
 
    NSUInteger inputWidth = CGImageGetWidth(inputCGImage); 
 
    NSUInteger inputHeight = CGImageGetHeight(inputCGImage); 
 

 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
 

 
    NSUInteger bytesPerPixel = 4; 
 
    NSUInteger bitsPerComponent = 8; 
 

 
    NSUInteger inputBytesPerRow = bytesPerPixel * inputWidth; 
 

 
    inputPixels = (UInt32 *)calloc(inputHeight * inputWidth, sizeof(UInt32)); 
 

 
    CGContextRef context = CGBitmapContextCreate(inputPixels, inputWidth, inputHeight, bitsPerComponent, inputBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
 

 
    CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage); 
 

 
    //2 
 

 
    for (NSUInteger j = 0; j < inputHeight; j++) { 
 
    for (NSUInteger i = 0; i < inputWidth; i++) { 
 
     UInt32 * currentPixel = inputPixels + (j * inputWidth) + i; 
 
     UInt32 color = *currentPixel; 
 

 
     if (R(color) == 255 && G(color) == 0 && B(color) == 255) { 
 
     *currentPixel = RGBAMake(0, 0, 0, A(0)); 
 
     }else{ 
 
      *currentPixel = RGBAMake(R(color), G(color), B(color), A(color)); 
 
     } 
 
     } 
 
    } 
 
    CGImageRef newCGImage = CGBitmapContextCreateImage(context); 
 

 
    //3 
 

 
    UIImage * maskImage = [UIImage imageWithCGImage:newCGImage]; 
 
    CGColorSpaceRelease(colorSpace); 
 
    CGContextRelease(context); 
 
    free(inputPixels); 
 

 
    UIImage *result = [self maskImageWithMask:maskImage]; 
 

 
    //4 
 

 
    return result; 
 
} 
 

 
@end

was, wenn Ihr Bild mit Farbverlauf Hintergrund? Verwenden Sie den folgenden Code.

- (UIImage *)complexReoveBackground{ 
 

 
    GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:self]; 
 

 
    GPUImagePrewittEdgeDetectionFilter *filter = [[GPUImagePrewittEdgeDetectionFilter alloc] init]; 
 
    [filter setEdgeStrength:0.04]; 
 

 
    [stillImageSource addTarget:filter]; 
 
    [filter useNextFrameForImageCapture]; 
 
    [stillImageSource processImage]; 
 

 
    UIImage *resultImage = [filter imageFromCurrentFramebuffer]; 
 

 
    UIImage *processedImage = [resultImage floodFillFromPoint:CGPointMake(0, 0) withColor:[UIColor magentaColor] andTolerance:0]; 
 

 
    CGImageRef inputCGImage=processedImage.CGImage; 
 
    UInt32 * inputPixels; 
 
    NSUInteger inputWidth = CGImageGetWidth(inputCGImage); 
 
    NSUInteger inputHeight = CGImageGetHeight(inputCGImage); 
 

 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
 

 
    NSUInteger bytesPerPixel = 4; 
 
    NSUInteger bitsPerComponent = 8; 
 

 
    NSUInteger inputBytesPerRow = bytesPerPixel * inputWidth; 
 

 
    inputPixels = (UInt32 *)calloc(inputHeight * inputWidth, sizeof(UInt32)); 
 

 
    CGContextRef context = CGBitmapContextCreate(inputPixels, inputWidth, inputHeight, bitsPerComponent, inputBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
 

 
    CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage); 
 

 
    for (NSUInteger j = 0; j < inputHeight; j++) { 
 
    for (NSUInteger i = 0; i < inputWidth; i++) { 
 
     UInt32 * currentPixel = inputPixels + (j * inputWidth) + i; 
 
     UInt32 color = *currentPixel; 
 

 
     if (R(color) == 255 && G(color) == 0 && B(color) == 255) { 
 
     *currentPixel = RGBAMake(0, 0, 0, A(0)); 
 
     }else{ 
 
     *currentPixel = RGBAMake(0, 0, 0, 255); 
 
     } 
 
    } 
 
    } 
 
    CGImageRef newCGImage = CGBitmapContextCreateImage(context); 
 
    UIImage * maskImage = [UIImage imageWithCGImage:newCGImage]; 
 
    CGColorSpaceRelease(colorSpace); 
 
    CGContextRelease(context); 
 
    free(inputPixels); 
 

 
    GPUImagePicture *maskImageSource = [[GPUImagePicture alloc] initWithImage:maskImage]; 
 

 
    GPUImageGaussianBlurFilter *blurFilter = [[GPUImageGaussianBlurFilter alloc] init]; 
 
    [blurFilter setBlurRadiusInPixels:0.7]; 
 
    [maskImageSource addTarget:blurFilter]; 
 
    [blurFilter useNextFrameForImageCapture]; 
 
    [maskImageSource processImage]; 
 

 
    UIImage *blurMaskImage = [blurFilter imageFromCurrentFramebuffer]; 
 
    //return blurMaskImage; 
 
    UIImage *result = [self maskImageWithMask:blurMaskImage]; 
 

 
    return result; 
 
}

Sie können Chroma Key Compositing von hier sample code

+0

Ich weiß, das ist spät, aber danke! Die Verwendung des ersten Code-Snippets funktionierte nach dem Spielen mit der Flood-Toleranz großartig und fügte zusätzlichen Code hinzu, um die überschüssige Magenta-Färbung zu entfernen. – Chris

+3

Der richtige Link zum Beispiel [hier] (https://github.com/darkcl/Background-Removal-Example) –