将检测到的矩形从纵向 CIImage 转换为横向 CIImage

Posted

技术标签:

【中文标题】将检测到的矩形从纵向 CIImage 转换为横向 CIImage【英文标题】:Translate detected rectangle from portrait CIImage to landscape CIImage 【发布时间】:2017-03-24 05:19:35 【问题描述】:

我正在修改找到here 的代码。在代码中,我们使用 AVCaptureSession 从手机摄像头捕获视频,并使用 CIDetector 检测图像馈送中的矩形。提要有一个 640x842 的图像(iphone5 纵向)。然后我们在图像上进行叠加,以便用户可以看到检测到的矩形(实际上它大部分时间都是梯形)。

当用户按下 UI 上的按钮时,我们会从视频中捕获图像,然后在这个较大的图像 (3264x2448) 上重新运行矩形检测,您可以看到它是横向的。然后我们对检测到的矩形进行透视变换并裁剪图像。

这工作得很好,但我遇到的问题是,5 个中的 1 个捕获较大图像上检测到的矩形与从较小图像中检测到(并呈现给用户)的矩形不同。尽管我仅在检测到手机(相对)静止时才捕获,但最终图像并不代表用户期望的矩形。

为了解决这个问题,我的想法是使用最初捕获的矩形的坐标并将它们转换为捕获的静止图像上的矩形。这就是我挣扎的地方。

我用检测到的矩形尝试了这个:

CGFloat radians = -90 * (M_PI/180);
CGAffineTransform rotation = CGAffineTransformMakeRotation(radians);

CGRect rect = CGRectMake(detectedRect.bounds.origin.x, detectedRect.bounds.origin.y, detectedRect.bounds.size.width, detectedRect.bounds.size.height);

CGRect rotatedRect = CGRectApplyAffineTransform(rect, rotation);

所以给定一个检测到的矩形:

左上角:88.213425、632.31329 右上角:545.59302、632.15546 右下角:575.57819、369.22321 左下:49.973862、369.40466

我现在有了这个旋转的矩形:

原点 = (x = 369.223206, y = -575.578186) 尺寸=(宽度=263.090088,高度=525.604309)

如何将较小纵向图像中的旋转矩形坐标转换为 3264x2448 图像的坐标?

编辑 Duh.. 阅读我自己的方法后发现,用梯形创建一个矩形并不能解决我的问题!

支持代码检测矩形等...

// In this method we detect a rect from the video feed and overlay

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);

    CIImage *image = [CIImage imageWithCVPixelBuffer:pixelBuffer];

   // image is 640x852 on iphone5

    NSArray *rects = [[CIDetector detectorOfType:CIDetectorTypeRectangle context:nil options:@CIDetectorAccuracy : CIDetectorAccuracyHigh] featuresInImage:image];

    CIRectangleFeature *detectedRect = rects[0]; 

    // draw overlay on image code....

这是如何获得静止图像的总结版本:

// code block to handle output from AVCaptureStillImageOutput
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
     
         NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
         CIImage *enhancedImage = [[CIImage alloc] initWithData:imageData options:@kCIImageColorSpace:[NSNull null]];
             imageData = nil;

         CIRectangleFeature *rectangleFeature = [self getDetectedRect:[[self highAccuracyRectangleDetector] featuresInImage:enhancedImage]];

         if (rectangleFeature) 
             enhancedImage = [self   correctPerspectiveForImage:enhancedImage withTopLeft:rectangleFeature.topLeft andTopRight:rectangleFeature.topRight andBottomRight:rectangleFeature.bottomRight andBottomLeft:rectangleFeature.bottomLeft];
         
    

谢谢。

【问题讨论】:

【参考方案1】:

我在做这种事情时遇到了同样的问题。我已经通过快速执行以下代码解决了这个问题。看看它是否可以帮助你。

 if let videoConnection = stillImageOutput.connection(withMediaType: AVMediaTypeVideo) 
            stillImageOutput.captureStillImageAsynchronously(from: videoConnection) 
                (imageDataSampleBuffer, error) -> Void in
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
                var img = UIImage(data: imageData!)!

                let outputRect = self.previewLayer?.metadataOutputRectOfInterest(for: (self.previewLayer?.bounds)!)
                let takenCGImage = img.cgImage
                let width = (takenCGImage?.width)!
                let height = (takenCGImage?.height)!
                let cropRect = CGRect(x: (outputRect?.origin.x)! * CGFloat(width), y: (outputRect?.origin.y)! * CGFloat(height), width: (outputRect?.size.width)! * CGFloat(width), height: (outputRect?.size.height)! * CGFloat(height))
                let cropCGImage = takenCGImage!.cropping(to: cropRect)
                img = UIImage(cgImage: cropCGImage!, scale: 1, orientation: img.imageOrientation)

                let cropViewController = TOCropViewController(image: self.cropToBounds(image: img))
                cropViewController.delegate = self
                self.navigationController?.pushViewController(cropViewController, animated: true)
            
        

【讨论】:

感谢您的发帖,但我不清楚 metadataOutputRectOfInterest 是否与 takeCIImage 的方向不同

以上是关于将检测到的矩形从纵向 CIImage 转换为横向 CIImage的主要内容,如果未能解决你的问题,请参考以下文章

将 UIView 坐标从纵向转换为横向,反之亦然

从 PHAsset 获取视频时如何检测视频是不是为横向/纵向?

检测“samsung galaxy Android 2.3.5”的方向(横向和纵向模式)的事件

将应用程序转换为 IPAD 时如何保持横向或纵向模式?

将纵向模式转换为横向模式时的 iPad 设计问题

Twain 检测横向扫描