Преобразование точек VNRectangleObservation в другую систему координат

Мне нужно преобразовать полученные VNRectangleObservation CGPoints (bottomLeft, bottomRight, topLeft, topRight) в другую систему координат (например, координату представления на экране).

Я определяю запрос:

    // Rectangle Request
    let rectangleDetectionRequest = VNDetectRectanglesRequest(completionHandler: handleRectangles)
    rectangleDetectionRequest.minimumSize = 0.5
    rectangleDetectionRequest.maximumObservations = 1

Я получаю sampleBuffer из камеры при вызове делегата и выполняю запрос обнаружения:

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {

    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {return}
    var requestOptions:[VNImageOption:Any] = [:]
    if let cameraIntrinsicData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) {
        requestOptions = [.cameraIntrinsics:cameraIntrinsicData]
    }
    let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: CGImagePropertyOrientation(rawValue:6)!, options: requestOptions)
    do {
        try imageRequestHandler.perform(self.requests)
    } catch {
        print(error)
    }

}

Позже в завершенииHandler я получаю результаты:

func handleRectangles (request:VNRequest, error:Error?) {

     guard let results = request.results as? [VNRectangleObservation] else { return }

     let flipTransform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -self.previewView.frame.height)
     let scaleTransform = CGAffineTransform.identity.scaledBy(x: self.previewView.frame.width, y: self.previewView.frame.height)

     for rectangle in results {
        let rectangleBounds = rectangle.boundingBox.applying(scaleTransform).applying(flipTransform)
        // convertedTopLeft = conversion(rectangle.topLeft) 
        // convertedTopRight = conversion(rectangle.topRight) 
        // convertedBottomLeft = conversion(rectangle.bottomLeft) 
        // convertedBottomRight = conversion(rectangle.bottomRight) 
    }
}

Это работает для boundingBox, который является CGRect, но вместо этого мне нужно преобразовать CGPoints в систему координат другого представления. Проблема в том, что я не знаю, как получить преобразование из системы координат sampleBuffer: CMSampleBuffer в систему координат previewView.

Спасибо!


person mihaicris    schedule 21.12.2017    source источник


Ответы (3)


Это был просто вопрос применения преобразования к самой CGPoint, где size — это CGSize целевого представления, для которого мне нужно транспонировать четыре точки.

    let transform = CGAffineTransform.identity
        .scaledBy(x: 1, y: -1)
        .translatedBy(x: 0, y: -size.height)
        .scaledBy(x: size.width, y: size.height)

    let convertedTopLeft = rectangle.topLeft.applying(transform)
    let convertedTopRight = rectangle.topRight.applying(transform)
    let convertedBottomLeft = rectangle.bottomLeft.applying(transform)
    let convertedBottomRight = rectangle.bottomRight.applying(transform)
person mihaicris    schedule 18.01.2018
comment
это прекрасно, но как мне снова удалить это преобразование, немного изменив его углы? Мне нужно снова передать эти точки в CIPerspectiveCorrection. - person Ameet Dhas; 16.10.2018

Ответ @mihaicris работает, но только в портретном режиме. В ландшафте нам нужно сделать это немного по-другому.

if UIApplication.shared.statusBarOrientation.isLandscape {
    transform = CGAffineTransform.identity
        .scaledBy(x: -1, y: 1)
        .translatedBy(x: -size.width, y: 0)
        .scaledBy(x: size.width, y: size.height)
} else {
    transform = CGAffineTransform.identity
        .scaledBy(x: 1, y: -1)
        .translatedBy(x: 0, y: -size.height)
        .scaledBy(x: size.width, y: size.height)
}

let convertedTopLeft = rectangle.topLeft.applying(transform)
let convertedTopRight = rectangle.topRight.applying(transform)
let convertedBottomLeft = rectangle.bottomLeft.applying(transform)
let convertedBottomRight = rectangle.bottomRight.applying(transform)
person heyfrank    schedule 06.03.2019

Я предполагаю, что вы используете слой для камеры, и это слой AVCaptureVideoPreviewLayer. (https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer). Поэтому, если вы хотите преобразовать одну точку, используйте эту функцию:layerPointConverted (https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer/1623502-layerpointconverted). Обратите внимание, что y инвертирован из-за системы координат VNRectangleObservation.

let convertedTopLeft: CGPoint = cameraLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: rectangle.topLeft.x, y: 1 - rectangle.topLeft.y))
let convertedTopRight: CGPoint = cameraLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: rectangle.topRight.x, y: 1 - rectangle.topRight.y))
let convertedBottomLeft: CGPoint = cameraLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: rectangle.bottomLeft.x, y: 1 - rectangle.bottomLeft.y))
let convertedBottomRight: CGPoint = cameraLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: rectangle.bottomRight.x, y: 1 - rectangle.bottomRight.y))

Надеюсь, это помогло

person user3699466    schedule 09.01.2018
comment
Спасибо, я проверю ваш ответ в своем коде, потому что это может быть лучшим решением для компенсации свойства точки гравитации аспектного заполнения слоя предварительного просмотра. - person mihaicris; 19.01.2018
comment
Круто, отпишись если помогло - person user3699466; 21.01.2018
comment
Привет, я попробовал метод layerPointConverted, но он не работает должным образом. При вводе точек в качестве углов координат устройства захвата (0,0 - 1,0 - 0,1 - 1,1) преобразованные точки x координаты выходят за рамки конечного вида. Похоже, что метод не принимает во внимание свойство видеогравитации аспектаFill для предварительного просмотра (которое точно соответствует размеру экрана, а не больше). Я думал, что эта функция умеет компенсировать смещение.. - person mihaicris; 31.01.2018
comment
@mihaicris У меня та же проблема, координаты x не в кадре назначения. Но если вы перейдете к документации Apple (developer.apple.com/documentation/avfoundation /), в нем говорится, что преобразование, выполняемое этим методом, учитывает размер кадра слоя и свойство videoGravity получателя. Я изучу эту проблему и посмотрю, смогу ли я понять, что происходит - person kikettas; 16.08.2018