Je ne parviens pas à accéder à la caméra iMac à partir d'un programme OpenCV en ligne de commande. (Je compile et exécute le programme sous CodeRunner, pas Xcode.) J'ai lu que Mojave nécessite NSCameraUsageDescription
dans Info.plist et je pense que je l'incorpore correctement dans le binaire. J'ai ajouté -sectcreate __TEXT __info_plist Info.plist
( dont j'ai entendu parler ici ) pour les drapeaux de compilation et lorsque j'exécute otool -X -s __TEXT __info_plist videotest | xxd -r
(du même article de blog), il affiche:
-?<?xml ve.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>Uses camera to see vision targets</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires to access your microphone in order to access the camera</string>
</dict>
</plist>
(J'ai ajouté NSMicrophoneUsageDescription au cas où il essaierait d'ouvrir le microphone avec la caméra.)
Voici la sortie lorsque j'exécute le programme:
OpenCV version 4.1.0-dev
[ INFO:0] global /Users/steve/Documents/GitHub/ssteve-opencv/modules/videoio/src/videoio_registry.cpp (185) VideoBackendRegistry VIDEOIO: Enabled backends(5, sorted by priority): FFMPEG(1000); GSTREAMER(990); AVFOUNDATION(980); CV_IMAGES(970); CV_MJPEG(960)
[ INFO:0] global /Users/steve/Documents/GitHub/ssteve-opencv/modules/videoio/src/backend_plugin.cpp (248) getPluginCandidates VideoIO pluigin (GSTREAMER): glob is 'libopencv_videoio_gstreamer*.dylib', 1 location(s)
[ INFO:0] global /Users/steve/Documents/GitHub/ssteve-opencv/modules/videoio/src/backend_plugin.cpp (256) getPluginCandidates - /usr/local/lib: 0
[ INFO:0] global /Users/steve/Documents/GitHub/ssteve-opencv/modules/videoio/src/backend_plugin.cpp (259) getPluginCandidates Found 0 plugin(s) for GSTREAMER
OpenCV: not authorized to capture video (status 0), requesting...
OpenCV: camera failed to properly initialize!
Unable to open camera
Cela implique qu'il demande l'accès, mais je n'ai jamais de boîte de dialogue et aucune application n'est répertoriée sous Préférences Système> Sécurité et confidentialité> Appareil photo.
Voici le programme que j'utilise:
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
int main(int argc, char *argv[]) {
cout << "OpenCV version " << CV_VERSION << endl;
VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) {
cerr << "Unable to open camera\n";
return -1;
}
Mat frame;
for (;;) {
cap >> frame;
if (frame.empty()) {
cerr << "Got blank frame\n";
return -1;
}
imshow("Live", frame);
if (waitKey(5) >= 0)
break;
}
return 0;
}
C'est l'invocation du compilateur:
xcrun clang++ -x c++ -lc++ -o "$out" -std=c++11 -I/usr/local/include/opencv4 -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_videoio -lopencv_calib3d -lopencv_aruco -lopencv_xfeatures2d -lopencv_features2d -sectcreate __TEXT __info_plist Info.plist "${files[@]}" "${@:1}"
Quelle pièce du puzzle me manque?
(Je sais que cela est similaire à Impossible d'accéder à la caméra avec opencv sur Mac Mojave mais cette question n'a jamais dépassé un fichier plist mal formé.)
En réponse à la suggestion de s'assurer que ffmpeg voit le périphérique:
$ ffmpeg -hide_banner -f avfoundation -list_devices true -i ""
[AVFoundation input device @ 0x7fed77d16dc0] AVFoundation video devices:
[AVFoundation input device @ 0x7fed77d16dc0] [0] FaceTime HD Camera (Built-in)
[AVFoundation input device @ 0x7fed77d16dc0] [1] Capture screen 0
[AVFoundation input device @ 0x7fed77d16dc0] [2] Capture screen 1
[AVFoundation input device @ 0x7fed77d16dc0] [3] Capture screen 2
[AVFoundation input device @ 0x7fed77d16dc0] AVFoundation audio devices:
[AVFoundation input device @ 0x7fed77d16dc0] [0] Built-in Microphone
Le problème était que le programme c ++, pour une raison quelconque, ne demandait pas l'accès à la caméra. J'ai suivi les conseils de @gerwin dans les commentaires pour l'essayer avec Python. L'exécution de ce programme à partir de Terminal a conduit Terminal à demander l'accès à la caméra. Une fois que j'ai accordé cela, le programme c ++ a pu accéder à la caméra lorsqu'il était exécuté à partir du terminal.
En ce qui concerne CodeRunner, je ne sais pas comment obtenir CodeRunner pour exécuter des programmes Python sous un environnement virtuel, donc je n'ai pas pu exécuter un Python = Programme OpenCV pour qu'il demande l'accès à la caméra. Donc pour le moment je ne peux pas utiliser CodeRunner pour exécuter un programme c ++ qui accède à la caméra.
Ce n'est pas une solution ultime, mais je l'ai résolue en installant une application de terminal qui demande l'accès à votre caméra. Ensuite, votre programme openCv c ++ aura ensuite accès à la caméra FaceTime HD.
par exemple, vous pouvez installer ImageSnap en:
brasser installer imagesnap
imagesnap -w 1 shot.png
Donnez ensuite la permission à la caméra via la fenêtre qui apparaîtra.
Quelques commentaires ici ...
L'erreur que je vois en essayant d'exécuter OpenCV à partir de mon environnement de développement MacOS est:
OpenCV: non autorisé à capturer la vidéo (état 0), demande ... OpenCV: la caméra n'a pas pu s'initialiser correctement! Erreur lors de l'ouverture du flux vidéo ou du fichier. Le programme s'est terminé avec le code de sortie: 255
Je sais que ces mots proviennent de la bibliothèque OpenCV ici. Ma pensée initiale était que c'était un problème OpenCV. Avec un peu plus de tests, je pense que c'est autre chose. Comme d'autres l'ont noté, problème de sécurité/autorisations pour MacOS. Mais voici le hic.
Si je vais sur Mac Apple (coin supérieur gauche) -> Préférences systèmes -> Sécurité et confidentialité, je peux glaner beaucoup d'informations.
Vérifiez l'icône de l'appareil photo.
Dans mon cas, cela montre deux applications qui nécessitent des autorisations supplémentaires pour accéder à la caméra, Terminal et Virtualbox (vous ne savez pas ce qui arrive au navigateur, Facetime?) Je note, Xcode n'a pas fait cette liste.
Lorsque je clique sur Microphone, je vois différentes applications répertoriées, Y COMPRIS Xcode.
Comment ça marche même? J'ai fait beaucoup de tests, y compris des recherches sur la modification de Info.plist pour le package d'application Xcode (Finder -> Dossier Applications -> Xcode -> Rt click, Afficher le contenu du package. Copiez Info.plist, enregistrez-le ailleurs, modifiez-le via Xcode, soumettez à nouveau.) Remarque: N'essayez pas ceci sans conserver une copie de l'Info.plist d'origine. Échec total. L'ajout de la clé/valeur NSCameraUsageDescription
a été un échec total. Xcode ne s'ouvrira pas du tout. Rappel NE perdez PAS l'Info.plist d'origine.
Tout cela est déroutant. Pourquoi Apple nous permet-il d'accéder à la caméra via un terminal mais pas dans Xcode? Quelle est la logique là-bas?
Je voudrais certainement pouvoir parcourir le code pour comprendre les problèmes de conception possibles image par image. Ce n'est tout simplement pas amusant.
Donc, deux ou trois choses à comprendre.
Oui, vous pouvez exécuter un projet OpenCV sur MacOS AVEC votre appareil photo après que le programme a été compilé avec succès vers Unix Executable. Vous devez vous assurer que les autorisations pour le terminal sont définies dans Sécurité et confidentialité par photo ci-dessus. Évidemment, vous construisez l'exécutable dans votre outil de développement (dans mon cas Xcode) puis ouvrez l'exécutable à partir du dossier Build/Debug du projet. L'application s'ouvre dans la fenêtre du terminal et fonctionne très bien comme l'a noté SSteve.
Si vous voulez vraiment faire un débogage vidéo/caméra, vous avez la possibilité de "pré-enregistrer" une vidéo, puis ouvrez cette vidéo dans votre environnement de développement. À ce stade, vous pouvez utiliser le débogueur. Comment procédez-vous analyse image par image? C'est le seul moyen que je connaisse qui fonctionnera au moins partiellement.
(modifier la mise à jour 22/05/19 ...) Whoa. Je viens de réaliser .. vous pouvez attacher le débogueur à un processus (terminal) en cours d'exécution. Vous pouvez totalement faire le débogage image par image, en utilisant la caméra (tant que le programme se compile en un exécutable fonctionnel.) Maintenant, c'est assez cool, et cela m'amène à 98% de fonctionnalités. Pour ce faire, démarrez l'exécutable du terminal, puis allez dans Xcode -> Debug -> Attach to Process. Sélectionnez l'application en cours d'exécution, ajoutez des points d'arrêt au code source et déboguez/poursuivez. Fonctionne bien.
Je démarre mon projet OpenCV avec:
int main(int argc, char** argv){
// Parse command line arguments
CommandLineParser parser(argc,argv,keys);
// Create a VideoCapture object & open the input file
VideoCapture cap;
if (parser.has("video")){
cap.open(parser.get<String>("video"));
}
else
cap.open(0);
...
C'est un travail de piratage, mais mieux que rien. (Bien sûr, souhait Apple inclus la caméra dans l'émulateur iOS, ce serait une autre façon de résoudre ce problème, soupir). Évidemment, cela dépend beaucoup de la direction que vous prenez avec votre projet. En fin de compte, j'ai besoin du mien pour exécuter sur un iPad; Proveout sur MacOS, puis envelopper le code dans Swift, etc ...
Pour référence, j'utilise macOS Mojave, 10.14.4, MacBook 2.7GHz i7
PS. Les préférences de sécurité ci-dessus ne montrent pas Chrome avec accès à la caméra. Semble étrange. Je viens de tester la caméra à ce site ... dans Chrome, et il demande permission et fonctionne exactement comme prévu. Ce n'est pas clair sur ce qui se passe ici.
PS2. Suis-je la seule personne à déposer un rapport de bogue sur ce problème? Lien inclus pour votre commodité. Merci.
J'ai trouvé un moyen de contourner cela:
Tout d'abord, réinitialisez les règles de votre appareil photo:
tccutil reset Camera
Ensuite, j'ai exécuté un logiciel tiers pour accéder à la caméra depuis le terminal. En exécutant ce qui suit:
brew install imagesnap
imagesnap -w 1 snapshot.png
On m'a demandé si je voulais autoriser le terminal à accéder à ma caméra. J'ai cliqué sur "Oui". Et maintenant, mon programme C++ peut désormais accéder à la caméra depuis le terminal.
Remarque: Les images présentées ZipZit étaient très similaires, sauf que je n'avais pas de terminal répertorié sous la caméra.
Mais après avoir exécuté un programme tiers ,. il a ensuite été ajouté à la liste.
J'ai finalement pu résoudre ce problème en suivant une chaîne de recommandations à travers Stackoverflow et GitHub. C'était un bug douloureux qui a brûlé ma journée en essayant de faire fonctionner à nouveau mon code même s'il fonctionnait bien avant MacOS Mojave.
Solution
Placez le fichier Info.plist
avec le champ NSCameraUsageDescription
comme suggéré dans le répertoire Products/Build de votre cible (cliquez avec le bouton droit sur le produit dans le volet gauche du projet Xcode et cliquez sur "Afficher dans le Finder").
Info.plist
dans votre répertoire de construction (après cela suggestion ) en l'ajoutant à la liste de Copy Files
sous Build Phases
de votre "cible" et en changeant la destination en "répertoire de produits" et sous-chemin à "."Résultat
System Preferences > Privacy > Camera
. tccutil reset Camera
dans Terminal
Problème
L'instanciation de l'objet cv::VideoCapture(0)
pour accéder au flux vidéo de la caméra génère l'erreur suivante même si le code fonctionnait correctement dans la version MacOS avant Mojave
OpenCV: non autorisé à capturer de la vidéo (état 0), demandant ...
OpenCV: la caméra n'a pas pu s'initialiser correctement!
Cause
MacOS Mojave a resserré la protection de la confidentialité, ce qui oblige désormais les applications à demander et demander explicitement l'autorisation avant d'accéder à la caméra, comme expliqué ici .
Suggestions qui n'ont pas fonctionné
Les suggestions ci-dessous telles que données dans divers Stackoverflow posts n'ont pas réussi à forcer le binaire construit à demander l'autorisation d'accéder à la caméra: - Ajouter le Info.plist
à votre répertoire de projet - Définir le chemin d'accès à Info.plist
sous Build Settings > Packaging > Info.plist File
ou - Le choisir dans General > Identity > Choose Info.plist File...
de votre cible
Suggestions qui auraient pu aider
Comme indiqué dans le opencv
fermé GitHub issue , une modification a été apportée dans le libopencv
vers avril 19, ce qui aurait également pu faciliter l'utilisation du Info.plist
disponible dans le répertoire de construction pour demander à l'utilisateur l'autorisation d'accéder à la caméra. J'ai donc également mis à jour mon opencv
vers la dernière version stable de 4.1.0
en utilisant brew upgrade
.
P.S. J'utilise MacOS Mojave 10.14.5
, Xcode 10.2.1
et OpenCV 4.1.0
Nous obtenons ce problème exact en cours d'exécution sur opencv 4.1.1-pre. Nous avons résolu le problème en revenant à 4.0.1.
Versions: XCode 10., MacOS Mohave 10.14.6, OpenCV 4.1.1_2
Le projet OpenCV est sur C++
Ajoutez cette classe à votre projet:
En-tête (.h
):
class CameraIssue {
public:
CameraIssue() {}
~CameraIssue() {}
bool dealWithCamera();
};
Fichier .mm
. Notez que ce n'est pas .cpp
, C'est .mm
Parce que nous voulons fonctionner avec AVFoundation
bool CameraIssue::dealWithCamera()
{
AVAuthorizationStatus st = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (st == AVAuthorizationStatusAuthorized) {
return true;
}
dispatch_group_t group = dispatch_group_create();
__block bool accessGranted = false;
if (st != AVAuthorizationStatusAuthorized) {
dispatch_group_enter(group);
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
accessGranted = granted;
NSLog(@"Granted!");
dispatch_group_leave(group);
}];
}
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)));
return accessGranted;
}
Et avant d'accéder à VideoCapture
, appelez cette méthode comme ça:
CameraIssue _camIssue;
_camIssue.dealWithCamera(); //do whatever you need with bool return
Vous vous demandez peut-être pourquoi je crée la classe C++
En utilisant l'extension Objective-C++
(.mm
)?
Afin de créer la classe Objective-C, je devrai peut-être importer Foundation
framework et importation qui m'a donné beaucoup d'erreurs sur les symboles en double parce que Foundation
et les bibliothèques tierces que j'utilise beaucoup de partages des noms. J'ai donc créé la classe C++
, Mais avec l'extension .mm
Pour pouvoir importer le framework AVFoundation
et accorder l'accès à la caméra.
La méthode dealWithCamera()
est très loin d'être parfaite mais elle correspond exactement à mes besoins. N'hésitez pas à l'étendre, à l'optimiser, à ajouter un rappel, etc.