我在使用该方法时遇到了奇怪的行为
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:)
时做错了什么,或者这是苹果端的一个错误。
有什么想法吗?
这里发生的事情是,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
)