zoukankan      html  css  js  c++  java
  • 二维码扫描知识点

    二维码知识点总结

    01-二维码简介

    1.概念

    • 二维码:用某种特定的集合图形按照一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号的信息
    • 生成二维码:根据给定的信息,将其按照二维码的编码方式生成一张图片
    • 读取二维码:识别二维码图像里面存储的数据

    2.使用场景

    • 信息获取(名片/WiFi密码/资料)
    • 手机电商(用户扫码/手机直接购物下单)
    • 加好友(QQ/微信/扫一扫加好友)
    • 手机支付(扫描商品二维码,通过银行或第三方支付提供的手机端通道完成支付)

    3.生成方式

    • 从iOS7开始集成了二维码的生成和读取功能
    • 此前被广泛使用的zbarsdk目前不支持64位处理器
    • 2015年2月1日起,不允许不支持64位处理器的APP上架

    4.二维码读取

    • 直接从图片中识别,最低支持iOS8.0
    • 利用摄像头扫描识别,需要真机设备

    02-生成/识别/读取二维码

    1.生成二维码

    • 导入CoreImage框架
      • 一些图片处理操作的功能,都是用这个框架实现,比如:滤镜效果/毛玻璃/美颜相机等
      • #import <CoreImage/CoreImage.h>
    • 通过滤镜CIFilter生成二维码
      1. 实例化二维码滤镜 CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
      2. 恢复滤镜的默认属性 [filter setDefault];
      3. 将字符串转换成NSData NSData *data = [@"木喳喳的夏天" dataUsingEncoding:NSUTF8StringEncoding];
      4. 通过KVC设置滤镜inputMessage数据 [filter setValue:data forKey:@"inputMessage"];
      5. 获得滤镜输出的图像,大小默认是23*23 CIImage *outputImage = [filter outputImage];
      6. 将CIImage转换成UIImage,并放大显示 return [UIImage imageWithCIImage:outputImage scale:20.0 orientation:UIImageOrientationUp];
      7. 通过位图创建高清图片
    /**
         根据CIImage生成指定大小的高清UIImage
         :param: image 指定CIImage
         :param: size    指定大小
         :returns: 生成好的图片
         */
        private func createBigImage(image: CIImage, size: CGFloat) -> UIImage {
    
            let extent: CGRect = CGRectIntegral(image.extent)
            let scale: CGFloat = min(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent))
    
            // 1.创建bitmap;
            let width = CGRectGetWidth(extent) * scale
            let height = CGRectGetHeight(extent) * scale
            let cs: CGColorSpaceRef = CGColorSpaceCreateDeviceGray()!
            let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, cs, 0)!
    
            let context = CIContext(options: nil)
            let bitmapImage: CGImageRef = context.createCGImage(image, fromRect: extent)
    
            CGContextSetInterpolationQuality(bitmapRef,  CGInterpolationQuality.None)
            CGContextScaleCTM(bitmapRef, scale, scale);
            CGContextDrawImage(bitmapRef, extent, bitmapImage);
    
            // 2.保存bitmap到图片
            let scaledImage: CGImageRef = CGBitmapContextCreateImage(bitmapRef)!
    
            return UIImage(CGImage: scaledImage)
        }
    

    2.自定义二维码

    • 所谓自定义二维码,就是指给二维码添加一些图片(前景或背景图片),或者改变下颜色
    • 可以添加前景图片的前提是因为二维码具备一定的"容错率"
      • 如果二维码被部分遮挡,可以根据其他部分,计算出遮挡部分的内容;
      • 但是要保证三个角不能被遮挡;
      • 三个角用作扫描定位使用(可能用户倒着拍/斜着拍等)
    • 通过KVC设置滤镜的inputCorrectionLevel(容错率)
      • @"L",@"M",@"Q",@"H"中的一个
      • L水平:7%的字码可被修正
      • M水平:15%的字码可被修正
      • Q水平:25%的字码可被修正
      • H水平:30%的字码可被修正
    func createImage(bgImage: UIImage?, iconImage: UIImage?) -> UIImage?
    {
        if bgImage == nil || iconImage == nil
        {
            return nil
        }
        // 1.开启图片上下文
        UIGraphicsBeginImageContext(bgImage!.size)
        // 2.绘制背景
        bgImage!.drawInRect(CGRect(origin: CGPointZero, size: bgImage!.size))
        // 3.绘制图标
        let w:CGFloat = 50
        let h = w
        let x = (bgImage!.size.width - w) * 0.5
        let y = (bgImage!.size.height - h) * 0.5
        iconImage!.drawInRect(CGRect(x: x, y: y,  w, height: h))
        // 4.取出图片
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        // 5.关闭上下文
        UIGraphicsEndImageContext()
    
        return newImage
    }
    
    

    3.识别二维码

    • 识别图片二维码
      1. 创建一个上下文 let context = CIContext()
      2. 创建一个探测器 let detector = CIDetector(ofType:CIDetectorTypeQRCode,context:context,option:[CIDetectorAccuracy:CIDetectorAccuracyHigh])
      3. 转换图片为CIImage let image = CIImage(CGImage:sourceImage.CGImage)
      4. 获取探测器识别的图像特征 let features = detector.featuresInImage(image)
      5. 遍历图片特征,获取数据
        • var tempArray = [String]()
        • for feature in features {}
        • let resultFeature: CIQRCodeFeature = feature as! CIQRCodeFeature
        • tempArray.append(resultFeature.messageString)
      6. 绘制识别到的二维码边框
    private class func drawRectInImage(qrFeature: CIQRCodeFeature, image: UIImage) -> UIImage
    {
        let size = image.size
        UIGraphicsBeginImageContext(size)
    
        image.drawInRect(CGRectMake(0, 0, size.width, size.height))
    
        // 反转坐标系(因为是别的二维码坐标是相对于图片的坐标, 坐标系是以, 左下角为0, 0, 所以需要上下翻转坐标系)
        let context = UIGraphicsGetCurrentContext()
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextTranslateCTM(context, 0, -image.size.height);
    
        let path: UIBezierPath = UIBezierPath(rect: qrFeature.bounds)
    
        UIColor.redColor().set()
        path.lineWidth = 6
        path.stroke()
    
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()
    
        UIGraphicsEndImageContext()
        
        return resultImage 
    }
    
    

    3.2 扫描二维码

    • 二维码扫描动画
    • 二维码扫描功能
      1. 实例化拍摄设备
        • AVCaptureDevice *device = [AVCaputureDevice defalutDeviceWithMediaType:AVMediaTypeVideo];
      2. 设置输入设备
        • AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
      3. 设置元数据输出处理对象
        • 实例化拍摄元数据输出
        • AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
        • 设置输出数据代理
        • [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
      4. 添加拍摄会话
        • 实例化拍摄会话
        • AVCaptureSession *session = [[AVCaptureSession alloc] init];
        • 添加会话输入
        • [session addInput:input];
        • 添加会话输出
        • [session addOutput:output];
        • 设置输出数据类型,需要将元数据输出添加到会话后,才能指定元数据类型,否则报错
        • [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
      5. 视频预览图层(不是必须)
        • 实例化预览图层
        • AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        • preview.frame = self.view.bounds;
        • 将图层插入当前视图
        • [self.view.layer addSublayer:preview];
        • self.previewLayer = preview;
      6. 启动会话
        • [_session startRunning];
      7. 监听元数据处理后的结果
        • 当扫描到数据就会执行captureOutput:didOutputMetadataObjects:fromConnection
    • 二维码边框描绘
      • 提示:获取到二维码后,可以获得二维码的四个角,但是需要使用预览图层进行坐标转换
      • previewLayer.transformedMetadataObjectForMetadataObject(object as! AVMetadataObject)
      • 创建CAShapLayer,并设置path
    • 二维码扫描区域限定
      • 设置兴趣点
      • 注意:每个参数的取值都是对应的比例
      • 注意:坐标系是横屏状态下的坐标系
      • 而且值域范围是0-1
      • output.rectOfInterest = rect

    3.3 使用注意

    • 读取二维码需要导入AVFoundation框架
    • 利用摄像头识别二维码中的内容(模拟器不行)
  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/coderwjq/p/6211138.html
Copyright © 2011-2022 走看看