Почему мой Image CIPerspectiveCorrection отличается на каждом устройстве? - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу использовать CIPerspectiveCorrection для изображения, взятого из AVCaptureSession.Но полученное исправленное изображение отличается на другом устройстве, но использует тот же код.Это мой код для получения точек:

targetRectLayer - это слой, в котором я рисую прямоугольник, чтобы выделить сфокусированный прямоугольник.scannerView - это вид, в котором я показываю видеосессию в

let request = VNDetectRectanglesRequest { req, error in
    DispatchQueue.main.async {
        if let observation = req.results?.first as? VNRectangleObservation {
            let points = self.targetRectLayer.drawTargetRect(observation: observation, previewLayer: self.previewLayer, animated: false)
            let size = self.scannerView.frame.size
            self.trackedTopLeftPoint = CGPoint(x: points.topLeft.x / size.width, y: points.topLeft.y / size.height )
            self.trackedTopRightPoint = CGPoint(x: points.topRight.x / size.width, y: points.topRight.y / size.height )
            self.trackedBottomLeftPoint = CGPoint(x: points.bottomLeft.x / size.width, y: points.bottomLeft.y / size.height )
            self.trackedBottomRightPoint = CGPoint(x: points.bottomRight.x / size.width, y: points.bottomRight.y / size.height )
        } else {
            _ = self.targetRectLayer.drawTargetRect(observation: nil, previewLayer: self.previewLayer, animated: false)
        }
    }
}

И

func drawTargetRect(observation: VNRectangleObservation?, previewLayer: AVCaptureVideoPreviewLayer?, animated: Bool) -> (topLeft: CGPoint, topRight: CGPoint, bottomLeft: CGPoint, bottomRight: CGPoint) {
    guard let observation = observation, let previewLayer = previewLayer else {
        draw(path: nil, animated: false)
        return (topLeft: CGPoint.zero, topRight: CGPoint.zero, bottomLeft: CGPoint.zero, bottomRight: CGPoint.zero)
    }

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

    let rectanglePath = UIBezierPath()
    rectanglePath.move(to: convertedTopLeft)
    rectanglePath.addLine(to: convertedTopRight)
    rectanglePath.addLine(to: convertedBottomRight)
    rectanglePath.addLine(to: convertedBottomLeft)
    rectanglePath.close()

    draw(path: rectanglePath, animated: animated)

    return (topLeft: convertedTopLeft, topRight: convertedTopRight, bottomLeft: convertedBottomLeft, bottomRight: convertedBottomRight)
}

. Здесь я ставлю точки на новые позиции, чтобы продолжить движение к CIPerspectiveCorrection:

let imageTopLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomLeftPoint.x, y: trackedBottomLeftPoint.y * image.size.height)
let imageTopRight: CGPoint = CGPoint(x: image.size.width * trackedTopLeftPoint.x, y: trackedTopLeftPoint.y * image.size.height)
let imageBottomLeft: CGPoint = CGPoint(x: image.size.width * trackedBottomRightPoint.x, y: trackedBottomRightPoint.y * image.size.height)
let imageBottomRight: CGPoint = CGPoint(x: image.size.width * trackedTopRightPoint.x, y: trackedTopRightPoint.y * image.size.height)

При применении CIPerspectiveCorrection, декартова система координат учитывается с помощью:

extension UIImage {
   func cartesianForPoint(point:CGPoint,extent:CGRect) -> CGPoint {
       return CGPoint(x: point.x,y: extent.height - point.y)
   }
}

Все остальные математические расчеты основаны на тех 4 self.trackedPoints, которые я установил здесь.Вот несколько фотографий того, что я имею в виду, увидеть области, которые не были обрезаны.Выделенный targetRect отлично нарисован по краям документа.Эти результаты сохраняются на этих устройствах.Все снимки сделаны в portrait под управлением iOS 12.1.3.

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

iPhone X, см. Пространство слева и справа

iphonex

iPad Air 2, см. пробел сверху и снизу

ipadair2

iPhone 5s, именно так я и ожидал их всех iphone5s

1 Ответ

0 голосов
/ 07 февраля 2019

Я обнаружил ошибку конфигурации для свойства videoGravity.Он был установлен на .resizeAspectFill и поэтому выдвигает одну из сторон видео за границу просмотра, чтобы заполнить любое оставленное пространство для другой стороны.И поскольку все устройства предоставляют разные пространства, пустое пространство для компенсации было различным и приводило к описанному поведению при съемке видеопотока в полном разрешении, а не только в видимом.Я слишком сосредоточился на математической части и упустил эту возможность.

Идеальная посадка на iphone5s была абсолютно случайной.

Вот как выглядит исправленный код:

// setup view preview layer
    let previewLayer = AVCaptureVideoPreviewLayer(session: newCaptureSession)
    self.previewLayer = previewLayer
    previewLayer.videoGravity = .resize
    self.scannerView.layer.addSublayer(previewLayer)
    self.scannerView.layer.addSublayer(targetRectLayer)
...