Open emmanuelperez opened 11 years ago
This bug affects me too when recording videos.
How do you set up your camera for image processing? How do you feed your images to the GPUImageView? If you are feeding directly from the camera into the view, are you setting the camera's outputImageOrientation to UIInterfaceOrientationPortrait?
I am feeding the images from the camera to GPUImageView directly without filters. This is the code:
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
_videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
[_videoCamera addTarget:_videoView];
same issue
Hi Brad,
I'm not using GPUImage to take photo, i've got my own classes to do that. This is the code to take the photo, where "orientation" value is AVCaptureVideoOrientationPortrait, and i send the image to save and to proceed on the call to [delegate performSelector:@selector(savePhoto:) withObject:image]
(void) captureStillImage { AVCaptureConnection *stillImageConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; if ([stillImageConnection isVideoOrientationSupported]) { [stillImageConnection setVideoOrientation:orientation]; }
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
ALAssetsLibraryWriteImageCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
if (error) {
if ([[self delegate] respondsToSelector:@selector(captureManager:didFailWithError:)]) {
[[self delegate] captureManager:self didFailWithError:error];
}
}
};
if (imageDataSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
UIImage *image = [[UIImage alloc] initWithData:imageData];
//EMP
self.m_pImageCaptured = image;
[delegate performSelector:@selector(savePhotos:)withObject:image];
[library writeImageToSavedPhotosAlbum:[image CGImage]
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:completionBlock];
[image release];
[library release];
}
else
completionBlock(nil, error);
if ([[self delegate] respondsToSelector:@selector(captureManagerStillImageCaptured:)]) {
[[self delegate] captureManagerStillImageCaptured:self];
}
}];
}
Thanks for your reply and best regards
Any news on this issue?
No, no more news from Brad. In fact, i use another function to fix orientation on Image taken from camera before process it. But the problem still be there with filter using lookup image as amatorka or missEtikate and don't know why with these filter even if the orientation is well configured, the result is rotate.
I found that using a sepia filter with intensity = 0
there is no recording rotation issue. When using GPUImage
without filters the whole tool doesn't work as intended. This should be fixed.
hi marzapower. Where can I set intensity= 0?
Do it like this:
filter = [[GPUImageSepiaFilter alloc] init];
filter.intensity = 0;
Hi marzapower, Thanks for reply quickly. But your solution was not work with me, the image is still rotated.
It's the issue of the conversion of the meta orientation and and UIImageOrientation
.
I have fixed it by updating the the orientation value in the meta data dictionary of the photo.
Referece: http://stackoverflow.com/questions/6699330/how-to-save-photo-with-exifgps-and-orientation-on-iphone
So I started diving in to GPUImage, specifically GPUImageStillCamera. I started simple, just creating a camera that can overlay a UIImage and capture it.
To set up the camera, my code looks a bit like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.stillCamera = [[GPUImageStillCamera alloc] init];
GPUImageAlphaBlendFilter *blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
blendFilter.mix = 1.0f;
// Create new filter to blend the camera + overlay
self.overlayImage = [UIImage imageNamed:@"overlay"];
self.overlayImagePicture = [[GPUImagePicture alloc] initWithImage:self.overlayImage smoothlyScaleOutput:YES];
[self.overlayImagePicture processImage];
// Add the camera to the filter
[self.stillCamera addTarget:blendFilter];
// Add the overlay to the filter
[self.overlayImagePicture addTarget:blendFilter];
// Add the filter to the view
GPUImageView *filterView = (GPUImageView *)self.view;
[blendFilter addTarget:filterView];
// Retain the overlay
self.overlay = blendFilter;
// Set the output orientation to the current orientation (doesn't work yet...)
UIInterfaceOrientation deviceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
self.stillCamera.outputImageOrientation = deviceOrientation;
[self.stillCamera startCameraCapture];
}
Pretty standard stuff. I added a button as well, and linked it up to an action that looks like this:
- (void)takePhoto:(id)sender {
[self.captureButton setEnabled:NO];
[self.stillCamera capturePhotoAsImageProcessedUpToFilter:self.overlay withCompletionHandler:^(UIImage *processedImage, NSError *error) {
[self.captureButton setEnabled:YES];
PhotoReviewViewController *vc = [[PhotoReviewViewController alloc] initWithImage:processedImage];
[self.navigationController pushViewController:vc animated:YES];
}];
}
The PhotoReviewViewController just displays the photo in a new view controller with a UIImageView. Nothing crazy.
Additionally, I'm responding to UIDeviceOrientationDidChangeNotification as such:
- (void)deviceOrientationDidChange:(NSNotification *)note {
UIInterfaceOrientation deviceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
self.stillCamera.outputImageOrientation = deviceOrientation;
}
The caveat here is my view controller (and app as a whole) is locked to landscape.
Expected: My PhotoReviewViewController
shows the image in the correct orientation.
Acutal: My PhotoReviewViewController
shows the image rotated 90° left/right, depending on which way I orient the device.
In diving deeper, I found that my procedure of setting outputImageOrientation
seemed okay, following the chain of calls through GPUImageVideoCamera
, specifically to updateOrientationSendToTargets
. The problem actually arised when hitting the capturePhotoAsImageProcessedUpToFilter:
method.
capturePhotoAsImageProcessedUpToFilter
calls a variety of methods, leading up to the juicy bit for me though, imageFromCurrentlyProcessedOutput
. This method grabs UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
, runs deviceOrientation
through a sensible switch, calculates the correct UIImageOrientation
, and calls imageFromCurrentlyProcessedOutputWithOrientation:
to move forward with grabbing the UIImage for me. All of this seems fine and dandy, except that my image was never in the right orientation! By just hard coding the switch to always return UIImageOrientationUp
for any deviceOrientation
, all is well.
I've tried by best to reason my way through this, but I can't. Any thoughts on removing imageWithCGImage:scale:orientation:
and going with imageWithCGImage:
instead?
Yeah, I was seeing this same behavior myself the other day, and I think it is localized to the default image rotation applied based on the accelerometer in that method. The way to solve this would probably be to maintain the camera metadata throughout the image capture and base things off of that.
@emmanuelperez : Can u please share the orientation fixing function. I have been wasting too much time on this and still couldnt fix it. Thanks
I am also ran into this problem which photo captured by GPUImageStillCamera been rotated 90 degree, still struggling with it. is anyone worked out some final solution?
Check out this Stack Overflow answer. So basically the iPhone camera's native mode is landscape. You will get orientation right if you take a portrait photo and retrieve the UIImage. UIImageView handles the rotation of the image for you when displayed, but GPUImageView does not do that.
What helped me after a little investigation was to load the picture either by Uri or File reference, so GPUImage can determine the rotation properly (at least on the Android port - I guess there is some similar mechanic for iPhone?)
// load either by File or other ContentResolver
// important for correct usage of detecting image rotation (File: ExifInterface; ContentResolver: MediaStore > ImageColumns)
if ("file".equals(uri.getScheme())) {
mGPUImageView.setImage(new File(uri.getPath()));
} else {
mGPUImageView.setImage(uri);
}
I also have the same issue Is there any way to do it in iPhone??.
First of all, I would like to thank Brad to let us use GPUImage, fantastic program.
I also have the same problem in my iPhone app that I am developing now. It seems difficult to improve it within GPUImage, but I found a way to rotate a saved image by 90° by using an edit function in iOS, which needs to ask user's operation.
The way is, go to photo library, select a saved image rotated by 90°, push "Edit" button to edit the image, you will find image rotation button at bottom left of the screen. This button makes an image rotated by 90° rotate back to the correct position.
This is not a smart way, but better than nothing to do. Please try it if acceptable.
(Solution at the end for the quickies)
To those who are still scratching head on this, if you are using UIImagePickerController when you:
The UIImage obtained has the right orientation, if you do a debug after obtaining the UIImage, check out the imageOrientation properties:
Portrait
Landscape
@drunkirishcoder is right, based on the information from his link:
http://stackoverflow.com/questions/13074161/uiimage-from-uiimagepickercontroller-orientation-issue
I was able to figure out why landscape photos look ok after going through filter(s). imageFromCurrentlyProcessedOutputWithOrientation is producing the right output, based on the current device orientation, it produces the image as per request, for video camera operations, this is fine because you are taking videos in the same orientation as the video images enter through the chain.
However, if the input is a still image (e.g. GPUImagePicture), the original orientation could be Landscape (UIImageOrientationUp), or Portrait (UIImageOrientationRight). GPUImagePicture probably load it correctly using the UIImageOrientation information, so your image looks "right". However, when it save the image back into a UIImage via any of the capture from frame function, it will "lost" the original orientation because you are likely holding the device in portrait orientation :-) (Which is UIImageOrientationUp). When you put it back out to a UIImageView, it will be....well you guessed 90° rotated!. Bottomline is the saved image orientation is NOT the same as your device orientation (default for camera is landscape).
Solution
Well, simple isn't it, just give it the right orientation again, we can do it in GPUImage but that would mean changing the code to crusade down the original image info, for now:
processedImage = [UIImage imageWithCGImage:[processedImage CGImage] scale:1.0 orientation:originalImage.imageOrientation];
This will give the processedImage the original orientation. I tested it out on my app it works. Would be embarrassing in production since in the iOS simulator somehow looks alright!
use @skyuplam 's solution, I solved this problem.
[self.stillCamera capturePhotoAsJPEGProcessedUpToFilter:self.currentFilter withCompletionHandler:^(NSData processedJPEG, NSError error){
// Save to assets library
ALAssetsLibrary *library = [ALAssetsLibrary new];
NSMutableDictionary* metadata = [NSMutableDictionary dictionaryWithDictionary:self.stillCamera.currentCaptureMetadata];
metadata[(__bridge NSString*)kCGImagePropertyOrientation] = @(UIImageOrientationUp);
[library writeImageDataToSavedPhotosAlbum:processedJPEG metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error2) {
if (error2) {
NSLog(@"ERROR: the image failed to be written");
} else {
NSLog(@"PHOTO SAVED - assetURL: %@", assetURL);
}
}];
}];
None of these solutions support GPUImageView. If I push a portrait image into GPUImageView, it comes out landscape. How to fix?
self.gpuImagePicture = [[GPUImagePicture alloc] initWithImage:myImage];
[self.gpuImagePicture addTarget:self.gpuImageView];
[self.gpuImagePicture processImage];
The solution by @zenvendof works great. Here is how I fixed it end-to-end:
// self.chosenImg is the image that you took, replace it with the appropriate image.
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:self.chosenImg];
GPUImageSepiaFilter *stillImageFilter = [[GPUImageSepiaFilter alloc] init];
[stillImageSource addTarget:stillImageFilter];
[stillImageFilter useNextFrameForImageCapture];
[stillImageSource processImage];
UIImage* processedImg = [stillImageFilter imageFromCurrentFramebuffer];
processedImg = [UIImage imageWithCGImage:[processedImg CGImage] scale:1.0 orientation:self.chosenImg.imageOrientation];
But ideally, GPUImage should preserve the original orientation. @BradLarson any thoughts?
The issue with the 90 degree rotation is that images taken by iOS are rotated 90 degrees. The JPEGs are rotated back when they are rendered. This is all done through the EXIF orientation tag.
Same issue i face when i capture video and filter . Video automatically rotate and display in 90 degree anti-clockwised. I also check below methods for that but nothing happen. if (orientation == UIInterfaceOrientationPortrait){ [filterRef setInputRotation:kGPUImageRotateRight atIndex:0]; } else if (orientation == UIInterfaceOrientationLandscapeRight) { [filterRef setInputRotation:kGPUImageRotate180 atIndex:0]; } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { [filterRef setInputRotation:kGPUImageRotateLeft atIndex:0]; }
@mediavrog :+1: Thanks. You saved my life =)) I'm finding this error for android app, surprise when i found that in a topic for IOS =)). Thanks again.
Wanted to add another +1 for @zenvendof solution. However wanted to add one thing. My app allows any orientation except upside down. I found I always need to reset the orientation to up
no matter which orientation the image was taken in:
stillImage = desaturationFilter.imageFromCurrentFramebuffer()
if let stillCG = stillImage?.cgImage {
stillImage = UIImage(cgImage: stillCG, scale: 1.0, orientation: UIImageOrientation.up)
}
Hi,
I'm using your framework to process image taken by camera. My application is in portrait mode only. After taken the photo and apply a filter on it, the image display on a GPUImageView is rotate by 90° I read some other post on this issue and can't find the solution. Thanks and regards