AVFoundation識別二維碼并加邊框

目標(biāo):識別二維碼,并且在視頻流中,在已識別的二維碼周邊加上邊框。

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>

@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *preview;

@property (nonatomic, strong) CALayer *drawLayer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // session
    _session = [[AVCaptureSession alloc] init];
    
    // input
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:nil];
    
    // output
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
    
    // addInput, addOutput
    if ([_session canAddInput:input]) {
        [_session addInput:input];
    }
    if ([_session canAddOutput:output]) {
        [_session addOutput:output];
    }
    
    output.metadataObjectTypes = output.availableMetadataObjectTypes;
    
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    _preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    _preview.frame = self.view.bounds;
    
    _drawLayer = [CALayer layer];
    _drawLayer.frame = self.view.bounds;
}


- (IBAction)testButton1:(id)sender {
    
    if (_session.isRunning) {
        [_preview removeFromSuperlayer];
        [_drawLayer removeFromSuperlayer];
        [_session stopRunning];
    } else {
        [self.view.layer insertSublayer:_drawLayer atIndex:0];
        [self.view.layer insertSublayer:_preview atIndex:0];
        [_session startRunning];
        
    }
}

- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    
    NSArray *layers = _drawLayer.sublayers.copy;
    for (CALayer *layer in layers) {
        [layer removeFromSuperlayer];
    }
    
    for (AVMetadataObject *obj in metadataObjects) {
        if ([obj isKindOfClass:AVMetadataMachineReadableCodeObject.class]) {
            //將0-1間小數(shù)表示的坐標(biāo)系轉(zhuǎn)換為常用的坐標(biāo)系
            AVMetadataMachineReadableCodeObject *temp = (AVMetadataMachineReadableCodeObject*)[_preview transformedMetadataObjectForMetadataObject:obj];
            [self addBorderOnOjbect:(AVMetadataMachineReadableCodeObject *)temp];
        }
    }
}

//添加一個(gè)中間是透明的,周邊是有顏色的layer
- (void)addBorderOnOjbect:(AVMetadataMachineReadableCodeObject *)obj {
    
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.lineWidth = 4;
    layer.strokeColor = UIColor.greenColor.CGColor;
    layer.fillColor = UIColor.clearColor.CGColor;
    layer.path = [self boderPathWithObject:obj].CGPath;
    
    [_drawLayer addSublayer:layer];
    
}

//獲取邊框的path
- (UIBezierPath *)boderPathWithObject:(AVMetadataMachineReadableCodeObject *)obj {
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    NSArray *corners = obj.corners;
    CGPoint point = CGPointZero; int index = 0;
    //將corner里0-1小數(shù)表示的坐標(biāo)點(diǎn)轉(zhuǎn)換為常用的坐標(biāo)點(diǎn)。
    CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)corners[index++], &point);
    [path moveToPoint:point];
    
    while (index < corners.count) {
        CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)corners[index++], &point);
        [path addLineToPoint:point];
    }
    [path closePath];
    return path;
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容