web-dev-qa-db-fra.com

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

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
8
SSteve

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.

3
SSteve

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.

2
byiringiro billy

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.

Mac Systems Preferences

Vérifiez l'icône de l'appareil photo.

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 (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.

Security and Privacy Microphone

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.

  1. 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.

  2. 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.

  3. (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.

2
zipzit

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.

0
Shawn Swanson

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").

  • Automatisez ce processus de copier/coller 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

  • Le binaire exécutable Unix de Target demandera alors la permission d'accéder à la caméra et, s'il y consent, le binaire sera ajouté à la liste des applications autorisées à accéder à la caméra disponible dans System Preferences > Privacy > Camera.
    • Pour info: pour forcer l'effacement de cette liste, tapez tccutil reset Camera dans Terminal
  • Vous devrez peut-être exécuter la cible plusieurs fois avant de vous demander l'autorisation/l'accès à la caméra.

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

0
Pacific Stickler

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.

0
Liam

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.

0
Eugene Alexeev