Перевести обнаруженный прямоугольник из портрета CIImage в ландшафт CIImage

Я изменяю код, найденный здесь. В коде мы снимаем видео с камеры телефона, используя AVCaptureSession и используя CIDetector для обнаружения прямоугольника в канале изображения. В ленте есть изображение размером 640x842 (iphone5 в портретной ориентации). Затем мы делаем наложение на изображение, чтобы пользователь мог видеть обнаруженный прямоугольник (на самом деле это трапеция в большинстве случаев).

Когда пользователь нажимает кнопку в пользовательском интерфейсе, мы снимаем изображение с видео и повторно запускаем обнаружение прямоугольника на этом увеличенном изображении (3264x2448), которое, как вы можете видеть, является пейзажным. Затем мы делаем перспективное преобразование на обнаруженном прямоугольнике и обрезаем изображение.

Это работает довольно хорошо, но проблема, с которой я столкнулся, заключается в том, что 1 из 5 захватывает обнаруженный прямоугольник на большем изображении и отличается от обнаруженного (и представленного пользователю) от меньшего. Даже при том, что я только делаю снимок, когда я обнаруживаю, что телефон (относительно) все еще, окончательное изображение тогда не представляет прямоугольник, ожидаемый пользователем.

Чтобы решить эту проблему, моя идея состоит в том, чтобы использовать координаты первоначально захваченного прямоугольника и перевести их в прямоугольник на захваченном неподвижном изображении. Вот где я борюсь.

Я попробовал это с обнаруженным прямоугольником:

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);

Итак, учитывая обнаруженный прямоугольник:

TopLeft: 88.213425, 632.31329 TopRight: 545.59302, 632.15546 BottomRight: 575.57819, 369.22321 BottomLeft: 49.973862, 369.40466

Теперь у меня есть этот повернутый прямоугольник:

origin = (x = 369.223206, y = -575.578186) размер = (ширина = 263.090088, высота = 525.604309)

Как перевести повернутые координаты прямоугольника на меньшем портретном изображении в координаты к изображению 3264x2448?

Отредактируйте Дух.. читая мой собственный подход, я понял, что создание прямоугольника из трапеции не решит мою проблему!

Вспомогательный код для обнаружения прямоугольника и т.д...

// 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 ответ

У меня была такая же проблема, когда я делал подобные вещи. Я решил ее, выполнив код ниже в swift. Посмотрите, может ли это помочь вам.

 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)
            }
        }
Другие вопросы по тегам