iphonecocoa-touchcgimage

Convert image to grayscale


I am trying to convert an image into grayscale in the following way:

#define bytesPerPixel 4
#define bitsPerComponent 8

-(unsigned char*) getBytesForImage: (UIImage*)pImage
{
    CGImageRef image = [pImage CGImage];
    NSUInteger width = CGImageGetWidth(image);
    NSUInteger height = CGImageGetHeight(image);

    NSUInteger bytesPerRow = bytesPerPixel * width;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = malloc(height * width * 4);
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
    CGContextRelease(context);

    return rawData;
}

-(UIImage*) processImage: (UIImage*)pImage
{   
    DebugLog(@"processing image");
    unsigned char *rawData = [self getBytesForImage: pImage];

    NSUInteger width = pImage.size.width;
    NSUInteger height = pImage.size.height;

    DebugLog(@"width: %d", width);
    DebugLog(@"height: %d", height);

    NSUInteger bytesPerRow = bytesPerPixel * width;

    for (int xCoordinate = 0; xCoordinate < width; xCoordinate++)
    {
        for (int yCoordinate = 0; yCoordinate < height; yCoordinate++)
        {
            int byteIndex = (bytesPerRow * yCoordinate) + xCoordinate * bytesPerPixel;

            //Getting original colors
            float red = ( rawData[byteIndex] / 255.f );
            float green = ( rawData[byteIndex + 1] / 255.f );
            float blue = ( rawData[byteIndex + 2] / 255.f );

            //Processing pixel data
            float averageColor = (red + green + blue) / 3.0f;

            red = averageColor;
            green = averageColor;
            blue = averageColor;

            //Assigning new color components
            rawData[byteIndex] = (unsigned char) red * 255;
            rawData[byteIndex + 1] = (unsigned char) green * 255;
            rawData[byteIndex + 2] = (unsigned char) blue * 255;


        }
    }

    NSData* newPixelData = [NSData dataWithBytes: rawData length: height * width * 4];
    UIImage* newImage = [UIImage imageWithData: newPixelData];

    free(rawData);

    DebugLog(@"image processed");

    return newImage;

}

So when I want to convert an image I just call processImage:

imageToDisplay.image = [self processImage: image];

But imageToDisplay doesn't display. What may be the problem?

Thanks.


Solution

  • What exactly takes place when you use this function? Is the function returning an invalid image, or is the display not showing it correctly?

    This is the method I use to convert to greyscale.

    - (UIImage *) convertToGreyscale:(UIImage *)i {
    
        int kRed = 1;
        int kGreen = 2;
        int kBlue = 4;
    
        int colors = kGreen | kBlue | kRed;
        int m_width = i.size.width;
        int m_height = i.size.height;
    
        uint32_t *rgbImage = (uint32_t *) malloc(m_width * m_height * sizeof(uint32_t));
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(rgbImage, m_width, m_height, 8, m_width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
        CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
        CGContextSetShouldAntialias(context, NO);
        CGContextDrawImage(context, CGRectMake(0, 0, m_width, m_height), [i CGImage]);
        CGContextRelease(context);
        CGColorSpaceRelease(colorSpace);
    
        // now convert to grayscale
        uint8_t *m_imageData = (uint8_t *) malloc(m_width * m_height);
        for(int y = 0; y < m_height; y++) {
            for(int x = 0; x < m_width; x++) {
                uint32_t rgbPixel=rgbImage[y*m_width+x];
                uint32_t sum=0,count=0;
                if (colors & kRed) {sum += (rgbPixel>>24)&255; count++;}
                if (colors & kGreen) {sum += (rgbPixel>>16)&255; count++;}
                if (colors & kBlue) {sum += (rgbPixel>>8)&255; count++;}
                m_imageData[y*m_width+x]=sum/count;
            }
        }
        free(rgbImage);
    
        // convert from a gray scale image back into a UIImage
        uint8_t *result = (uint8_t *) calloc(m_width * m_height *sizeof(uint32_t), 1);
    
        // process the image back to rgb
        for(int i = 0; i < m_height * m_width; i++) {
            result[i*4]=0;
            int val=m_imageData[i];
            result[i*4+1]=val;
            result[i*4+2]=val;
            result[i*4+3]=val;
        }
    
        // create a UIImage
        colorSpace = CGColorSpaceCreateDeviceRGB();
        context = CGBitmapContextCreate(result, m_width, m_height, 8, m_width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
        CGImageRef image = CGBitmapContextCreateImage(context);
        CGContextRelease(context);
        CGColorSpaceRelease(colorSpace);
        UIImage *resultUIImage = [UIImage imageWithCGImage:image];
        CGImageRelease(image);
    
        free(m_imageData);
    
        // make sure the data will be released by giving it to an autoreleased NSData
        [NSData dataWithBytesNoCopy:result length:m_width * m_height];
    
        return resultUIImage;
    }