CGImage.crop(to:) 在 MacOS 上返回奇怪的裁剪

问题描述 投票:0回答:1

我在使用该方法时遇到了奇怪的行为

CGImage.crop(to:)

我的目标是使用苹果视觉框架裁剪用户脸部,以训练基于人工智能的模型,但是在

utkface
数据集上运行视觉时,我得到了完全奇怪的裁剪,请参阅上面的示例。

这是相关代码:


        let image = NSImage(byReferencingFile: imagePath)!
        let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)!
        
        let visionRequest = VNDetectFaceRectanglesRequest()

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: .up, options: [:])
        do {
            try await handler.perform([visionRequest])
        } catch {
            print("Failed ... \(error.localizedDescription)")
            return
        }

        let observations = visionRequest.results?
            .filter {
                $0.confidence >= request.faceCaptureThreshold &&
                ($0.boundingBox.size.width >= 0.1 || $0.boundingBox.size.height >= 0.1)
            } ?? []

        for (index, observation) in observations.enumerated() {
            let normalizedBoundingBox = observation.boundingBox
            let boundingBox = VNImageRectForNormalizedRect(normalizedBoundingBox, cgImage.width, cgImage.height)
            let croppedImage = cgImage.cropping(to: boundingBox)!
            // Redacted: store croppedImage on Disk
        }

在调试时,我发现一切都很顺利,直到函数

crop(to:)
被调用,这很奇怪,因为当我使用 CoreImage 相关函数在原始图像上方绘制一个矩形时,该矩形位于正确的位置,但作物完全不同。

我能够解决这个问题,使用

CoreImage
重新创建图像,例如:

            let croppedImage = DrawImageInCGContext(size: boundingBox.size) { (context) -> () in
                context.draw(cgImage, in: .init(origin: .init(x: -boundingBox.minX, y: -boundingBox.minY), size: CGSize(width: cgImage.width, height: cgImage.height)), byTiling: true)
            }

但是我不明白我在使用

CGImage.crop(to:)
时做错了什么,或者这是苹果端的一个错误。

有什么想法吗?

Original Image

Image with rect

Weird Crop

swift macos image-processing cocoa ios-vision
1个回答
0
投票

这里发生的事情是,macOS 使用不同的坐标系,从左下角开始,而不是像 iOS 那样从左上角开始。但是

CGImage.crop(to:)
期望基于左上角的矩形来裁剪图像,因此需要进行翻译才能正确裁剪它。

一个小小的改变就足以解决这个问题:

            let normalizedBoundingBox = observation.boundingBox
            let boundingBox = VNImageRectForNormalizedRect(normalizedBoundingBox, cgImage.width, cgImage.height)
            
            let flippedY = CGFloat(cgImage.height) - boundingBox.maxY
            
            let macOSBoundingBox = CGRect(
                origin: .init(x: boundingBox.minX, y: flippedY),
                size: boundingBox.size
            )
© www.soinside.com 2019 - 2024. All rights reserved.