【问题标题】:Cropping image from AVCapture according rectangle view above camera layer根据相机层上方的矩形视图从 AVCapture 裁剪图像
【发布时间】:2015-03-12 18:02:11
【问题描述】:

我有相机预览层,其中相机预设为 1280x720。 在预览层上方,我添加了一个带边框的方形 UIView。

我的目标是从相机中获取裁剪图像。

从相机中提取数据的方法

-(CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer
                              left:(size_t)left
                               top:(size_t)top
                             width:(size_t)width
                            height:(size_t)height CF_RETURNS_RETAINED {
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
    size_t dataWidth = CVPixelBufferGetWidth(buffer);
    size_t dataHeight = CVPixelBufferGetHeight(buffer);

    if (left + width > dataWidth ||
        top + height > dataHeight) {
        [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."];
    }

    size_t newBytesPerRow = ((width*4+0xf)>>4)<<4;

    CVPixelBufferLockBaseAddress(buffer,0);

    int8_t *baseAddress = (int8_t *)CVPixelBufferGetBaseAddress(buffer);

    size_t size = newBytesPerRow*height;
    int8_t *bytes = (int8_t *)malloc(size * sizeof(int8_t));
    if (newBytesPerRow == bytesPerRow) {
        memcpy(bytes, baseAddress+top*bytesPerRow, size * sizeof(int8_t));
    } else {
        for (int y=0; y<height; y++) {
            memcpy(bytes+y*newBytesPerRow,
                   baseAddress+left*4+(top+y)*bytesPerRow,
                   newBytesPerRow * sizeof(int8_t));
        }
    }
    CVPixelBufferUnlockBaseAddress(buffer, 0);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef newContext = CGBitmapContextCreate(bytes,
                                                    width,
                                                    height,
                                                    8,
                                                    newBytesPerRow,
                                                    colorSpace,
                                                    kCGBitmapByteOrder32Little|
                                                    kCGImageAlphaNoneSkipFirst);
    CGColorSpaceRelease(colorSpace);

    CGImageRef result = CGBitmapContextCreateImage(newContext);

    CGContextRelease(newContext);

    free(bytes);

    return result;
}

旋转图片的代码

- (CGImageRef)createRotatedImage:(CGImageRef)original degrees:(float)degrees CF_RETURNS_RETAINED {
    if (degrees == 0.0f) {
        CGImageRetain(original);
        return original;
    } else {
        double radians = degrees * M_PI / 180;

#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
        radians = -1 * radians;
#endif

        size_t _width = CGImageGetWidth(original);
        size_t _height = CGImageGetHeight(original);

        CGRect imgRect = CGRectMake(0, 0, _width, _height);
        CGAffineTransform __transform = CGAffineTransformMakeRotation(radians);
        CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, __transform);

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(NULL,
                                                     rotatedRect.size.width,
                                                     rotatedRect.size.height,
                                                     CGImageGetBitsPerComponent(original),
                                                     0,
                                                     colorSpace,
                                                     kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst);
        CGContextSetAllowsAntialiasing(context, FALSE);
        CGContextSetInterpolationQuality(context, kCGInterpolationNone);
        CGColorSpaceRelease(colorSpace);

        CGContextTranslateCTM(context,
                              +(rotatedRect.size.width/2),
                              +(rotatedRect.size.height/2));
        CGContextRotateCTM(context, radians);

        CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2,
                                               -imgRect.size.height/2,
                                               imgRect.size.width,
                                               imgRect.size.height),
                           original);

        CGImageRef rotatedImage = CGBitmapContextCreateImage(context);
        CFRelease(context);

        return rotatedImage;
    }
}

提取数据:

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

        if(self.lastDecodeTime && [self.lastDecodeTime timeIntervalSinceNow]>-DECODE_LIMIT_TIME){
            return;
        }
        if ( self.scannerDisabled)
            return;

        self.lastDecodeTime=[NSDate date];

        CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
        CGFloat cameraFrameWidth = CVPixelBufferGetWidth(videoFrame);
        CGFloat cameraFrameHeight = CVPixelBufferGetHeight(videoFrame);


        CGPoint rectPoint = self.rectangleView.frame.origin;
        rectPoint = [self.previewLayer convertPoint:rectPoint fromLayer:self.view.layer];
        CGPoint cameraPoint =    [self.previewLayer captureDevicePointOfInterestForPoint:rectPoint];
        CGPoint matrixPoint = CGPointMake(cameraPoint.x*cameraFrameWidth,cameraPoint.x*cameraFrameHeight);

        CGFloat D = self.rectangleView.frame.size.width*2.0;
        CGRect matrixRect = CGRectMake(matrixPoint.x, matrixPoint.y, D, D);


        CGImageRef videoFrameImage = [self createImageFromBuffer:videoFrame left:matrixRect.origin.x top:matrixRect.origin.y width:matrixRect.size.width height:matrixRect.size.height];

        CGImageRef rotatedImage = [self createRotatedImage:videoFrameImage degrees:self.rotationDeg];
        CGImageRelease(videoFrameImage);
...
...
...
}

为了调试,我在左上角添加了一个小图像视图来查看裁剪结果。 你可以看到我在正确的方向但是有某种偏移。 我假设因为相机缓冲区是 1280x720 并且 iphone 屏幕有不同的方面,所以有某种裁剪可能是我正在处理的偏移量..

附上截图,你可以看到裁剪图像没有居中

p.s 这里是输出设置

 AVCaptureVideoDataOutput *output = [AVCaptureVideoDataOutput new];

    NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
                                       [NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
    [output setVideoSettings:rgbOutputSettings];

有什么想法吗?

【问题讨论】:

    标签: ios iphone


    【解决方案1】:

    试试这个从整个图像中获取裁剪图像

    [self.view resizableSnapshotViewFromRect:requiredRectToCrop afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
    

    【讨论】:

    • 谢谢,但这不是我要找的
    • 只需将 requiredRectToCrop 设置为方形 UIview rect 的矩形。
    • 什么是必需的RectToCrop?没有找到此方法的任何参考
    • “我得到了相机预览层,其中相机预设为 1280x720。在预览层上方我添加了一个带边框的方形 UIView”。 RequiredRectToCrop 是 Square UIView 的 Cgrect。 requiredRectToCrop = squareView.frame;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 2020-04-02
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多