質問

I am working on a project that requires image pixel manipulation. What I am doing now is using UIImagePicker to receive a UIImage from the devices library. I then convert it to a CGImage, get the RBG values and change them slightly.

I then convert it back to a UIImage and write it out to disk. The issue is when I read the image back in, from the UIImagePicker, the RBG values are not the same. I have verified that the values are correct after I change them and before the image is actually written out. The pixel values only are different when I read it back in and then only by a few values. I am curious, why is this happening and are there any ways around this? I want to get back the exact same RBG values.

Here is a bit of code, if you want something specific please let me know.

- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {

    // I only ever manipulate self.editingImage which is directly read from the photo library
    // self.editingImage is a UIImage property
    self.editingImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
    self.imageView.image = self.editingImage;

    if (self.option == EDITPIXELS) {
        // After this method completes it automatically calls READPIXELS and the values are correct
        // converts self.editingImage to a CGImage before editing pixels
        [self editImage:self.editingImage];
    } else if (self.option == READPIXELS) {
        // converts self.editingImage to a CGImage before reading pixels, then logs RBG values
        [self readImage:self.editingImage];
    }

    [self.imagePickerPopoverController dismissPopoverAnimated:YES];
}

Edit: I am using the category from here to save my image, the code from the category:

-(void)saveImage:(UIImage*)image toAlbum:(NSString*)albumName withCompletionBlock:(SaveImageCompletion)completionBlock {

    //write the image data to the assets library (camera roll)
    [self writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation 
                       completionBlock:^(NSURL* assetURL, NSError* error) {

                      //error handling
                      if (error!=nil) {
                          completionBlock(error);
                          return;
                      }
                      //add the asset to the custom photo album
                      [self addAssetURL: assetURL 
                                toAlbum:albumName 
                    withCompletionBlock:completionBlock];
                  }];
}

I am calling it on an action button:

- (IBAction)saveImage:(id)sender {
    // Called before saving to verify the RBG values, they are correct
    [self readImage:self.editingImage];

    // saving image
    [self.library saveImage:self.editingImage toAlbum:@"My Album" withCompletionBlock:^(NSError *error){}];
}

This is the code I am using to edit the RBG values:

+ (UIImage *) fromImage:(UIImage *)source toRedColors:(NSArray *)redColorArray {

    // Code adapted from: http://brandontreb.com/image-manipulation-retrieving-and-updating-pixel-values-for-a-uiimage/
    CGContextRef ctx;
    CGImageRef imageRef = [source CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    byte *rawData = malloc(height * width * 4);
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, 
                                     bitsPerComponent, bytesPerRow, colorSpace, 
                                     kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    int byteIndex = 0;

    for (NSNumber *n in redColorArray) {
        rawData[byteIndex] = Clamp255([n integerValue]);
        byteIndex += 4;
    }
    ctx = CGBitmapContextCreate(rawData,
                            CGImageGetWidth( imageRef ),
                            CGImageGetHeight( imageRef ),
                            8,
                            bytesPerRow,
                            colorSpace,
                            kCGImageAlphaPremultipliedLast );
    CGColorSpaceRelease(colorSpace);
    imageRef = CGBitmapContextCreateImage (ctx);
    UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGContextRelease(ctx);
    free(rawData);

    return rawImage;
}

Reading the values is using almost the exact same code except I store the values into an array and just return the array of RBG values (I do not return all of the RBG values just some of them). So instead of:

rawData[byteIndex] = Clamp255([n integerValue]);

I use:

[myMutableArray addObject:@(rawData[byteIndex])];
役に立ちましたか?

解決

Using the imagePickerController the imagedata is compressed into a jpg and that alone changes the data.

When you want to do some serious image manipulation you will need to use AVFoundation. The AVCam project in the documentation provides sample code you can use as a reference. The problem with iOS is that it only provides jpg and png as possibilities to save your data as a picture as far as I know.

For my application I use the OpenCV library to save the image data as a BMP on the phone. In this post you can see my solution. Also there you can see a link to a description of the "645 PRO" app. Those programmers faced the same problem and describe in general how their app works around it.

If you just need to save your data for a while to use it in your app again you could try saving the image data in a NSData object and write it on your phone.

Capture still UIImage without compression (from CMSampleBufferRef)? provides more insight to that matter. OpenCV imread() returns no image data on iOS.

When you search on stackoverflow you can find more posts like that. Those are just the ones I was involved.

他のヒント

You need to save the image to your library you are only modifing it in your app. Try this After you have the image try saving it to photo library add this line of code:

UIImageWriteToSavedPhotosAlbum(rawImage, self, @selector(image:didFinishSavingWithError:contextInfo:), self);

and to confirm the save add this method:

    - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{

        NSString *str = @"Saved!!!";

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Saved." message:str delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];

        [alert show];

    }

EDIT: I didn't see the full code For the save process, my mistake sorry. The code looks ok it should save the image can you check the RGB code for the image just before you save it? it might not be saving the correct image or it might be reset. other then that i can't see to find a fault

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top