精华内容
下载资源
问答
  • 二维码扫码和相册二维码提取的方法在原生系统 AVFoundation 的 SDK 中提供了摄像头设备扫描捕获和检测提取的相应方法,具体方法 code 如下: 注:如下方法需在 iOS7 系统之后,通过系统中 AVMetadataObject 提供的...

    二维码扫码和相册二维码提取的方法在原生系统 AVFoundation 的 SDK 中提供了摄像头设备扫描捕获和检测提取的相应方法,具体方法 code 如下:
    注:如下方法需在 iOS7 系统之后,通过系统中 AVMetadataObject 提供的方法,从而解析二维码

    QRCScan Github

     

    首先,通过相机摄像头扫描部分

    #pragma mark - 扫描
    - (void)beginScanning {
        //获取摄像设备
        AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //创建输入流
        AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        if (!input) return;
        //创建输出流
        AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理 在主线程里刷新
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //设置有效扫描区域
        CGRect scanCrop=[self getScanCrop:_scanWindow.bounds readerViewBounds:self.view.frame];
        output.rectOfInterest = scanCrop;
        //初始化链接对象
        _session = [[AVCaptureSession alloc]init];
        //高质量采集率
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        
        [_session addInput:input];
        [_session addOutput:output];
        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
        output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                       AVMetadataObjectTypeEAN13Code,
                                       AVMetadataObjectTypeEAN8Code,
                                       AVMetadataObjectTypeCode128Code
        ];
        
        AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
        layer.frame=self.view.layer.bounds;
        [self.view.layer insertSublayer:layer atIndex:0];
        //开始捕获
        [_session startRunning];
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
        if (metadataObjects.count > 0) {
            [_session stopRunning];
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
            self.result = metadataObject.stringValue;
            [self.Args setValue:self.result forKey:@"QrCode"]; // 将结果拼装并回调
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }

    其次,通过相册选择二维码图片后检测并校验提取其中的数据

    #pragma mark - Delegate
    - (void)YHCameraCallBack:(UIImage *)image {
        NSLog(@"相册回调:%@", image);
        // 初始化检测器
        CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
        // 监测到的结果数组
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        if (features.count >=1) {
            /** 结果对象 */
            CIQRCodeFeature *feature = [features objectAtIndex:0];
            NSString *scannedRes = feature.messageString;
            [self disMiss];
            NSLog(@"二维码扫码结果:%@", scannedRes);
            [self.Args setValue:scannedRes forKey:@"QrCode"]; // 将结果拼装并回调
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        } else {
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"该图片没有包含一个二维码" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alertView show];
        }
    }

    通过如上两个 code 片段即可实现对二维码的识别和提取操作,具体还有一些详细的属性和方法可以从其提供的 SDK 接口中挑选配置;

    最后,如下是一个完整的 demo 可供参考:

    #import "FYHBaseViewController.h"
    typedef void(^returnQRCScanRsultBlock)(NSString *result);
    @protocol QRCScanViewControllerDelegate <NSObject>
    
    - (void)QRCScanCallBack:(NSMutableDictionary *)Dic;
    
    @end
    @interface QRCScanViewController : FYHBaseViewController
    
    @property (nonatomic, strong) NSMutableDictionary *Args;
    @property (nonatomic, assign) id<QRCScanViewControllerDelegate>delegate;
    @property (nonatomic, copy) returnQRCScanRsultBlock QRCScanRsultBlock;
    
    - (void)setQRCScanRsultBlock:(returnQRCScanRsultBlock)QRCScanRsultBlock;
    - (returnQRCScanRsultBlock)QRCScanRsultBlock;
    
    @end
    #import "QRCScanViewController.h"
    #import <AVFoundation/AVFoundation.h>
    #import "UIView+Exttension.h"
    #import "UIImage+FYH.h"
    #import "YHCameraManager.h"
    
    @interface QRCScanViewController () <AVCaptureMetadataOutputObjectsDelegate, UIAlertViewDelegate, YHCameraManagerDelegate>
    
    @property (nonatomic, strong) AVCaptureSession *session;
    @property (nonatomic, strong) UIImageView *scanLineImageView;
    @property (nonatomic, strong) UIView *scanWindow;
    @property (nonatomic, strong) UIView *maskView;
    
    @property (nonatomic, copy) NSString *result;
    @end
    
    @implementation QRCScanViewController
    
    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
    //    self.navigationController.navigationBar.hidden = YES;
    //    [self leftNavButtonType:NavLeftButtonTypeBack];
        [self basicConfig];
        [self resumeAnimation];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setupMaskView];
        [self setupScanWindow];
        [self beginScanning];
        [kNotificationCenter addObserver:self
                                selector:@selector(resumeAnimation)
                                    name:@"EnterForeground"
                                  object:nil];
    }
    
    - (void)viewDidDisappear:(BOOL)animated{
        [super viewDidDisappear:animated];
    //    self.navigationController.navigationBar.hidden = NO;
    //    [self.navigationController setNavigationBarHidden:YES animated:YES];
    }
    
    - (void)basicConfig {
    //    self.tabBarController.hidesBottomBarWhenPushed = YES;
    //    [self setupNavView]; // 自定义导航
        [self.navigationController setNavigationBarHidden:NO animated:YES];
        self.navigationController.navigationBar.translucent = NO;
        [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.7]]
                                                      forBarMetrics:UIBarMetricsDefault];
        [self leftNavButtonType:NavButtonStyleBackWhite];
        [self settingNavRightButton];
    }
    
    - (void)settingNavRightButton {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.titleLabel.font = [UIFont systemFontOfSize:14.f];
        [btn setTitle:@"相册" forState:UIControlStateNormal];
        [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [btn addTarget:self action:@selector(btnClickSelPhoto:) forControlEvents:UIControlEventTouchUpInside];
        UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:btn];
        self.navigationItem.rightBarButtonItem = item;
    }
    
    - (void)btnClickSelPhoto:(UIButton *)btn {
        NSLog(@"调用系统相册");
        YHCameraManager *cameraMag = [YHCameraManager shareInstance];
        cameraMag.delegate = self;
        [cameraMag openPhotoLibraryWithController:self];
    }
    
    - (void)dealloc {
        [kNotificationCenter removeObserver:self name:@"EnterForeground" object:nil];
    }
    
    
    
    #pragma mark - 自定义导航视图 Btn(注:若不需要相册二维码识别,也可使用该方法)
    -(void)setupNavView {
        UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, 64)];
        bgView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        bgView.userInteractionEnabled = YES;
        //1.返回
        UIButton *backBtn=[UIButton buttonWithType:UIButtonTypeCustom];
        backBtn.frame = CGRectMake(20, 30, 25, 25);
        [backBtn setBackgroundImage:[[UIImage imageNamed:@"navBack"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
                           forState:UIControlStateNormal];
    //    backBtn.contentMode = UIViewContentModeScaleAspectFit;
        [backBtn addTarget:self action:@selector(disMiss) forControlEvents:UIControlEventTouchUpInside];
        [bgView addSubview:backBtn];
        [self.view addSubview:bgView];
    }
    
    
    
    #pragma mark - UI
    - (void)setupMaskView {
        CGFloat Margin = 30; //
        CGFloat scanWindowH = self.view.width - 30 * 2;
    //    CGFloat scanWindowW = self.view.height - 30 * 2;
        
    //    UIView *topBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 64, self.view.width, 100)]; // 无系统导航版本
        UIView *topBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 100)];
        topBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:topBackgroundView];
        
        UIView *leftBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(topBackgroundView.frame), Margin, scanWindowH)];
        leftBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:leftBackgroundView];
        
        UIView *rightBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(self.view.width - Margin, leftBackgroundView.y, leftBackgroundView.width, leftBackgroundView.height)];
        rightBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:rightBackgroundView];
        
        UIView *bottmBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(rightBackgroundView.frame), self.view.width, self.view.height - CGRectGetMaxY(rightBackgroundView.frame))];
        bottmBackgroundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        [self.view addSubview:bottmBackgroundView];
    }
    
    
    
    #pragma mark - 设置相机 UI
    - (void)setupScanWindow {
        CGFloat kMargin = 30;
        CGFloat scanWindowH = self.view.width - kMargin * 2;
        CGFloat scanWindowW = self.view.width - kMargin * 2;
        _scanWindow = [[UIView alloc] initWithFrame:CGRectMake(kMargin, 100, scanWindowW, scanWindowH)];
        _scanWindow.clipsToBounds = YES;
        [self.view addSubview:_scanWindow];
        
        self.scanLineImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scan_net"]];
        CGFloat buttonWH = 18;
        
        UIButton *topLeft = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonWH, buttonWH)];
        [topLeft setImage:[UIImage imageNamed:@"scan_1"] forState:UIControlStateNormal];
        [_scanWindow addSubview:topLeft];
        
        UIButton *topRight = [[UIButton alloc] initWithFrame:CGRectMake(scanWindowW - buttonWH, 0, buttonWH, buttonWH)];
        [topRight setImage:[UIImage imageNamed:@"scan_2"] forState:UIControlStateNormal];
        [_scanWindow addSubview:topRight];
        
        UIButton *bottomLeft = [[UIButton alloc] initWithFrame:CGRectMake(0, scanWindowH - buttonWH, buttonWH, buttonWH)];
        [bottomLeft setImage:[UIImage imageNamed:@"scan_3"] forState:UIControlStateNormal];
        [_scanWindow addSubview:bottomLeft];
        
        UIButton *bottomRight = [[UIButton alloc] initWithFrame:CGRectMake(topRight.x, bottomLeft.y, buttonWH, buttonWH)];
        [bottomRight setImage:[UIImage imageNamed:@"scan_4"] forState:UIControlStateNormal];
        [_scanWindow addSubview:bottomRight];
        
        UILabel * tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_scanWindow.frame) + 20, self.view.bounds.size.width, 12)];
        tipLabel.text = @"将取景框对准二维码,即可自动扫描";
        tipLabel.textColor = [UIColor whiteColor];
        tipLabel.textAlignment = NSTextAlignmentCenter;
        tipLabel.lineBreakMode = NSLineBreakByWordWrapping;
        tipLabel.numberOfLines = 2;
        tipLabel.font=[UIFont systemFontOfSize:12];
        tipLabel.backgroundColor = [UIColor clearColor];
        [self.view addSubview:tipLabel];
    }
    
    - (void)resumeAnimation {
        CAAnimation *anim = [self.scanLineImageView.layer animationForKey:@"translationAnimation"];
        if(anim){
            // 1. 将动画的时间偏移量作为暂停时的时间点
            CFTimeInterval pauseTime = self.scanLineImageView.layer.timeOffset;
            // 2. 根据媒体时间计算出准确的启动动画时间,对之前暂停动画的时间进行修正
            CFTimeInterval beginTime = CACurrentMediaTime() - pauseTime;
            
            // 3. 要把偏移时间清零
            [self.scanLineImageView.layer setTimeOffset:0.0];
            // 4. 设置图层的开始动画时间
            [self.scanLineImageView.layer setBeginTime:beginTime];
            
            [self.scanLineImageView.layer setSpeed:1.0];
        } else {
            CGFloat scanNetImageViewH = 241;
            CGFloat scanWindowH = self.view.width - 30 * 2;
            CGFloat scanNetImageViewW = _scanWindow.width;
            
            self.scanLineImageView.frame = CGRectMake(0, -scanNetImageViewH, scanNetImageViewW, scanNetImageViewH);
            CABasicAnimation *scanNetAnimation = [CABasicAnimation animation];
            scanNetAnimation.keyPath = @"transform.translation.y";
            scanNetAnimation.byValue = @(scanWindowH);
            scanNetAnimation.duration = 1.5;
            scanNetAnimation.repeatCount = MAXFLOAT;
            [self.scanLineImageView.layer addAnimation:scanNetAnimation forKey:@"translationAnimation"];
            [_scanWindow addSubview:self.scanLineImageView];
        }
    }
    
    
    
    #pragma mark - 扫描
    - (void)beginScanning {
        //获取摄像设备
        AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //创建输入流
        AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        if (!input) return;
        //创建输出流
        AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理 在主线程里刷新
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //设置有效扫描区域
        CGRect scanCrop=[self getScanCrop:_scanWindow.bounds readerViewBounds:self.view.frame];
        output.rectOfInterest = scanCrop;
        //初始化链接对象
        _session = [[AVCaptureSession alloc]init];
        //高质量采集率
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        
        [_session addInput:input];
        [_session addOutput:output];
        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
        output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                       AVMetadataObjectTypeEAN13Code,
                                       AVMetadataObjectTypeEAN8Code,
                                       AVMetadataObjectTypeCode128Code
        ];
        
        AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
        layer.frame=self.view.layer.bounds;
        [self.view.layer insertSublayer:layer atIndex:0];
        //开始捕获
        [_session startRunning];
    }
    
    
    
    #pragma mark - 获取扫描区域的比例关系
    - (CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)readerViewBounds {
        CGFloat x,y,width,height;
        x = (CGRectGetHeight(readerViewBounds)-CGRectGetHeight(rect))/2/CGRectGetHeight(readerViewBounds);
        y = (CGRectGetWidth(readerViewBounds)-CGRectGetWidth(rect))/2/CGRectGetWidth(readerViewBounds);
        width = CGRectGetHeight(rect)/CGRectGetHeight(readerViewBounds);
        height = CGRectGetWidth(rect)/CGRectGetWidth(readerViewBounds);
        
        return CGRectMake(x, y, width, height);
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
        if (metadataObjects.count > 0) {
            [_session stopRunning];
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
            self.result = metadataObject.stringValue;
            [self disMiss];
            [self.Args setValue:self.result forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }
    
    //- (void)setArgs:(NSMutableDictionary *)Args
    //{
    //    if (self.Args != Args)
    //    {
    //        self.Args = Args;
    //    }
    //
    //}
    
    - (void)setQRCScanRsultBlock:(returnQRCScanRsultBlock)QRCScanRsultBlock {
        if (self.QRCScanRsultBlock != QRCScanRsultBlock) {
            self.QRCScanRsultBlock = QRCScanRsultBlock;
        }
    }
    
    - (returnQRCScanRsultBlock)QRCScanRsultBlock {
        return self.QRCScanRsultBlock;
    }
    
    - (void)disMiss {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    
    
    #pragma mark - 提示框
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
        if (buttonIndex == 0) {
            [_session startRunning];
        } else if (buttonIndex == 1) {
            [self disMiss];
            [self.Args setValue:self.result forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        }
    }
    
    
    
    #pragma mark - Delegate
    - (void)YHCameraCallBack:(UIImage *)image {
        NSLog(@"相册回调:%@", image);
        // 初始化检测器
        CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
        // 监测到的结果数组
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        if (features.count >=1) {
            /** 结果对象 */
            CIQRCodeFeature *feature = [features objectAtIndex:0];
            NSString *scannedRes = feature.messageString;
            [self disMiss];
            NSLog(@"二维码扫码结果:%@", scannedRes);
            [self.Args setValue:scannedRes forKey:@"QrCode"];
            if (self.delegate && [self.delegate respondsToSelector:@selector(QRCScanCallBack:)]) {
                [self.delegate QRCScanCallBack:self.Args];
            }
        } else {
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"该图片没有包含一个二维码" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
            [alertView show];
        }
    }
    
    @end

     

    拓展:
    1.实现中背景色部分应用到了 Color 转 Image 的方法具体如下:

    + (UIImage *)imageWithColor:(UIColor *)color {
        CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
        UIGraphicsBeginImageContext(rect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        
        CGContextSetFillColorWithColor(context, [color CGColor]);
        CGContextFillRect(context, rect);
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return image;
    }

    2.调用相册的功能封装成了单独的 基于 PickerController 功能模块封装相关 - iOS 类,具体方法实现如下:

    /**
     调用相册
     
     @param controller 当前 VC 控件
     */
    - (void)openPhotoLibraryWithController:(UIViewController *)controller {
        if (@available(iOS 11, *)) {
            UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
        }
        
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
            UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
            imagePicker.allowsEditing = YES;
            imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            imagePicker.delegate = self;
            
            [controller presentViewController:imagePicker animated:YES completion:^{
                NSLog(@"调用了 --- 相册");
            }];
        } else {
            [MBProgressHUD showCommonHudWithAlertString:@"无法打开相册" afterDelay:2.0 toView:controller.view];
        }
    }

     


    以上便是此次分享的全部内容,希望能对大家有所帮助!

    展开全文
  • 二维码提取(不包括识别)

    千次阅读 2020-08-02 09:06:27
    二维码提取(不包括识别) 实验室相关课题需要对二维码中心点作为特征点来提取,得到其像素坐标,然后利用深度相机恢复其三维空间坐标,用于后续实验。本文主要针对二维码中心点像素坐标提取做介绍。 ...

    二维码提取(不包括识别)

    实验室相关课题需要对二维码中心点作为特征点来提取,得到其像素坐标,然后利用深度相机恢复其三维空间坐标,用于后续实验。本文主要针对二维码中心点像素坐标提取做介绍。

    二维码概述

    二维码在日常生活中非常常见,其符号图形如图所示,QR二维码全称Quick Response,简称为QR码,QR码是在1994年9月由Denso公司研制而成。
    在这里插入图片描述
    QR码是由一系列相同尺寸的黑白小方格组成的正方形条码,其由编码区、分隔符、寻像图形、位置探测图形、校正图形和定位图形等识别功能图形组成。QR码和其它传统二维码相比具有高信息量、高可靠性以及高速全方位识读等特点,所以QR码已经广泛应用于各行各业。QR码由很多不同的符号结构组成,每一块符号结构均具有特定的功能,QR二维码的符号结构说明图如图所示。在这里插入图片描述
    由二维码的符号结构说明图可以看到其有三个分别位于左上角、右上角和左下角的“回”字形图案,这三个“回”字形图案被称为位置探测图形,如下图所示。将位置探测图形的黑白交界从左到右或从上到下画一条直线,则这条直线经过的图案黑白比例大约为1:1:3:1:1,其不仅具有独特的像素比例关系,而且具有旋转不变性,比较容易从图像中提取出来,所以利用其三个位置探测图形,二维码可在图片中被快速地定位和提取出来。
    在这里插入图片描述

    ZBar算法实现二维码检测

    由于二维码是标准化产品,并且在日常生活中应用广泛,目前已经有开源的二维码检测算法用于工业、物流业等行业中实现对二维码的快速检测。目前二维码检测算法应用较多的有ZBar算法和ZXing算法,但是ZBar算法是基于C语言编写,并且检测效率比ZXing算法高,所以本文采用ZBar算法来实现对QR码的检测定位,ZBar算法的流程如图所示。
    在这里插入图片描述
    ZBar算法的基本流程为首先建立4×4的窗口对图像整体以Z字形进行逐行扫描并均值去噪,根据梯度变换得到每行每列的明暗宽度流;然后判断明暗宽度流是否满足QR码的图案特征,若满足则保存明暗宽度流并设置扫码种类为QR码;根据QR码位置探测图形的黑白比例大约为1:1:3:1:1对明暗宽度流线段进行筛选并聚类之后求出横向和纵向线段的交叉点,进而可以求出QR码的四个顶点坐标。
    求出QR码的四个顶点坐标之后,通过绘制矩形框在图像上显示出QR码的位置信息,并求出矩形框的中心点的像素坐标即为QR码在像素坐标系下的坐标值。

    最终实现结果

    对于简单背景:
    在这里插入图片描述
    对于复杂背景:
    在这里插入图片描述
    可以看出对于简单背景和复杂背景,ZBar算法都能较好地检测出二维码中心点,并能提取出其像素坐标。

    展开全文
  • 二维码提取链接

    2021-08-20 05:03:00
    } else { this.$message.error('识别二维码失败, 请重新上传') } }).catch(err => { this.$message.error(JSON.stringify(err)) }) } }, getQrUrl(file) { const url = window.webkitURL.createObjectURL...

    import QrCode from 'qrcode-decoder';

    beforeUpload(event) {

          let that = this;

          for (let i = 0; i < event.length; i++) {

            const result = that.getQrUrl(event[i].raw)

            result.then(res => {

              if (res.data) {

                that.ruleForm.fileObj+=event.length==1?res.data:res.data+'\n';

                // this.$message.success('识别二维码成功!')

                this.$refs.ruleForm.validateField("fileObj");

              } else {

                this.$message.error('识别二维码失败, 请重新上传')

              }

            }).catch(err => {

              this.$message.error(JSON.stringify(err))

            })

          }

        },

        getQrUrl(file) {

          const url = window.webkitURL.createObjectURL(file)||window.URL.createObjectURL(file)

          const qr = new QrCode()

          return qr.decodeFromImage(url)

        },

    展开全文
  • 之前就想写个关于android zxing 二维码扫描相关功能提取的文章,现在终于有时间写出来了,zxing 条形码扫描代码支持多种格式,而我们项目中有时候只需要其中一种或者几中扫描,如果直接把zxing直接放入项目中,会...

    之前就想写个关于android zxing 二维码扫描相关功能提取的文章,现在终于有时间写出来了,zxing 条形码扫描代码支持多种格式,而我们项目中有时候只需要其中一种或者几中扫描,如果直接把zxing直接放入项目中,会增加项目的大小,所有我们需要根据需求去提取我们想要的扫描格式
    zxing github地址 [https://github.com/zxing/zxing]
    zxing把支持的所有格式条形码扫描格式放在 com.google.zxing包下的BarcodeFormat中,可以根据自己项目需求集成不同格式条形码的扫描与生成

    我们只介绍二维码的扫描与生成,二维码扫描步骤分为:扫描,解码,返回结果,zxing中,android二维码扫描放在包android下,其中,cameraManager管理相机相关,CaptureActivityHandler为二维码扫描结果handler,DecoderThread中启动解码,解码结果通过decodehanlder返回给captureactivityhandler,再返回到ui中,
    viewfinderview为二维码预览界面,如果项目需要自定义预览界面,可以重写viewfinderview 的ondraw方法

    cameramanager中实现了camera的PreviewCallback接口,通过回调previewcallback的实现类中的onpreviewframe方法返回当前相机界面数据,获取到的数据以byte[]数组格式通过decoderhanlder发送给decoderthread,decoderhanlder接收到数据后,调用decode()方法解析开始解析二维码数据

    zxing通过MultiFormatReader控制多种二维码解析,MultiFormatReader中有一个reader[]数据来报错reader解析器,

     public void setHints(Map<DecodeHintType,?> hints) {
        this.hints = hints;
    
        boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
        @SuppressWarnings("unchecked")
        Collection<BarcodeFormat> formats =
            hints == null ? null : (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
        Collection<Reader> readers = new ArrayList<>();
        if (formats != null) {
          boolean addOneDReader =
              formats.contains(BarcodeFormat.UPC_A) ||
              formats.contains(BarcodeFormat.UPC_E) ||
              formats.contains(BarcodeFormat.EAN_13) ||
              formats.contains(BarcodeFormat.EAN_8) ||
              formats.contains(BarcodeFormat.CODABAR) ||
              formats.contains(BarcodeFormat.CODE_39) ||
              formats.contains(BarcodeFormat.CODE_93) ||
              formats.contains(BarcodeFormat.CODE_128) ||
              formats.contains(BarcodeFormat.ITF) ||
              formats.contains(BarcodeFormat.RSS_14) ||
              formats.contains(BarcodeFormat.RSS_EXPANDED);
          // Put 1D readers upfront in "normal" mode
          if (addOneDReader && !tryHarder) {
            readers.add(new MultiFormatOneDReader(hints));
          }
          if (formats.contains(BarcodeFormat.QR_CODE)) {
            readers.add(new QRCodeReader());
          }
          if (formats.contains(BarcodeFormat.DATA_MATRIX)) {
            readers.add(new DataMatrixReader());
          }
          if (formats.contains(BarcodeFormat.AZTEC)) {
            readers.add(new AztecReader());
          }
          if (formats.contains(BarcodeFormat.PDF_417)) {
             readers.add(new PDF417Reader());
          }
          if (formats.contains(BarcodeFormat.MAXICODE)) {
             readers.add(new MaxiCodeReader());
          }
          // At end in "try harder" mode
          if (addOneDReader && tryHarder) {
            readers.add(new MultiFormatOneDReader(hints));
          }
        }
        if (readers.isEmpty()) {
          if (!tryHarder) {
            readers.add(new MultiFormatOneDReader(hints));
          }
    
          readers.add(new QRCodeReader());
          readers.add(new DataMatrixReader());
          readers.add(new AztecReader());
          readers.add(new PDF417Reader());
          readers.add(new MaxiCodeReader());
    
          if (tryHarder) {
            readers.add(new MultiFormatOneDReader(hints));
          }
        }
        this.readers = readers.toArray(new Reader[readers.size()]);
      }

    sethints()通过hints map,将自己需要的条形码解析器放入reader数组中,如果我们只需要二维码解析,可以直接调用qrcode包下的QRcodeReader类,通过PlanarYUVLuminanceSource与HybridBinarizer将byte[]数据转换为Bitmap,然后调用QRcodeReader.decode解析数据,解析完成后,通过handler回调到主线程

    二维码生成类为qrcode包下的QRCodeWriter类,调用QRCodeWriter的encode生成二维码

    public static Bitmap witerQR(String content,int size,int qrColor,int bgColor){
            Map<EncodeHintType,Object> hints=new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
            hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
            BitMatrix result;
            try {
                result= new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE,size,size,hints);
            } catch (WriterException e) {
                e.printStackTrace();
                return null;
            }
    
            int width=result.getWidth();
            int height=result.getHeight();
            int[] pixels=new int[width*height];
    
            for (int y = 0; y < height; y++) {
                int offset=y*width;
                for (int x = 0; x < width; x++) {
                    //给二维码设置颜色
                    pixels[offset+x]=result.get(x,y)?qrColor:bgColor;
                }
            }
    
            Bitmap bitmap=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels,0,width,0,0,width,height);
            return bitmap;
        }

    生成二维码

    展开全文
  • 这个问题解决办法很简单,只要在链接后面加上 #wechat_redirect 就行了。 如:...aaaa&bbb ...aaaa&bbb#wechat_redirect 这样就可以了。这个问题居然疑惑了几天。......
  • 在复杂背景下的二维码区域定位一直是QR Code二维条码解码过程中的难题之一。...火车票通过图像预处理得到可能是二维码的区域块,提取经图像处理后的二维码区域块图像特征并结合BP神经网络过滤出正确的二维码区域。
  • 请问,想把图片中的二维码提取出来,把背景去掉提取出二维码图像,然后做成方方正正的。应该什么思路去实现呢![请问,想把图片中的二维码提取出来,把背景去掉提取出二维码图像,然后做成方方正正的。应该什么思路去...
  • 这里来说明一下做这次的二维码提取算法用到的函数,最后再给出完整的代码!  进行图像的二值化,这里可以使用opencv2里的函数threshold,当然在opencv里也有cvThreshold函数  (这个函数可以具体参考:...
  • halcon二维码的识别和提取二维码数据信息--我用的halcon10,本分算子其他版本可能需要修改。
  • } else { this.$message.error('识别二维码失败, 请重新上传') } }).catch(err => { this.$message.error(JSON.stringify(err)) }) } }, getQrUrl(file) { const url = window.webkitURL.createObjectURL...
  • python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容1 pyzbar二维码检测模块1.1. pyzbar模块介绍1.2 pyzbar模块的安装1.3 pyzbar模块测试用例2 python3 + opencv +pyzbar实时...
  • 摄像头扫到二维码提取二维码中的信息分别放到数组中把想要的信息编辑好放到二维码中(网上有好多在线生成二维码的工具)char name[6];//从二维码扫到的姓名:eg:weibo char ID[12];//从二维码扫到的ID:eg:...
  • Android二维码源码提取、解释、使用

    千次阅读 2018-01-23 10:11:06
    Android二维码源码提取、解释、使用 参考(已经封装好):https://github.com/yipianfengye/android-zxingLibrary 参考(提取源码):https://www.jianshu.com/p/e80a85b17920 参考(讲的清晰):...
  • 数字图像处理之二维码图像提取算法(二)

    万次阅读 多人点赞 2014-11-06 13:27:59
    二维码标准: 国外:pdf417,Data...译码:二维码码字提取-> 纠错译码-> 信息译码 纠错译码:求解伴随因子(判断)  正确码字=Yji ^ 错误码字。; 信息译码:模式指示+字符段+数据位流  判断编码模式和字
  • 一维二维码提取、识别和产生 零、相关说明: 在“jsxyhelu.cnblogs.com/机器视觉”栏目主要介绍和图像处理和机器视觉相关的的成套的解决方案、思路和软件集。希望能够为大家在实际工作中解决具体问题提供一些...
  • 二维条码图像提取主要是实现二维条码中码字的提取,包括图像预处理和码字提取两部分。具体的流程图如下所示:     整个图像提取流程大致分为 8 个步骤, 现按步骤分别说明如下:   第一步 将图像采集设备获取的...
  • 通过霍夫变换我们可以知道整个二维码倾斜的角度,然后我们就可以进行二维码的矫正。  霍夫变换具体如下:采用分级的Hough变换方法,不但降低了Hough变换的运算量,而且精确的求得了条码的倾斜角度。其次,扫描 PDF...
  • opencv-python提取二维码

    千次阅读 2018-08-14 15:01:55
    利用二维码的三个定位点来找到提取二维码 算法的主要思想和C++参考该博主:C++ Opencv提取二维码 该博主的算法是不完整的。 我的算法思想: 1)定位点的轮廓有三层轮廓 2)每个定位点的轮廓中心点一样的 3)三...
  • 二维码预处理之自适应亮度均衡算法的介绍
  • 接着进行码字提取,如下图:     总结 : 用分级的Hough变换算法检测PDF417条码的倾斜角度并将条码旋转到水平状态。 对于可能发生的几何形变也给出了相应的几何校正算法,复原图像。...
  • Python提取图片二维码Python

    千次阅读 2018-08-08 11:23:40
    1、安装tesseract   2、安装tesserocr windows环境直接pip install tesserocr 安装失败! ...conda install -c simonflueckiger tesserocr ...用上面这条指令可以成功安装tesserocr,,检验是否成功安装:import一下,...
  • 数字图象处理之二维码图像提取算法(十二)

    千次阅读 多人点赞 2015-02-22 00:27:11
    新年代码大放送: // test1.cpp : Defines the entry point for the console application. #include "stdafx.h" #include "highgui.h" #include "cv.h" #include "cvaux.h" #include "stdio.h" ...
  • python+opencv3.4提取图片中的二维码区域,有简单的算法思路介绍。链接 https://blog.csdn.net/kellen_f/article/details/81667315

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,453
精华内容 7,781
关键字:

二维码提取