Thursday, August 15, 2013

How to convert a UIImage to Grayscale?



Please do follow this post along with the post here

Note that I have already shown you the coding on how to pick an image from the UIImagePickerViewController and display it in the UIImageView we have in the screen. So, I assume you have already assigned the selected image's value using imageDisplay.image to the sourceImage variable. 

OK, let's discuss the code to convert an image to Grayscale and display the output.

//this button click even twill call the toGrayscale() method 
-(IBAction) convertGrayScale:(id)sender
{    
    if(sourceImage==nil)//sourceImage  is the user selected image from the Image Picker. I simply display it on a UIImageView and for the processing  i get the image that is currently viewed in the UIImageView
    {
        NSLog(@"Image Not selected");
    }
    
    else
    {   
        UIImage *greyScaledImage=[self toGrayscale:sourceImage];
        resultImageView.image=greyScaledImage;
    } 
}

//method is used to convert an image to its grayscale image and view in the UIImageView on te screen
- (UIImage *) toGrayscale:(UIImage *)initialImage
{
    const int RED = 1;
    const int GREEN = 2;
    const int BLUE = 3;
    
    // Create image rectangle with current image width/height
    CGRect imageRect = CGRectMake(0, 0, initialImage.size.width * initialImage.scale, initialImage.size.height * initialImage.scale);
    
    int width = imageRect.size.width;
    int height = imageRect.size.height;
    
    // the pixels will be painted to this array
    uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
    
    // clear the pixels so any transparency is preserved
    memset(pixels, 0, width * height * sizeof(uint32_t));
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // create a context with RGBA pixels
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, 
                                                 kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    
    // paint the bitmap to our context which will fill in the pixels array
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [initialImage CGImage]);
    
    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width; x++)
        {
            uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x];
            
            //convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
            
            uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE];
            
            // set the pixels to gray
            rgbaPixel[RED] = gray;
            rgbaPixel[GREEN] = gray;
            rgbaPixel[BLUE] = gray;
        }
    }
    
    // create a new CGImageRef from our context with the modified pixels
    CGImageRef image = CGBitmapContextCreateImage(context);
    
    // we're done with the context, color space, and pixels
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(pixels);
    
    // make a new UIImage to return
    UIImage *resultUIImage = [UIImage imageWithCGImage:image
                                                 scale:initialImage.scale 
                                           orientation:UIImageOrientationUp];
    
    return resultUIImage;
}