Iphone 为什么AVCaptureVideoOrientation横向模式会产生倒置的静止图像?
我正在使用AVFoundation类在我的应用程序中实现自定义相机。我只拍摄静止图像,而不是视频。我什么都做得很好,但有什么事难倒了我。在拍摄静止图像时,我会考虑设备方向,并适当设置视频连接的视频方向。代码片段:Iphone 为什么AVCaptureVideoOrientation横向模式会产生倒置的静止图像?,iphone,ios,avcapturesession,image-capture,avcapturedevice,Iphone,Ios,Avcapturesession,Image Capture,Avcapturedevice,我正在使用AVFoundation类在我的应用程序中实现自定义相机。我只拍摄静止图像,而不是视频。我什么都做得很好,但有什么事难倒了我。在拍摄静止图像时,我会考虑设备方向,并适当设置视频连接的视频方向。代码片段: // set the videoOrientation based on the device orientation to // ensure the pic is right side up for all orientations AVCaptureVid
// set the videoOrientation based on the device orientation to
// ensure the pic is right side up for all orientations
AVCaptureVideoOrientation videoOrientation;
switch ([UIDevice currentDevice].orientation) {
case UIDeviceOrientationLandscapeLeft:
// Not clear why but the landscape orientations are reversed
// if I use AVCaptureVideoOrientationLandscapeLeft here the pic ends up upside down
videoOrientation = AVCaptureVideoOrientationLandscapeRight;
break;
case UIDeviceOrientationLandscapeRight:
// Not clear why but the landscape orientations are reversed
// if I use AVCaptureVideoOrientationLandscapeRight here the pic ends up upside down
videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
break;
case UIDeviceOrientationPortraitUpsideDown:
videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
break;
default:
videoOrientation = AVCaptureVideoOrientationPortrait;
break;
}
videoConnection.videoOrientation = videoOrientation;
请注意我在景观案例中的评论。我必须反转方向贴图,否则生成的图像是颠倒的。我使用以下代码捕获并保存图像:
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
self.stillImage = [UIImage imageWithData:imageData];
// notify observers (image gets saved to the camera roll)
[[NSNotificationCenter defaultCenter] postNotificationName:CaptureSessionManagerDidCaptureStillImageNotification object:self];
self.stillImage = nil;
}];
没有其他的图像处理或操作
我的应用程序使用上述代码。我只是想弄明白为什么横向的方向常数必须颠倒。谢谢 嘿,似乎没人想插嘴这件事。结果证明答案很简单。通过
stillImageOutput CaptureSillImageAsynchronousLyfromConnection:…
方法捕获的图像始终具有以下属性:
- UIImage orientation=始终UIImageOrientationRight,无论设备方向如何
- UIImage size=宽x高(例如,纵向宽度x纵向高度,取决于您的相机分辨率)
- CGImage size=取决于设备方向(例如纵向或横向)
- (UIImage *)imageRotatedUpForDeviceOrientation:(UIDeviceOrientation)deviceOrientation
在包含各种图像处理增强功能的UIImage类别中
编辑-实施示例
我收到了很多关于这方面功能代码的请求。我已经从一个正在运行的应用程序中提取了相关的实现
// this method is implemented in your capture session manager (wherever AVCaptureSession is used)
// capture a still image and save the device orientation
- (void)captureStillImage
{
UIDeviceOrientation currentDeviceOrientation = UIDevice.currentDevice.orientation;
[self.stillImageOutput
captureStillImageAsynchronouslyFromConnection:self.videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
if (imageData) {
UIImage *image = [UIImage imageWithData:imageData];
NSDictionary *captureInfo = {
@"image" : image,
@"deviceOrientation" : @(currentDeviceOrientation)
};
// TODO: send image & orientation to delegate or post notification to observers
}
else {
// TODO: handle image capture error
}
}];
}
// this method rotates the UIImage captured by the capture session manager based on the
// device orientation when the image was captured
- (UIImage *)imageRotatedUpFromCaptureInfo:(NSDictionary *)captureInfo
{
UIImage *image = [captureInfo objectForKey:@"image"];
UIDeviceOrientation deviceOrientation = [[captureInfo objectForKey:@"deviceOrientation"] integerValue];
UIImageOrientation rotationOrientation = [self rotationNeededForImageCapturedWithDeviceOrientation:deviceOrientation];
// TODO: scale the image if desired
CGSize newSize = image.size;
return [imageScaledToSize:newSize andRotatedByOrientation:rotationOrientation];
}
// return a scaled and rotated an image
- (UIImage *)imageScaledToSize:(CGSize)newSize andRotatedByOrientation:(UIImageOrientation)orientation
{
CGImageRef imageRef = self.CGImage;
CGRect imageRect = CGRectMake(0.0, 0.0, newSize.width, newSize.height);
CGRect contextRect = imageRect;
CGAffineTransform transform = CGAffineTransformIdentity;
switch (orientation)
{
case UIImageOrientationDown: { // rotate 180 deg
transform = CGAffineTransformTranslate(transform, imageRect.size.width, imageRect.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
} break;
case UIImageOrientationLeft: { // rotate 90 deg left
contextRect = CGRectTranspose(contextRect);
transform = CGAffineTransformTranslate(transform, imageRect.size.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
} break;
case UIImageOrientationRight: { // rotate 90 deg right
contextRect = CGRectTranspose(contextRect);
transform = CGAffineTransformTranslate(transform, 0.0, imageRect.size.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
} break;
case UIImageOrientationUp: // no rotation
default:
break;
}
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceRef = CGImageGetColorSpace(imageRef);
// madify bitmapInfo to work with PNG if necessary
if (bitmapInfo == kCGImageAlphaNone) {
bitmapInfo = kCGImageAlphaNoneSkipLast;
}
else if (bitmapInfo == kCGImageAlphaLast) {
bitmapInfo = kCGImageAlphaPremultipliedLast;
}
// Build a context that's the same dimensions as the new size
CGContextRef context = CGBitmapContextCreate(NULL,
contextRect.size.width,
contextRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
colorSpaceRef,
bitmapInfo);
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, imageRect, imageRef);
// Get the rotated image from the context and a UIImage
CGImageRef rotatedImageRef = CGBitmapContextCreateImage(context);
UIImage *rotatedImage = [UIImage imageWithCGImage:rotatedImageRef];
// Clean up
CGImageRelease(rotatedImageRef);
CGContextRelease(context);
return rotatedImage;
}
// return the UIImageOrientation needed for an image captured with a specific deviceOrientation
- (UIImageOrientation)rotationNeededForImageCapturedWithDeviceOrientation:(UIDeviceOrientation)deviceOrientation
{
UIImageOrientation rotationOrientation;
switch (deviceOrientation) {
case UIDeviceOrientationPortraitUpsideDown: {
rotationOrientation = UIImageOrientationLeft;
} break;
case UIDeviceOrientationLandscapeRight: {
rotationOrientation = UIImageOrientationDown;
} break;
case UIDeviceOrientationLandscapeLeft: {
rotationOrientation = UIImageOrientationUp;
} break;
case UIDeviceOrientationPortrait:
default: {
rotationOrientation = UIImageOrientationRight;
} break;
}
return rotationOrientation;
}
至于为什么当设备的方向为UIDeviceOrientation和ScapeLeft时需要AVCaptureVideoOrientation和ScapeRight,那是因为出于某种原因,UIDeviceOrientation和ScapeLeft==UIInterfaceOrientation和ScapeRight,而AVCaptureVideoOrientation遵循UIInterfaceOrientation约定
此外,UIDeviceOrientation还包括其他选项,如UIDeviceOrientationFaceUp、UIDeviceOrientationFaceDown和UIDeviceOrientationUnknown。如果要旋转界面以匹配设备的方向,可以尝试从[UIApplication sharedApplication].statusBarOrientation获取UIDeviceOrientation。实际上,您的实现中没有错误,您可以消除整个交换机情况 为什么可以消除开关盒: 设备和视频方向的对应值在数值上相等,即只要设备方向不是未知的、面朝上或面朝下,就可以将UIDeviceOrientation和AVCaptureVideoOrientation相等 关于令人困惑的术语: 设备方向LandscapeLeft=>手机顶部位于左侧 所以,想象一下视频的起点在哪里。。。。。对了,右上角=>右上角 同样,在其他横向方向中,视频方向远离手机顶部。 这在肖像和倒挂的情况下不会混淆 证明 拍摄静止图像时,请检查方向EXIF值。 对于横向左侧,EXIF方向为3(180度反转) 对于横向右侧,EXIF方向为1(无旋转) 显示时,exif方向将转换为相应的UIImageOrientation,因此不应反转 对于前置摄像头,我注意到EXIF值仅遵循视频方向值(不考虑镜像效果)。仅使用EXIF的1、3、6、8个值 此外,镜子始终沿着设备顶部到底部的直线
所以,风景看起来是颠倒的,而肖像和颠倒的肖像只是镜像的很好的答案,但几行实现将节省我一些输入!8-@XJones我无法理解下面这行代码,你能给我解释一下吗?contextRect=CGRectTranspose(contextRect);CGRectTranspose wtfuideviceoorientation和scapeRight只为后置摄像头引导UIImageOrientationDown。对于前置摄像头,正确的结果是UIImageOrientationUp。UIDeviceOrientation和ScapeLeft的情况相同:UIImageOrientationUp仅适用于后置摄像头。对于前置摄像头UIImageOrientationDown,存在一个问题——因为苹果又增加了两个设备方向——UIDeviceOrientationFaceUp和UIDeviceOrientationFaceDown。也不要忘记UIDeviceOrientationUnknown。你需要处理所有这些。不要问我怎么做,因为Idk。当您实际想要使用UIInterface定向时,不要使用UIDevice定向。在这种情况下,您不能使用
UIInterface
定向。拍摄图像时的设备方向始终正确。捕获数据后,stillImage
的图像方向不正确。我能够使用UIDeviceOrientation解决这个问题,并在旋转时转换为适当的UIImageOrientation。当时,这里没有人打电话,所以我没有发代码。如果我有时间,我将添加代码。@XJones,请用精确的解决方案更新您的答案。是否左/右横向是由于使用前后摄像头?否,前后摄像头的值相等。