15 votes

L'application de ligne de commande OpenCV ne peut pas accéder à la caméra sous macOS Mojave

Je n'arrive pas à accéder à la caméra de l'iMac depuis un programme OpenCV en ligne de commande. (Je compile et exécute le programme sous CodeRunner, et non Xcode.) J'ai lu que Mojave requiert que NSCameraUsageDescription dans Info.plist et je pense l'intégrer correctement dans le binaire. J'ai ajouté -sectcreate __TEXT __info_plist Info.plist ( dont j'ai appris l'existence ici ) aux drapeaux de compilation et lorsque j'exécute otool -X -s __TEXT __info_plist videotest | xxd -r (du même article de blog) il sort :

-?<?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 essayait d'ouvrir le microphone en même temps que la caméra).

Voici le résultat 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 une demande d'accès, mais je n'obtiens jamais de dialogue et aucune application n'est répertoriée dans Préférences système > Sécurité et confidentialité > Caméra.

Voici le programme que j'exécute :

#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-t-il ?

(Je sais que c'est similaire à Impossible d'accéder à la caméra avec opencv sur Mac Mojave mais cette question n'est jamais allée au-delà d'un fichier plist malformé).


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

6voto

SSteve Points 4997

Le problème était que le programme c++, pour une raison quelconque, ne demandait pas l'accès à la caméra. J'ai suivi le conseil de @gerwin dans les commentaires pour faire un essai avec Python. En exécutant ce programme à partir du Terminal, le Terminal demandait l'accès à la caméra. Une fois que j'ai accordé cet accès, 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 faire pour que CodeRunner exécute des programmes Python dans un environnement virtuel. Je n'ai donc pas été en mesure d'exécuter un programme Python 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.

6voto

Ce n'est pas une solution ultime mais j'ai résolu le problème en installant n'importe quelle application terminale qui demande l'accès à votre caméra. Ensuite, votre programme openCv c++ obtiendra l'accès à la caméra FaceTime HD.

par exemple, vous pouvez installer ImageSnap en :

brew install imagesnap

imagesnap -w 1 shot.png

Donnez ensuite l'autorisation à la caméra par le biais de la fenêtre pop out qui apparaîtra.

3voto

zipzit Points 405

Quelques commentaires ici...

L'erreur que je vois lorsque j'essaie d'exécuter OpenCV depuis mon environnement de développement MacOS est la suivante :

OpenCV : non autorisé à capturer la vidéo (statut 0), demande... OpenCV : la caméra n'a pas réussi à s'initialiser correctement ! Erreur d'ouverture de vidéo stream or file Le programme s'est terminé avec le code de sortie : 255

Je sais que ces mots proviennent de la bibliothèque OpenCV. ici. Ma première idée était que c'était un problème d'OpenCV. Avec un peu plus de tests, je pense que c'est autre chose. Comme d'autres l'ont noté, c'est un problème de sécurité et de permissions sous MacOS. Mais c'est là que le bât blesse.

Si je vais dans l'icône Mac Apple (coin supérieur gauche) --> Préférences système --> Sécurité et confidentialité, je peux glaner beaucoup d'informations.

Mac Systems Preferences

Vérifiez l'icône de la caméra.

Security and Privacy Camera

Dans mon cas, cela montre deux applications qui nécessitent des autorisations supplémentaires pour accéder à la caméra, Terminal et Virtualbox (je ne suis pas sûr de ce qui se passe pour le navigateur, Facetime ?) Je note que Xcode ne fait pas partie de cette liste.

Lorsque je clique sur Microphone, je vois différentes applications listées, Y COMPRIS Xcode.

Security and Privacy Microphone

Comment ça marche ? J'ai fait tout un tas de tests, y compris des recherches pour modifier l'Info.plist du paquet d'application Xcode (Finder --> Dossier Applications --> Xcode --> Clic droit, Show Package Contents. Copier Info.plist, le sauvegarder ailleurs, le modifier via Xcode, resoumettre). Note : N'essayez pas ceci sans garder une copie de l'Info.plist original. Échec total. Ajout de la NSCameraUsageDescription key/value était un échec total. Xcode ne s'ouvre pas du tout. Rappel Ne perdez pas l'Info.plist original.

