【问题标题】:Rotating captured frame from Samplebuffer in CGContext从 CGContext 中的 Samplebuffer 旋转捕获的帧
【发布时间】:2016-12-01 19:08:01
【问题描述】:

我正在使用前置摄像头,当我捕捉帧时,它们会逆时针旋转 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!)
}

【问题讨论】:

    标签: ios swift camera rotation cgcontext


    【解决方案1】:

    对于任何搜索如何实际以任意角度物理旋转缓冲区的人来说,这里是您可以做到的方法。将此添加到文件顶部:

    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 变量来关闭缩放。

    【讨论】:

      【解决方案2】:

      经过大量搜索和阅读文章,我在 AVCaptureConnection 类中找到了我的解决方案! 我只需要在捕获函数中使用以下示例代码请求连接来旋转缓冲区内的帧!

      if connection.isVideoOrientationSupported
      {
           connection.videoOrientation = .portrait
      }
           if connection.isVideoMirroringSupported
      {
           connection.isVideoMirrored = true
      }
      

      就是这样!

      【讨论】:

        【解决方案3】:

        如果你使用的是方法:

        - (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];
        }
        

        希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多