La Détection de visage avec l'Appareil-photo
Comment puis-je faire face à la détection en temps réel de même que la "Caméra" n'?
J'ai remarqué que AVCaptureStillImageOutput est obsolète après 10.0, donc j'utilise
AVCapturePhotoOutput à la place. Toutefois, je trouve que l'image que j'ai enregistré pour la détection de visage n'est pas satisfait? Des idées?
Mise à JOUR
Après avoir essayer de @Shravya Boggarapu mentionné. Actuellement, j'utilise AVCaptureMetadataOutput
pour détecter le visage sans CIFaceDetector
. Il fonctionne comme prévu. Cependant, quand je suis en train de dessiner les limites de la face, il semble mislocated. Une idée?
let metaDataOutput = AVCaptureMetadataOutput()
captureSession.sessionPreset = AVCaptureSessionPresetPhoto
let backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
do {
let input = try AVCaptureDeviceInput(device: backCamera)
if (captureSession.canAddInput(input)) {
captureSession.addInput(input)
//MetadataOutput instead
if(captureSession.canAddOutput(metaDataOutput)) {
captureSession.addOutput(metaDataOutput)
metaDataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metaDataOutput.metadataObjectTypes = [AVMetadataObjectTypeFace]
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.frame = cameraView.bounds
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
cameraView.layer.addSublayer(previewLayer!)
captureSession.startRunning()
}
}
} catch {
print(error.localizedDescription)
}
et
extension CameraViewController: AVCaptureMetadataOutputObjectsDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if findFaceControl {
findFaceControl = false
for metadataObject in metadataObjects {
if (metadataObject as AnyObject).type == AVMetadataObjectTypeFace {
print("😇😍😎")
print(metadataObject)
let bounds = (metadataObject as! AVMetadataFaceObject).bounds
print("origin x: \(bounds.origin.x)")
print("origin y: \(bounds.origin.y)")
print("size width: \(bounds.size.width)")
print("size height: \(bounds.size.height)")
print("cameraView width: \(self.cameraView.frame.width)")
print("cameraView height: \(self.cameraView.frame.height)")
var face = CGRect()
face.origin.x = bounds.origin.x * self.cameraView.frame.width
face.origin.y = bounds.origin.y * self.cameraView.frame.height
face.size.width = bounds.size.width * self.cameraView.frame.width
face.size.height = bounds.size.height * self.cameraView.frame.height
print(face)
showBounds(at: face)
}
}
}
}
}
Original
var captureSession = AVCaptureSession()
var photoOutput = AVCapturePhotoOutput()
var previewLayer: AVCaptureVideoPreviewLayer?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
captureSession.sessionPreset = AVCaptureSessionPresetHigh
let backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do {
let input = try AVCaptureDeviceInput(device: backCamera)
if (captureSession.canAddInput(input)) {
captureSession.addInput(input)
if(captureSession.canAddOutput(photoOutput)){
captureSession.addOutput(photoOutput)
captureSession.startRunning()
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
previewLayer?.frame = cameraView.bounds
cameraView.layer.addSublayer(previewLayer!)
}
}
} catch {
print(error.localizedDescription)
}
}
func captureImage() {
let settings = AVCapturePhotoSettings()
let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType
]
settings.previewPhotoFormat = previewFormat
photoOutput.capturePhoto(with: settings, delegate: self)
}
func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
if let error = error {
print(error.localizedDescription)
}
//Not include previewPhotoSampleBuffer
if let sampleBuffer = photoSampleBuffer,
let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: nil) {
self.imageView.image = UIImage(data: dataImage)
self.imageView.isHidden = false
self.previewLayer?.isHidden = true
self.findFace(img: self.imageView.image!)
}
}
La findFace
fonctionne avec une image normale. Cependant, l'image que j'ai capturer par l'intermédiaire de la caméra ne fonctionne pas ou parfois seulement de reconnaître un visage.
Image Normale
De Capture De L'Image
func findFace(img: UIImage) {
guard let faceImage = CIImage(image: img) else { return }
let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy)
//For converting the Core Image Coordinates to UIView Coordinates
let detectedImageSize = faceImage.extent.size
var transform = CGAffineTransform(scaleX: 1, y: -1)
transform = transform.translatedBy(x: 0, y: -detectedImageSize.height)
if let faces = faceDetector?.features(in: faceImage, options: [CIDetectorSmile: true, CIDetectorEyeBlink: true]) {
for face in faces as! [CIFaceFeature] {
//Apply the transform to convert the coordinates
var faceViewBounds = face.bounds.applying(transform)
//Calculate the actual position and size of the rectangle in the image view
let viewSize = imageView.bounds.size
let scale = min(viewSize.width / detectedImageSize.width,
viewSize.height / detectedImageSize.height)
let offsetX = (viewSize.width - detectedImageSize.width * scale) / 2
let offsetY = (viewSize.height - detectedImageSize.height * scale) / 2
faceViewBounds = faceViewBounds.applying(CGAffineTransform(scaleX: scale, y: scale))
print("faceBounds = \(faceViewBounds)")
faceViewBounds.origin.x += offsetX
faceViewBounds.origin.y += offsetY
showBounds(at: faceViewBounds)
}
if faces.count != 0 {
print("Number of faces: \(faces.count)")
} else {
print("No faces 😢")
}
}
}
func showBounds(at bounds: CGRect) {
let indicator = UIView(frame: bounds)
indicator.frame = bounds
indicator.layer.borderWidth = 3
indicator.layer.borderColor = UIColor.red.cgColor
indicator.backgroundColor = .clear
self.imageView.addSubview(indicator)
faceBoxes.append(indicator)
}
- vous devez utiliser
CIDetector
à été détecté le visage. - Voici un lien qui a un exemple d'utilisation de Core Image, détection de visage à partir d'un flux vidéo en direct. C'est à partir de iOS 5 jours, il est donc de toute évidence à la fois daté et dans Objective-C, mais si vous avez travaillé avec CI avant, vous pourriez sans le traduire. icapps.com/face-detection-with-core-image-on-live-video. Désolé, appuyez sur return ne réalisant pas qu'il équivaut à une modification. Voici un second lien pour aider avec l'utilisation de Swift 2 et de l'application CI filtres à un flux de caméra: flexmonkey.blogspot.com/2015/07/...
- Utilisez cet exemple de ici. Cet exemple a vivre de détection pour les rectangles/carrés et qr codes, mais vous pouvez facilement modifier à détecter les visages. Vous pouvez utiliser cet exemple pour changer les superpositions et toutes sortes d'autres trucs aussi, il est très personnalisable. Espérons que cela aide 😀
- Vous êtes forçant un sourire et un clin d'œil le visage en filtrant les résultats à l'aide:
options: [CIDetectorSmile: true, CIDetectorEyeBlink: true]
. Est-ce que vous voulez? Cela pourrait conduire à de mauvais résultats lors de la détection de visages. - J'ai réglé le
options: nil
vous l'avez mentionné, mais elle continue à ne pas fonctionner comme prévu - Voir ma réponse. J'ai testé le code et ça fonctionne.
- voulez-vous répondre à cette question stackoverflow.com/questions/41238781/...
- Je l'ai mise à jour d'un solution avec
Image
cadre avec iOS11. Il vient de woks 😀
Vous devez vous connecter pour publier un commentaire.
Il y a 2 façons d'aller sur la détection des visages: l'Un est CIFaceDetector et l'autre est AVCaptureMetadataOutput
En fonction de vos besoins, choisissez ce qui est pertinent pour vous.
CIFaceDetector a plus de fonctionnalités, par exemple: vous Donne l'emplacement des yeux et de la bouche, détecteur de sourire, etc
D'autre part, AVCaptureMetadataOutput est calculée sur les images et les visages détectés sont suivis et il n'y a pas de code supplémentaire nécessaire pour être ajoutés par nous. Je trouve que, parce que le suivi des visages sont détectés de manière plus fiable dans ce processus. Le con, c'est que vous aurez simplement à détecter les visages, pas de la position des yeux/bouche.
Un autre avantage de cette méthode est que les questions d'orientation sont moins comme vous pouvez le videoOrientation chaque fois que l'appareil change de position et l'orientation de la face va être par rapport à cette orientation
Dans mon cas, mon application utilise YUV420 que le format requis, donc à l'aide d'CIDetector (qui fonctionne avec RVB) en temps réel n'était pas viable. À l'aide de AVCaptureMetadataOutput sauvé beaucoup d'efforts et réalisée de manière plus fiable en raison d'un suivi continu.
Une fois que j'ai eu de la boîte englobante pour le visage, j'ai codé des fonctionnalités supplémentaires, telles que la peau, la détection et l'a appliqué sur l'image.
Remarque: Lors de la capture d'image, le visage de la boîte de l'information est ajoutée avec les métadonnées donc, pas de problèmes de synchronisation.
Vous pouvez également utiliser une combinaison des deux afin d'obtenir de meilleurs résultats.
Faire examiner et d'évaluer les avantages et les inconvénients selon votre demande.
Mise à JOUR
Visage rectangle est wrt image d'origine. Donc, pour l'écran, il peut être différent.
Utiliser les éléments suivants:
metadataObjectTypes
à[AVMetadataObjectTypeFace]
. Aussi,didOutputMetadataObjects
sera appelé après visages trouve. Cependant, comment puis-je dessiner un rectangle sur l'écran?AVCaptureMetadataOutput
, et l'utilisationCIFaceDetector
par la suite avecAVCaptureStillImageOutput
AVCaptureMetadataOutput
, lorsque je capture avecAVCapturePhotoOutput
, alors je veux dessiner le visage de l'emplacement avec le rectangle de l'utilisationCIFaceDetector
, le CIFaceDetector n'a pas fonctionné comme prévu.AVMetadataFaceObject
, mais les limites mislocated, des idées? BTW, j'ai aussi essayé d'utiliserCMSampleBufferGetSampleAttachmentsArray
dansAVCaptureVideoDataOutputSampleBufferDelegate
, mais il semble comme un tableau vide.Pour effectuer la détection de visage sur iOS, il y a soit des CIDetector (Apple)
ou Mobile Vision (Google) de l'API.
De l'OMI, Google Mobile Vision fournit de meilleures performances.
Si vous êtes intéressé, voici le projet que vous pouvez jouer. (iOS 10.2, Swift 3)
Après la WWDC 2017, Apple introduit CoreML dans iOS 11.
Le Vision cadre fait de la détection de visage plus précis 🙂
J'ai fait un Projet De Démonstration. contenant Vision de la c. s. CIDetector. Il contient également face à des monuments de la détection en temps réel.
Assurez-vous de supprimer les vues créées par didOutputMetadataObjects.
Garder la trace de l'actif du visage id est la meilleure façon de le faire ^
Également lorsque vous êtes à essayer de trouver l'emplacement des visages pour votre aperçu de la couche, il est beaucoup plus facile à utiliser du visage de données et de les transformer. Aussi, je pense CIDetector est indésirable, metadataoutput va utiliser la substance matérielle pour la détection de visage qui rend vraiment rapide.
Un peu de retard, mais ici, c'est la solution pour les coordonnées problème. Il y a une méthode que vous pouvez appeler à l'aperçu de la couche de transformer l'objet de métadonnées pour votre système de coordonnées:
transformedMetadataObject
(pour:metadataObject
).Source: https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer/1623501-transformedmetadataobjectformeta
Par la façon dont, dans le cas où vous utilisez (ou de mise à niveau de votre projet de Swift 4, le délégué de la méthode de
AVCaptureMetadataOutputsObject
a changer:Salutations
En regardant ton code, je l'ai détecté 2 choses qui pourrait conduire à un mauvais/pauvres détection de visage.
[CIDetectorSmile: true, CIDetectorEyeBlink: true]
. Essayez de le mettre à néant:faceDetector?.features(in: faceImage, options: nil)
AVCapturePhotoOutput.jpegPhotoDataRepresentation
méthode pour générer de l'image source pour la détection et le système, par défaut, il génère l'image avec une orientation spécifique, de typeLeft
/LandscapeLeft
, je pense. Donc, fondamentalement, vous pouvez dire à la face du détecteur d'avoir cela à l'esprit en utilisant leCIDetectorImageOrientation
clé.Essayer de le définir comme
faceDetector?.features(in: faceImage, options: [CIDetectorImageOrientation: 8 /*Left, bottom*/])
.[CIDetectorSmile: true, CIDetectorEyeBlink: true]
est un filtre. Il raconte détecteur de passer plus de temps alors qu'il est en mesure de rendre un certain nombre d'informations. Elle en élargit les résultatsPour AVCaptureVideoDataOutput créer des paramètres suivants
de sortie.videoSettings = [ kCVPixelBufferPixelFormatTypeKey comme AnyHashable: Int(kCMPixelFormat_32BGRA) ]
3.Lorsque vous recevez CMSampleBuffer, créer une image