3

我正在开发一个应用程序来检测实时摄像机源中的矩形并突出显示检测到的矩形。我使用AVFoundation并使用了以下方法进行了相机操作,以检测和突出显示检测到的矩形。

var detector: CIDetector?;

override func viewDidLoad() {
    super.viewDidLoad();

    detector = self.prepareRectangleDetector();
}

func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) { // re check this method

    // Need to shimmy this through type-hell
    let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)

    // Force the type change - pass through opaque buffer
    let opaqueBuffer = Unmanaged<CVImageBuffer>.passUnretained(imageBuffer!).toOpaque()
    let pixelBuffer = Unmanaged<CVPixelBuffer>.fromOpaque(opaqueBuffer).takeUnretainedValue()

    let sourceImage = CIImage(CVPixelBuffer: pixelBuffer, options: nil)

    // Do some detection on the image
    self.performRectangleDetection(sourceImage);

    var outputImage = sourceImage

    // Do some clipping
    var drawFrame = outputImage.extent
    let imageAR = drawFrame.width / drawFrame.height
    let viewAR = videoDisplayViewBounds.width / videoDisplayViewBounds.height

    if imageAR > viewAR {
        drawFrame.origin.x += (drawFrame.width - drawFrame.height * viewAR) / 2.0
        drawFrame.size.width = drawFrame.height / viewAR
    } else {
        drawFrame.origin.y += (drawFrame.height - drawFrame.width / viewAR) / 2.0
        drawFrame.size.height = drawFrame.width / viewAR
    }

    //videoDisplayView is a GLKView which is used to display camera feed
    videoDisplayView.bindDrawable()
    if videoDisplayView.context != EAGLContext.currentContext() {
        EAGLContext.setCurrentContext(videoDisplayView.context)
    }

    // clear eagl view to grey
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(0x00004000)

    // set the blend mode to "source over" so that CI will use that
    glEnable(0x0BE2);
    glBlendFunc(1, 0x0303);

    renderContext.drawImage(outputImage, inRect: videoDisplayViewBounds, fromRect: drawFrame);

    videoDisplayView.display();

}

func prepareRectangleDetector() -> CIDetector {

    let options: [String: AnyObject] = [CIDetectorAccuracy: CIDetectorAccuracyHigh];
    return CIDetector(ofType: CIDetectorTypeRectangle, context: nil, options: options);
}

func performRectangleDetection(image: CIImage){

    let resultImage: CIImage? = nil;

    if let detector = detector {

        // Get the detections
        let features = detector.featuresInImage(image, options: [CIDetectorAspectRatio:NSNumber(float:1.43)]);


        if features.count != 0{ // feature found

            for feature in features as! [CIRectangleFeature] {

                self.previewImageView.layer.sublayers = nil;

                let line: CAShapeLayer = CAShapeLayer();
                line.frame = self.videoDisplayView.bounds;
                let linePath: UIBezierPath = UIBezierPath();

                linePath.moveToPoint(feature.topLeft);
                linePath.addLineToPoint(feature.topRight);
                linePath.addLineToPoint(feature.bottomRight);
                linePath.addLineToPoint(feature.bottomLeft);
                linePath.addLineToPoint(feature.topLeft);
                linePath.closePath();

                line.lineWidth = 5.0;
                line.path = linePath.CGPath;
                line.fillColor = UIColor.clearColor().CGColor;
                line.strokeColor = UIColor(netHex: 0x3399CC, alpha: 1.0).CGColor;

                // videoDisplayParentView is the parent of videoDisplayView and they both have same bounds
                self.videoDisplayParentView.layer.addSublayer(line);
             }    
         }                    
     }
}

我用CAShapeLayerandUIBezierPath来绘制矩形。这是非常非常缓慢的。几分钟后路径变得可见。

有人可以帮我弄清楚为什么它很慢,或者让我知道我在这里做错了什么。任何帮助将不胜感激。

或者,如果有比这更简单的方法,我也想知道。

4

1 回答 1

0

如果您从事将子层添加到 GLKView 的业务,那将会很慢。这里的GLKView每秒刷新多次(就像在captureOutput:didOutputSampleBuffer:..方法中一样),每次创建和添加子层的过程都会跟不上。

更好的方法是使用 CoreImage 绘制路径并将其合成到 resultImage。

于 2017-01-24T21:59:17.413 回答