CIDetector 边缘识别

作者: madaoCN | 来源:发表于2017-11-19 22:41 被阅读151次

    CoreImageCIDetector.h自带了四种识别功能

    / * 人脸识别 */
    CORE_IMAGE_EXPORT NSString* const CIDetectorTypeFace NS_AVAILABLE(10_7, 5_0);
    
    / * 矩形边缘识别 */
    CORE_IMAGE_EXPORT NSString* const CIDetectorTypeRectangle NS_AVAILABLE(10_10, 8_0);
    
    /* 二维码识别 */
    CORE_IMAGE_EXPORT NSString* const CIDetectorTypeQRCode NS_AVAILABLE(10_10, 8_0);
    
    /* 文本识别 */
    #if __OBJC2__
    CORE_IMAGE_EXPORT NSString* const CIDetectorTypeText NS_AVAILABLE(10_11, 9_0);
    

    接下来用CIDetectorTypeRectangle对图片的矩形状边缘进行识别,效果图如下 (Demo链接文章底部已给出

    识别边缘 截取

    部分代码:

    • 初始化一个高精度的识别器
    // 高精度边缘识别器
    - (CIDetector *)highAccuracyRectangleDetector
    {
        static CIDetector *detector = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^
                      {
                          detector = [CIDetector detectorOfType:CIDetectorTypeRectangle context:nil options:@{CIDetectorAccuracy : CIDetectorAccuracyHigh}];
                      });
        return detector;
    }
    
    • 调用照相机捕获摄像头图像
    NSArray *possibleDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
        AVCaptureDevice *device = [possibleDevices firstObject];
        if (!device) return;
        
        _imageDedectionConfidence = 0.0;
        
        AVCaptureSession *session = [[AVCaptureSession alloc] init];
        self.captureSession = session;
        [session beginConfiguration];
        self.captureDevice = device;
        
        NSError *error = nil;
        AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
        session.sessionPreset = AVCaptureSessionPresetPhoto;
        [session addInput:input];
        
        AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init];
        [dataOutput setAlwaysDiscardsLateVideoFrames:YES];
        [dataOutput setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)}];
        [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
        [session addOutput:dataOutput];
        
        self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
        [session addOutput:self.stillImageOutput];
        
        AVCaptureConnection *connection = [dataOutput.connections firstObject];
        [connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    
    • 还需要有个显示已捕获图像的容器
     self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        GLKView *view = [[GLKView alloc] initWithFrame:self.bounds];
        view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        view.translatesAutoresizingMaskIntoConstraints = YES;
        view.context = self.context;
        view.contentScaleFactor = 1.0f;
        view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
        [self insertSubview:view atIndex:0];
        _glkView = view;
        glGenRenderbuffers(1, &_renderBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
        
        //图像将绘制进_coreImageContext内
        _coreImageContext = [CIContext contextWithEAGLContext:self.context];
        [EAGLContext setCurrentContext:self.context];
    
    • 遵循AVCaptureVideoDataOutputSampleBufferDelegate代理,捕获到图像之后,会调用以下方法
    -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
    

    调用CIDetector进行识别,并且获取最大不规则四边形

    // 从缓冲区中获取CIImage
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
    CIImage *image = [CIImage imageWithCVPixelBuffer:pixelBuffer];
     // 用高精度边缘识别器 识别特征
    NSArray <CIFeature *>*features = [[self highAccuracyRectangleDetector] featuresInImage:image];
    // 选取特征列表中最大的不规则四边形
     _borderDetectLastRectangleFeature = [self biggestRectangleInRectangles:features];
    
    • 识别到边缘之后使用CAShapeLayer将边缘绘制并显示
    // 绘制边缘检测图层
    - (void)drawBorderDetectRectWithImageRect:(CGRect)imageRect topLeft:(CGPoint)topLeft topRight:(CGPoint)topRight bottomLeft:(CGPoint)bottomLeft bottomRight:(CGPoint)bottomRight
    {
        
        if (!_rectOverlay) {
            _rectOverlay = [CAShapeLayer layer];
            _rectOverlay.fillRule = kCAFillRuleEvenOdd;
            _rectOverlay.fillColor = [UIColor colorWithRed:73/255.0 green:130/255.0 blue:180/255.0 alpha:0.4].CGColor;
            _rectOverlay.strokeColor = [UIColor whiteColor].CGColor;
            _rectOverlay.lineWidth = 5.0f;
        }
        if (!_rectOverlay.superlayer) {
            self.layer.masksToBounds = YES;
            [self.layer addSublayer:_rectOverlay];
        }
    
        // 将图像空间的坐标系转换成uikit坐标系
        TransformCIFeatureRect featureRect = [self transfromRealRectWithImageRect:imageRect topLeft:topLeft topRight:topRight bottomLeft:bottomLeft bottomRight:bottomRight];
        
        // 边缘识别路径
        UIBezierPath *path = [UIBezierPath new];
        [path moveToPoint:featureRect.topLeft];
        [path addLineToPoint:featureRect.topRight];
        [path addLineToPoint:featureRect.bottomRight];
        [path addLineToPoint:featureRect.bottomLeft];
        [path closePath];
        // 背景遮罩路径
        UIBezierPath *rectPath  = [UIBezierPath bezierPathWithRect:CGRectMake(-5,
                                                                              -5,
                                                                              self.frame.size.width + 10,
                                                                              self.frame.size.height + 10)];
        [rectPath setUsesEvenOddFillRule:YES];
        [rectPath appendPath:path];
        _rectOverlay.path = rectPath.CGPath;
    }
    

    即可显示出实时识别的效果了

    • 最后拍照之后的裁剪,使用该滤镜将识别出的不规则四边形转换成矩形,即可转换成正正方方的矩形了
    /// 将任意四边形转换成长方形
    - (CIImage *)correctPerspectiveForImage:(CIImage *)image withFeatures:(CIRectangleFeature *)rectangleFeature
    {
        NSMutableDictionary *rectangleCoordinates = [NSMutableDictionary new];
        rectangleCoordinates[@"inputTopLeft"] = [CIVector vectorWithCGPoint:rectangleFeature.topLeft];
        rectangleCoordinates[@"inputTopRight"] = [CIVector vectorWithCGPoint:rectangleFeature.topRight];
        rectangleCoordinates[@"inputBottomLeft"] = [CIVector vectorWithCGPoint:rectangleFeature.bottomLeft];
        rectangleCoordinates[@"inputBottomRight"] = [CIVector vectorWithCGPoint:rectangleFeature.bottomRight];
        return [image imageByApplyingFilter:@"CIPerspectiveCorrection" withInputParameters:rectangleCoordinates];
    }
    

    // TODO : 识别出边缘之后,可以手动设置边缘范围

    手动设置边缘范围

    Demo地址: github传送门:https://github.com/madaoCN/MADRectDetect 好心人点下Star呗

    相关文章

      网友评论

        本文标题:CIDetector 边缘识别

        本文链接:https://www.haomeiwen.com/subject/fngpvxtx.html