在CGContext

时间:2016-12-01 19:08:01

标签: ios swift camera rotation cgcontext

我正在使用前置摄像头,当我捕捉到帧时,它们会逆时针旋转90度。我想在CGContext中旋转捕获的图像(因为我读取Core Graphic比其他框架快得多)。

这是我的代码:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
    let imageBuffer =  CMSampleBufferGetImageBuffer(sampleBuffer)
    CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))

    let width = CVPixelBufferGetWidthOfPlane(imageBuffer!, 0)
    let height = CVPixelBufferGetHeightOfPlane(imageBuffer!, 0)

    let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer!, 0)

    let lumaBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer!, 0)

    let grayColorSpace = CGColorSpaceCreateDeviceGray()

    let context = CGContext(data: lumaBuffer,
                            width: width,
                            height: height,
                            bitsPerComponent: 8,
                            bytesPerRow: bytesPerRow,
                            space: grayColorSpace,
                            bitmapInfo: CGImageAlphaInfo.none.rawValue);

    let transform1 = CGAffineTransform(rotationAngle: CGFloat(M_PI_2))
    context!.concatenate(transform1)

    //context!.rotate(by: CGFloat(M_PI_2)) // also not working!
    let dstImage = context!.makeImage()

    detect(image: dstImage!)
}

2 个答案:

答案 0 :(得分:2)

对于任何搜索如何以任何角度实际旋转缓冲区的人来说,这是如何做到的。将其添加到文件顶部:

static double radians (double degrees) {return degrees * M_PI/180;}

static double ScalingFactorForAngle(double angle, CGSize originalSize) {
    double oriWidth = originalSize.height;
    double oriHeight = originalSize.width;
    double horizontalSpace = fabs( oriWidth*cos(angle) ) + fabs( oriHeight*sin(angle) );
    double scalingFactor = oriWidth / horizontalSpace ;
    return scalingFactor;
}

CGColorSpaceRef rgbColorSpace = NULL;
CIContext *context = nil;
CIImage *ci_originalImage = nil;
CIImage *ci_transformedImage = nil;

CIImage *ci_userTempImage = nil;


static inline void RotatePixelBufferToAngle(CVPixelBufferRef thePixelBuffer, double theAngle) {

    @autoreleasepool {

        if (context==nil) {
            rgbColorSpace = CGColorSpaceCreateDeviceRGB();
            context = [CIContext contextWithOptions:@{kCIContextWorkingColorSpace: (__bridge id)rgbColorSpace,
                                                       kCIContextOutputColorSpace : (__bridge id)rgbColorSpace}];
        }

        long int w = CVPixelBufferGetWidth(thePixelBuffer);
        long int h = CVPixelBufferGetHeight(thePixelBuffer);

        ci_originalImage = [CIImage imageWithCVPixelBuffer:thePixelBuffer];
        ci_userTempImage = [ci_originalImage imageByApplyingTransform:CGAffineTransformMakeScale(0.6, 0.6)];
        //        CGImageRef UICG_image = [context createCGImage:ci_userTempImage fromRect:[ci_userTempImage extent]];

        double angle = theAngle;
        angle = angle+M_PI;
        double scalingFact = ScalingFactorForAngle(angle, CGSizeMake(w, h));


        CGAffineTransform transform =  CGAffineTransformMakeTranslation(w/2.0, h/2.0);
        transform = CGAffineTransformRotate(transform, angle);
        transform = CGAffineTransformTranslate(transform, -w/2.0, -h/2.0);

        //rotate it by applying a transform
        ci_transformedImage = [ci_originalImage imageByApplyingTransform:transform];

        CVPixelBufferLockBaseAddress(thePixelBuffer, 0);

        CGRect extentR = [ci_transformedImage extent];
        CGPoint centerP = CGPointMake(extentR.size.width/2.0+extentR.origin.x,
                                      extentR.size.height/2.0+extentR.origin.y);
        CGSize scaledSize = CGSizeMake(w*scalingFact, h*scalingFact);
        CGRect cropRect = CGRectMake(centerP.x-scaledSize.width/2.0, centerP.y-scaledSize.height/2.0,
                                     scaledSize.width, scaledSize.height);


        CGImageRef cg_img = [context createCGImage:ci_transformedImage fromRect:cropRect];
        ci_transformedImage = [CIImage imageWithCGImage:cg_img];

        ci_transformedImage = [ci_transformedImage imageByApplyingTransform:CGAffineTransformMakeScale(1.0/scalingFact, 1.0/scalingFact)];
        [context render:ci_transformedImage toCVPixelBuffer:thePixelBuffer bounds:CGRectMake(0, 0, w, h) colorSpace:NULL];

        CGImageRelease(cg_img);
        CVPixelBufferUnlockBaseAddress(thePixelBuffer, 0);

    }
}

转到captureOutput: captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 并应用函数:

CVPixelBufferRef pixBuf = CMSampleBufferGetImageBuffer(sampleBuffer);
RotatePixelBufferToAngle(pixBuf, radians(45.0));

其中 45.0 - 是所需的角度

请注意,这不仅可以旋转,还可以缩放图像,使其填充视频尺寸(类似于Aspect Fill)。您可以通过修改 scalingFact 变量来关闭缩放。

答案 1 :(得分:0)

如果您使用的方法:

- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
   fromConnection:(AVCaptureConnection*)connection

您可以更改缓冲区的方向以获得正确的图像,这里有一个示例:

UIInterfaceOrientation iOrientation = [UIApplication sharedApplication].statusBarOrientation;

if(iOrientation == UIInterfaceOrientationLandscapeLeft){
    [connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
}
else{
    [connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
}

希望它有所帮助。