简体   繁体   中英

Converting Array of Pixel Brightness Values Back into UIImage?

A while ago I used the following method to extract an array of pixel brightness values from 32x32 sized images. I'd like to convert these values back into the 32x32 png images if possible (The images were black and white so the red green and blue values should be equal for each pixel).

Here is the original method I used:

- (NSArray *)arrayOfPixelBrightnessFromImage:(UIImage *)image {

    NSMutableArray *pixelBrightnesses = [[NSMutableArray alloc] init];

    CGImageRef inputCGImage = [image CGImage];
    NSUInteger width = CGImageGetWidth(inputCGImage);
    NSUInteger height = CGImageGetHeight(inputCGImage);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;

    UInt32 * pixels;
    pixels = (UInt32 *) calloc(height * width, sizeof(UInt32));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixels, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), inputCGImage);

    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);

    #define Mask8(x) ( (x) & 0xFF )
    #define R(x) ( Mask8(x) )
    #define G(x) ( Mask8(x >> 8 ) )
    #define B(x) ( Mask8(x >> 16) )

    UInt32 * currentPixel = pixels;
    for (NSUInteger j = 0; j < height; j++) {
        for (NSUInteger i = 0; i < width; i++) {
            UInt32 color = *currentPixel;
            [pixelBrightnesses addObject:@(((R(color)+G(color)+B(color))/3.0)/255.0)];
            currentPixel++;
        }
    }

    free(pixels);

    #undef R
    #undef G
    #undef B

    return pixelBrightnesses;
}

I'm not really an expert with Core Graphics, but if anyone could help me that would be amazing.

PS Here's an example of the NSArray containing the pixel brightness values (There should be 1024 items [32 x 32]):

@[@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.8588235294117647,@0.8784313725490196,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.8862745098039215,@0.3176470588235294,@0.2588235294117647,@0.592156862745098,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.8235294117647058,@0.1882352941176471,@0.5843137254901961,@0.9803921568627451,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.7529411764705882,@0.1725490196078431,@0.6862745098039216,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.5725490196078431,@0.1843137254901961,@0.7607843137254902,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.8588235294117647,@0.3176470588235294,@0.3137254901960784,@0.8862745098039215,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.984313725490196,@0.5607843137254902,@0.196078431372549,@0.592156862745098,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.7686274509803922,@0.2666666666666667,@0.3568627450980392,@0.8745098039215686,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9176470588235294,@0.4274509803921568,@0.2274509803921569,@0.6901960784313725,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.7294117647058823,@0.2235294117647059,@0.4941176470588236,@0.9529411764705882,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9647058823529412,@0.1294117647058824,@0.5803921568627451,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9921568627450981,@0.615686274509804,@0.2901960784313726,@0.2745098039215687,@0.4509803921568628,@0.7058823529411765,@0.9098039215686274,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9921568627450981,@0.8313725490196079,@0.5882352941176471,@0.3529411764705883,@0.2509803921568627,@0.3058823529411765,@0.4549019607843137,@0.6470588235294118,@0.8274509803921568,@0.9568627450980393,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9450980392156862,@0.792156862745098,@0.6,@0.4117647058823529,@0.2862745098039216,@0.2549019607843137,@0.3294117647058823,@0.4666666666666667,@0.6313725490196078,@0.8470588235294118,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9098039215686274,@0.7607843137254902,@0.615686274509804,@0.4549019607843137,@0.1803921568627451,@0.3098039215686275,@0.9686274509803922,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.792156862745098,@0.4313725490196079,@0.2313725490196079,@0.4823529411764706,@0.9803921568627451,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9058823529411765,@0.592156862745098,@0.2862745098039216,@0.2901960784313726,@0.6235294117647059,@0.9333333333333333,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9529411764705882,@0.7058823529411765,@0.3843137254901961,@0.2392156862745098,@0.4196078431372549,@0.7725490196078432,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9607843137254902,@0.7333333333333333,@0.4313725490196079,@0.2470588235294118,@0.3372549019607843,@0.6431372549019608,@0.9254901960784314,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9725490196078431,@0.7450980392156863,@0.4392156862745098,@0.2509803921568627,@0.3215686274509804,@0.596078431372549,@0.8784313725490196,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.8196078431372549,@0.4862745098039216,@0.2588235294117647,@0.3137254901960784,@0.5882352941176471,@0.8705882352941177,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9215686274509803,@0.6352941176470588,@0.3176470588235294,@0.2627450980392157,@0.5254901960784314,@0.8470588235294118,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9333333333333333,@0.6784313725490196,@0.3803921568627451,@0.2431372549019608,@0.3882352941176471,@0.7254901960784313,@0.9764705882352941,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9882352941176471,@0.7450980392156863,@0.4117647058823529,@0.2431372549019608,@0.3607843137254902,@0.6549019607843137,@0.9176470588235294,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9333333333333333,@0.5882352941176471,@0.2705882352941176,@0.3058823529411765,@0.611764705882353,@0.9019607843137255,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.996078431372549,@0.6470588235294118,@0.2235294117647059,@0.407843137254902,@0.788235294117647,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9215686274509803,@0.203921568627451,@0.8156862745098039,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@0.9882352941176471,@0.9058823529411765,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1,@1];