Toute cette histoire est déconcertante. Pourquoi Apple nous permet d'accéder à la caméra via le terminal mais pas dans Xcode ? Quelle est la logique là-dedans ?

J'aimerais bien être en mesure de parcourir le code pour comprendre, image par image, les éventuels problèmes de conception. Ce n'est tout simplement pas amusant.

Il y a donc deux choses à comprendre.

  1. Oui, vous pouvez exécuter un projet OpenCV sur MacOS AVEC votre caméra après que le programme ait été compilé avec succès en exécutable Unix. Vous devez vous assurer que les permissions pour le terminal sont définies dans Sécurité et confidentialité, comme indiqué sur la photo ci-dessus. Évidemment vous construisez l'exécutable dans votre outil de développement (dans mon cas Xcode) puis ouvrez l'exécutable depuis le dossier Build/Debug du projet. L'application s'ouvre dans la fenêtre du terminal et fonctionne parfaitement comme l'a noté SSteve.

  2. Si vous voulez vraiment faire du débogage vidéo/caméra, vous avez la possibilité de "pré-enregistrer" une vidéo, puis d'ouvrir cette vidéo dans votre environnement de développement. À ce stade, vous pouvez utiliser le débogueur. Comment faites-vous l'analyse image par image ? C'est le seul moyen que je connaisse qui fonctionnera au moins partiellement.

  3. (edit update 5/22/19...) Whoa. Je viens de réaliser... vous pouvez attacher le débogueur à un processus en cours d'exécution (terminal). Vous pouvez tout à fait faire du 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 me permet d'atteindre 98% de fonctionnalité. Pour ce faire, démarrez l'exécutable 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/suivez le processus. Cela fonctionne bien.

Je commence 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 une solution de fortune, mais c'est mieux que rien. (Si seulement Apple incluait l'appareil photo dans l'émulateur iOS, ce serait une autre façon de résoudre ce problème, soupir). Évidemment, beaucoup de choses dépendent de l'objectif que vous poursuivez avec votre projet. En fin de compte, j'ai besoin que le mien fonctionne 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 un accès à la caméra. Cela semble étrange. Je viens de tester la caméra à ce site... dans Chrome, et il demande la permission et fonctionne exactement comme prévu. Je ne comprends pas bien ce qui se passe ici.

PS2. Suis-je la seule personne à déposer un rapport de bogue sur cette question ? Lien inclus pour votre commodité. Merci.

3voto

Eugene Alexeev Points 316

Versions : XCode 10.3 , 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();
};

.mm fichier. 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 et 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 C++ tout en utilisant Objective-C++ extension ( .mm ) ?

Afin de créer une classe Objective-C, je pourrais avoir besoin d'importer Foundation et l'importer m'a donné beaucoup d'erreurs à propos de symboles dupliqués parce que Foundation et les bibliothèques tierces que j'utilise partagent beaucoup de noms. J'ai donc créé C++ mais avec .mm pour que je puisse importer AVFoundation et accorder l'accès à la caméra.

Méthode dealWithCamera() est très loin d'être parfait mais il répond exactement à mes besoins. N'hésitez pas à l'étendre, à l'optimiser, à ajouter un callback, etc.

3voto

Benoni Jiang Points 11

Nous pouvons modifier TCC.db. Ouvrez Terminal.app, en 10.14 ou 10.15 :

/usr/bin/sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceCamera','com.krill.CodeRunner',0,1,1,NULL,NULL,NULL,'UNUSED',NULL,0,1602129687);"

dans 11.x :

/usr/bin/sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceCamera','com.krill.CodeRunner',0,2,0,1,NULL,NULL,NULL,'UNUSED',NULL,0,1608354323);"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X