将 Vision boundingBox 从 VNFaceObservation 转换为矩形以在图像上绘制
Convert Vision boundingBox from VNFaceObservation to rect to draw on image
我正在尝试使用新 Vision
API 中的 VNDetectFaceRectanglesRequest
来检测图像上的人脸。然后,我在每个检测到的脸上画一个红色矩形。
但是我在将 boundingBox
从 VNFaceObservation
转换为 CGRect
时遇到问题。看来我唯一的问题是 y origin。
这是我的代码:
let request=VNDetectFaceRectanglesRequest{request, error in
var final_image=UIImage(ciImage: image)
if let results=request.results as? [VNFaceObservation]{
for face_obs in results{
UIGraphicsBeginImageContextWithOptions(final_image.size, false, 1.0)
final_image.draw(in: CGRect(x: 0, y: 0, width: final_image.size.width, height: final_image.size.height))
var rect=face_obs.boundingBox
/*/*/*/ RESULT 2 is when I uncomment this line to "flip" the y /*/*/*/
//rect.origin.y=1-rect.origin.y
let conv_rect=CGRect(x: rect.origin.x*final_image.size.width, y: rect.origin.y*final_image.size.height, width: rect.width*final_image.size.width, height: rect.height*final_image.size.height)
let c=UIGraphicsGetCurrentContext()!
c.setStrokeColor(UIColor.red.cgColor)
c.setLineWidth(0.01*final_image.size.width)
c.stroke(conv_rect)
let result=UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
final_image=result!
}
}
DispatchQueue.main.async{
self.image_view.image=final_image
}
}
let handler=VNImageRequestHandler(ciImage: image)
DispatchQueue.global(qos: .userInteractive).async{
do{
try handler.perform([request])
}catch{
print(error)
}
}
这是目前的结果。
结果 1(不翻转 y)
结果 2(翻转 y)
解决方案
我自己找到了 rect 的解决方案。
let rect=face_obs.boundingBox
let x=rect.origin.x*final_image.size.width
let w=rect.width*final_image.size.width
let h=rect.height*final_image.size.height
let y=final_image.size.height*(1-rect.origin.y)-h
let conv_rect=CGRect(x: x, y: y, width: w, height: h)
但是,我将@wei-jay 的回答标记为好回答,因为它更优雅。
你必须根据图像进行过渡和缩放。
Example
func drawVisionRequestResults(_ results: [VNFaceObservation]) {
print("face count = \(results.count) ")
previewView.removeMask()
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -self.view.frame.height)
let translate = CGAffineTransform.identity.scaledBy(x: self.view.frame.width, y: self.view.frame.height)
for face in results {
// The coordinates are normalized to the dimensions of the processed image, with the origin at the image's lower-left corner.
let facebounds = face.boundingBox.applying(translate).applying(transform)
previewView.drawLayer(in: facebounds)
}
}
我尝试了多种方法,以下是最适合我的方法:
dispatch_async(dispatch_get_main_queue(), ^{
VNDetectedObjectObservation * newObservation = request.results.firstObject;
if (newObservation) {
self.lastObservation = newObservation;
CGRect transformedRect = newObservation.boundingBox;
CGRect convertedRect = [self.previewLayer rectForMetadataOutputRectOfInterest:transformedRect];
self.highlightView.frame = convertedRect;
}
});
var rect = CGRect()
rect.size.height = viewSize.height * boundingBox.width
rect.size.width = viewSize.width * boundingBox.height
rect.origin.x = boundingBox.origin.y * viewSize.width
rect.origin.y = boundingBox.origin.x * viewSize.height
有一些内置方法可以为您完成。
要从规范化形式转换,请使用:
func VNImageRectForNormalizedRect(_ normalizedRect: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGRect
反之亦然:
func VNNormalizedRectForImageRect(_ imageRect: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGRect
积分的类似方法:
func VNNormalizedFaceBoundingBoxPointForLandmarkPoint(_ faceLandmarkPoint: vector_float2, _ faceBoundingBox: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGPoint
func VNImagePointForNormalizedPoint(_ normalizedPoint: CGPoint, _ imageWidth: Int, _ imageHeight: Int) -> CGPoint
我正在尝试使用新 Vision
API 中的 VNDetectFaceRectanglesRequest
来检测图像上的人脸。然后,我在每个检测到的脸上画一个红色矩形。
但是我在将 boundingBox
从 VNFaceObservation
转换为 CGRect
时遇到问题。看来我唯一的问题是 y origin。
这是我的代码:
let request=VNDetectFaceRectanglesRequest{request, error in
var final_image=UIImage(ciImage: image)
if let results=request.results as? [VNFaceObservation]{
for face_obs in results{
UIGraphicsBeginImageContextWithOptions(final_image.size, false, 1.0)
final_image.draw(in: CGRect(x: 0, y: 0, width: final_image.size.width, height: final_image.size.height))
var rect=face_obs.boundingBox
/*/*/*/ RESULT 2 is when I uncomment this line to "flip" the y /*/*/*/
//rect.origin.y=1-rect.origin.y
let conv_rect=CGRect(x: rect.origin.x*final_image.size.width, y: rect.origin.y*final_image.size.height, width: rect.width*final_image.size.width, height: rect.height*final_image.size.height)
let c=UIGraphicsGetCurrentContext()!
c.setStrokeColor(UIColor.red.cgColor)
c.setLineWidth(0.01*final_image.size.width)
c.stroke(conv_rect)
let result=UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
final_image=result!
}
}
DispatchQueue.main.async{
self.image_view.image=final_image
}
}
let handler=VNImageRequestHandler(ciImage: image)
DispatchQueue.global(qos: .userInteractive).async{
do{
try handler.perform([request])
}catch{
print(error)
}
}
这是目前的结果。
结果 1(不翻转 y)
结果 2(翻转 y)
解决方案
我自己找到了 rect 的解决方案。
let rect=face_obs.boundingBox
let x=rect.origin.x*final_image.size.width
let w=rect.width*final_image.size.width
let h=rect.height*final_image.size.height
let y=final_image.size.height*(1-rect.origin.y)-h
let conv_rect=CGRect(x: x, y: y, width: w, height: h)
但是,我将@wei-jay 的回答标记为好回答,因为它更优雅。
你必须根据图像进行过渡和缩放。 Example
func drawVisionRequestResults(_ results: [VNFaceObservation]) {
print("face count = \(results.count) ")
previewView.removeMask()
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -self.view.frame.height)
let translate = CGAffineTransform.identity.scaledBy(x: self.view.frame.width, y: self.view.frame.height)
for face in results {
// The coordinates are normalized to the dimensions of the processed image, with the origin at the image's lower-left corner.
let facebounds = face.boundingBox.applying(translate).applying(transform)
previewView.drawLayer(in: facebounds)
}
}
我尝试了多种方法,以下是最适合我的方法:
dispatch_async(dispatch_get_main_queue(), ^{
VNDetectedObjectObservation * newObservation = request.results.firstObject;
if (newObservation) {
self.lastObservation = newObservation;
CGRect transformedRect = newObservation.boundingBox;
CGRect convertedRect = [self.previewLayer rectForMetadataOutputRectOfInterest:transformedRect];
self.highlightView.frame = convertedRect;
}
});
var rect = CGRect()
rect.size.height = viewSize.height * boundingBox.width
rect.size.width = viewSize.width * boundingBox.height
rect.origin.x = boundingBox.origin.y * viewSize.width
rect.origin.y = boundingBox.origin.x * viewSize.height
有一些内置方法可以为您完成。 要从规范化形式转换,请使用:
func VNImageRectForNormalizedRect(_ normalizedRect: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGRect
反之亦然:
func VNNormalizedRectForImageRect(_ imageRect: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGRect
积分的类似方法:
func VNNormalizedFaceBoundingBoxPointForLandmarkPoint(_ faceLandmarkPoint: vector_float2, _ faceBoundingBox: CGRect, _ imageWidth: Int, _ imageHeight: Int) -> CGPoint
func VNImagePointForNormalizedPoint(_ normalizedPoint: CGPoint, _ imageWidth: Int, _ imageHeight: Int) -> CGPoint