Перевести обнаруженный прямоугольник из портрета 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)
}
}