目标:识别二维码,并且在视频流中,在已识别的二维码周边加上边框。
#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间小数表示的坐标系转换为常用的坐标系
AVMetadataMachineReadableCodeObject *temp = (AVMetadataMachineReadableCodeObject*)[_preview transformedMetadataObjectForMetadataObject:obj];
[self addBorderOnOjbect:(AVMetadataMachineReadableCodeObject *)temp];
}
}
}
//添加一个中间是透明的,周边是有颜色的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小数表示的坐标点转换为常用的坐标点。
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