In much the same way.

You'll just (basically) want to do the reverse.

So you'll want to create a new bitmap context, iterate through each pixel, and populate each pixel with the brightness value from your array (with the RGB components all set to that value).

Something like this should do the trick:

static inline UInt32 colorFromComponents(UInt8* components) {

    UInt32 color = 0;

    // iterate through components
    for (int i = 0; i < 4; i++) {

        // shift component by its position
        UInt32 component = (UInt32)components[i] << i*8;

        // add the component to the color
        color += component;
    }

    return color;
}

...

-(UIImage*) grayscaleImageFromPixelBrightnesses:(NSArray*)brightnesses width:(size_t)width height:(size_t)height bitmapInfo:(CGBitmapInfo)bitmapInfo {

    // check that the brightness array has the correct count
    if (width*height != brightnesses.count) {
        NSLog(@"Pixel brightness array has an incorrect count!");
        return nil;
    }

    // create your data
    UInt32* data = calloc(width*height, sizeof(UInt32));

    // create a new RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // define your attributes
    size_t bytesPerPixel = 4;
    size_t bitsPerComponent = 8;
    size_t bytesPerRow = bytesPerPixel*width;

    // create bitmap context
    CGContextRef context = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);

    // iterate through each pixel
    for (NSUInteger i = 0; i < width*height; i++) {

        // get the brightness value from the brightness array. round is used due to potential rounding errors from the doubles.
        UInt8 brightnessValue = (UInt8)round([(NSNumber*)brightnesses[i] doubleValue]*255.0);

        // your color components to write to the pixel
        UInt8 components[4] = {brightnessValue, brightnessValue, brightnessValue, 255};

        // write components to pixel
        data[i] = colorFromComponents(components);
    }

    // create image from context
    CGImageRef img = CGBitmapContextCreateImage(context);

    // release data
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(data);

    // get return image and release CGImage
    UIImage* returnImage = [UIImage imageWithCGImage:img];
    CGImageRelease(img);

    // return image
    return returnImage;
}

Macro Rant...

You should also get rid of the macros in your existing code. They are absolutely horrible and should never be used instead of a function. They aren't type safe and can make debugging an absolute nightmare. Avoid them like the plague.

I would suggest you replace your macros with an enum and a function like so:

enum colorComponent {
    redComponent = 0,
    greenComponent = 8,
    blueComponent = 16,
    alphaComponent = 24
};

typedef enum colorComponent colorComponent;

static inline UInt8 getColorComponent(UInt32 color, colorComponent component) {
    return (color >> component) & 0xFF;
}

You could then use it like this:

UInt32 * currentPixel = pixels;
for (NSUInteger j = 0; j < height; j++) {
    for (NSUInteger i = 0; i < width; i++) {
        UInt32 color = *currentPixel;
        [pixelBrightnesses addObject:@(((getColorComponent(color, redComponent)+getColorComponent(color, greenComponent)+getColorComponent(color, blueComponent))/3.0)/255.0)];
        currentPixel++;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM