如何在swift中使用视觉框架从其特征点中提取外唇
Posted
技术标签:
【中文标题】如何在swift中使用视觉框架从其特征点中提取外唇【英文标题】:How to extract outer lips from its feature point using vision framework in swift 【发布时间】:2020-03-15 16:41:06 【问题描述】:我实现了 addFaceLandmarksToImage 函数来裁剪图像的外唇。 addFaceLandmarksToImage 函数首先使用视觉检测图像上的人脸,将人脸边界框大小和原点转换为图像大小和原点。然后我使用面部标志外唇来获取外唇的归一化点,并通过连接所有归一化点在图像的外唇上画线。 然后我实现了裁剪图像的逻辑。我首先将外唇的归一化点转换为图像坐标,并使用查找点方法获取左、右、顶部和最底部的点,并通过裁剪提取外唇并显示在处理后的图像视图中。 此函数的问题是输出following 与预期不符。此外,如果我使用以下链接中的图像以外的图像,它会裁剪除外唇以外的图像。 我不知道我哪里出错了,是在计算裁剪矩形还是 我应该使用另一种方法(使用 OpenCV 和感兴趣区域 (ROI))来提取外唇来自图像? video of an application
func addFaceLandmarksToImage(_ face: VNFaceObservation)
UIGraphicsBeginImageContextWithOptions(image.size, true, 0.0)
let context = UIGraphicsGetCurrentContext()
// draw the image
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
context?.translateBy(x: 0, y: image.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
// draw the face rect
let w = face.boundingBox.size.width * image.size.width
let h = face.boundingBox.size.height * image.size.height
let x = face.boundingBox.origin.x * image.size.width
let y = face.boundingBox.origin.y * image.size.height
let cropFace = self.image.cgImage?.cropping(to: CGRect(x: x, y: y, width: w, height: h))
let ii = UIImage(cgImage: cropFace!)
// outer lips
context?.saveGState()
context?.setStrokeColor(UIColor.yellow.cgColor)
if let landmark = face.landmarks?.outerLips
var actualCordinates = [CGPoint]()
print(landmark.normalizedPoints)
for i in 0...landmark.pointCount - 1
// last point is 0,0
let point = landmark.normalizedPoints[i]
actualCordinates.append(CGPoint(x: x + CGFloat(point.x) * w, y: y + CGFloat(point.y) * h))
if i == 0
context?.move(to: CGPoint(x: x + CGFloat(point.x) * w, y: y + CGFloat(point.y) * h))
else
context?.addLine(to: CGPoint(x: x + CGFloat(point.x) * w, y: y + CGFloat(point.y) * h))
// Finding left,right,top,buttom point from actual coordinates points[CGPOINT]
let leftMostPoint = self.findPoint(points: actualCordinates, position: .leftMost)
let rightMostPoint = self.findPoint(points: actualCordinates, position: .rightMost)
let topMostPoint = self.findPoint(points: actualCordinates, position: .topMost)
let buttonMostPoint = self.findPoint(points: actualCordinates, position: .buttonMost)
print("actualCordinates:",actualCordinates,
"leftMostPoint:",leftMostPoint,
"rightMostPoint:",rightMostPoint,
"topMostPoint:",topMostPoint,
"buttonMostPoint:",buttonMostPoint)
let widthDistance = -(leftMostPoint.x - rightMostPoint.x)
let heightDistance = -(topMostPoint.y - buttonMostPoint.y)
//Cropping the image.
// self.image is actual image
let cgCroppedImage = self.image.cgImage?.cropping(to: CGRect(x: leftMostPoint.x,y: leftMostPoint.x - heightDistance,width:1000,height: topMostPoint.y + heightDistance + 500))
let jj = UIImage(cgImage: cgCroppedImage!)
self.processedImageView.image = jj
context?.closePath()
context?.setLineWidth(8.0)
context?.drawPath(using: .stroke)
context?.saveGState()
// get the final image
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
// end drawing context
UIGraphicsEndImageContext()
imageView.image = finalImage
图像外唇的归一化点:-
[(0.397705078125, 0.3818359375),
(0.455322265625, 0.390625),
(0.5029296875, 0.38916015625),
(0.548828125, 0.40087890625),
(0.61279296875, 0.3984375),
(0.703125, 0.37890625),
(0.61474609375, 0.21875),
(0.52294921875, 0.1884765625),
(0.431640625, 0.20166015625),
(0.33203125, 0.34423828125)]
图像外唇的实际坐标点:-
[(3025.379819973372, 1344.4951847679913),
(3207.3986613331363, 1372.2607707381248),
(3357.7955853380263, 1367.633173076436),
(3502.7936454042792, 1404.6539543699473),
(3704.8654099646956, 1396.9412916004658),
(3990.2339324355125, 1335.2399894446135),
(3711.035540180281, 829.2893117666245),
(3421.039420047775, 733.6522934250534),
(3132.5858324691653, 775.3006723802537),
(2817.9091914743185, 1225.7201781179756)]
我也尝试使用以下方法,使用 CIDetector 获取嘴巴位置并通过裁剪提取外唇。输出不好。
func focusonMouth()
let ciimage = CIImage(cgImage: image.cgImage!)
let options = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: options)!
let faces = faceDetector.features(in: ciimage)
if let face = faces.first as? CIFaceFeature
if face.hasMouthPosition
let crop = image.cgImage?.cropping(to: CGRect(x: face.mouthPosition.x, y: face.mouthPosition.y, width: face.bounds.width - face.mouthPosition.x , height: 200))
processedImageView.image = imageRotatedByDegrees(oldImage: UIImage(cgImage: crop!), deg: 90)
【问题讨论】:
您使用的裁剪矩形似乎有误。为什么y
使用leftMostPoint.x
?为什么宽度是 1000?我的建议是首先将裁剪矩形绘制为图像上的实际矩形,这样您就可以看到实际计算的内容。
我尝试使用不同的值,但无法找出正确的裁剪矩形。所以我使用了我知道这是非常错误的静态宽度。
请记住,Vision 的坐标在左下角有 (0,0),在右上角有 (1,1)。
@MatthijsHollemans 我应该使用 OpenCV,感兴趣区域 (ROI)) 从图像中提取外唇还是使用适当的数学计算来找到裁剪矩形?
我认为使用正确的计算总是一个好主意。 ;-) 无需使用 OpenCV。您已经拥有所需的一切,您只需确保将视觉坐标转换为图像坐标(这已经在绘图代码中发生)。
【参考方案1】:
有两个问题:
ios 上的输入图像可以用orientation
属性标记旋转方式。 Vision Framework 将完成这项工作,但坐标将被旋转。最简单的解决方案是提供向上(正常旋转)的图像。
定位标志的位置和大小与检测到的面部标志的位置和大小有关。所以找到的位置和大小应该按找到的人脸的大小和偏移量来缩放,而不是整个图像。
【讨论】:
以上是关于如何在swift中使用视觉框架从其特征点中提取外唇的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 中使用 UITextField 从图像中提取特定文本?