web-dev-qa-db-ja.com

OpenCVコマンドラインアプリがmacOS Mojaveでカメラにアクセスできない

コマンドラインのOpenCVプログラムからiMacカメラにアクセスできません。 (Xcodeではなく、CodeRunnerの下でプログラムをコンパイルして実行しています。)MojaveはInfo.plistにNSCameraUsageDescriptionを必要とすることを読んだので、バイナリに正しく埋め込んでいると思います。 -sectcreate __TEXT __info_plist Info.plistここで学んだこと )をコンパイルフラグに追加し、otool -X -s __TEXT __info_plist videotest | xxd -rを実行すると(同じブログから) post)それは出力します:

-?<?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>

(カメラと一緒にマイクを開こうとした場合に備えて、NSMicrophoneUsageDescriptionを追加しました。)

これは私がプログラムを実行したときの出力です:

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

アクセスを要求していることを意味しますが、ダイアログは表示されず、システム環境設定>セキュリティとプライバシー>カメラにアプリが表示されません。

ここに私が実行しているプログラムがあります:

#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;
}

これはコンパイラーの呼び出しです。

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}"

パズルのどの部分が欠けていますか?

(これは Mac Mojave でopencvを使用してカメラにアクセスできないことを知っていますが、その質問は不正なplistファイルを超えることはありませんでした。)


Ffmpegがデバイスを参照していることを確認するための提案に応じて:

$ 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

問題は、c ++プログラムが何らかの理由でカメラへのアクセスを要求していないことでした。コメントで@gerwinのアドバイスを取り入れて、Pythonを試してみました。ターミナルからそのプログラムを実行すると、ターミナルからカメラへのアクセスが要求されます。許可すると、c ++プログラムはターミナルから実行したときにカメラにアクセスできました。

CodeRunnerに関する限り、CodeRunnerで仮想環境下でPythonプログラムを実行する方法がわからないため、Python OpenCVプログラムを実行して取得することができませんでした。カメラへのアクセスを要求します。そのため、現時点では、CodeRunnerを使用してカメラにアクセスするc ++プログラムを実行することはできません。

3
SSteve

これは究極のソリューションではありませんが、カメラへのアクセスを要求するターミナルアプリケーションをインストールすることで解決しました。その後、openCv c ++プログラムはFaceTime HD Cameraへのアクセスを取得します。

たとえば、次の方法でImageSnapをインストールできます。

brew install imagesnap

imagesnap -w 1 shot.png

次に、表示されるポップアウトからカメラに許可を与えます。

2

ここにいくつかのコメント...

MacOS開発環境からOpenCVを実行しようとしたときに表示されるエラーは次のとおりです。

OpenCV:ビデオのキャプチャを許可されていません(ステータス0)、要求しています... OpenCV:カメラは正しく初期化できませんでした!ビデオストリームまたはファイルを開くときにエラーが発生しましたプログラムが終了コード255で終了しました

私はそれらの言葉がOpenCVライブラリに由来することを知っています here。 私の最初の考えは、これはOpenCVの問題であるということでした。もう少しテストすると、それは別のことだと思います。他の人が指摘したように、MacOSのセキュリティ/権限の問題。しかし、ここで問題があります。

Macにアクセスした場合Appleアイコン(左上隅)-> [システム環境設定]-> [セキュリティとプライバシー]にアクセスすると、多くの情報を収集できます。

Mac Systems Preferences

カメラアイコンを確認してください。

Security and Privacy Camera

私の場合、これはカメラにアクセスするために追加の権限を必要とする2つのアプリケーション、ターミナルとVirtualboxを示しています(ブラウザー、Facetimeがどうなるかわかりません)。

[マイク]をクリックすると、Xcodeを含むさまざまなアプリが一覧表示されます。

Security and Privacy Microphone

それはどのように機能しますか? Xcodeアプリケーションパッケージ(Finder-> Applications Folder-> Xcode-> Rtクリック、パッケージの内容を表示)のInfo.plistの変更を調査するなど、多くのテストを行いました。Info.plistをコピーして、他の場所に保存します。 Xcodeを使用して変更し、再送信してください。)注:元のInfo.plistのコピーを保持せずにこれを試さないでください。完全に失敗します。 NSCameraUsageDescriptionキー/値を追加することは、完全なバストでした。 Xcodeがまったく開かない。注意:元のInfo.plistは失われません。

このすべてが不可解です。 Appleでターミナルからカメラにアクセスできるが、Xcodeではできないのはなぜですか?そこのロジックは何ですか?

コードをステップ実行して、フレームごとに考えられる設計上の問題を理解できるようにしたいと思います。これはただ面白くない。

したがって、理解しておくべきことがいくつかあります。

  1. はい、プログラムがUnix実行可能ファイルに正常にコンパイルされたら、カメラを使用してMacOSでOpenCVプロジェクトを実行できます。ターミナルの権限が上の写真のセキュリティとプライバシーに設定されていることを確認する必要があります。明らかに、開発ツール(私の場合はXcode)で実行可能ファイルをビルドしてから、プロジェクトのBuild/Debugフォルダーから実行可能ファイルを開きます。アプリはターミナルウィンドウで開き、SSteveで指摘されているように正常に動作します。

  2. 本当にビデオ/カメラのデバッグを行いたい場合は、ビデオを「事前に記録」して、開発環境でそのビデオを開くオプションがあります。その時点で、デバッガーを使用できます。どうやってフレームごとの分析をしますか?これが、少なくとも部分的に機能することがわかっている唯一の方法です。

  3. (編集5/22/19を編集...)おっと。私は気づきました。実行中の(ターミナル)プロセスにデバッガを接続できます。カメラを使用して、フレームごとのデバッグを完全に行うことができます(プログラムが機能する実行可能ファイルにコンパイルされる限り)。これでかなりクールになり、98%の機能に到達できます。これを行うには、ターミナル実行可能ファイルを起動し、Xcode-> Debug-> Attach to Processに移動します。実行中のアプリケーションを選択し、ソースコードにブレークポイントを追加して、デバッグ/ステップします。うまくいきます。

OpenCVプロジェクトを次のように開始します。

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

これはハック回避策ですが、何もしないよりはましです。 (確かにApple iOSエミュレータにカメラが含まれている、これはこれを解決する別の方法になるだろう、ため息)。明らかに、多くはプロジェクトのどこに行くかに依存します。最終的に私はiPadで実行、MacOSで検証、Swiftなどでコードをラップ...

参考までに、macOS Mojave、10.14.4、MacBook 2.7GHz i7を使用しています

PS。上記のセキュリティ設定にChromeは表示されません。奇妙に思われます。Chromeで このサイト... でカメラをテストしたところ、許可と期待どおりに動作します。ここで何が起こっているのかは明確ではありません。

PS2。この問題について バグレポートを提出 するのは私だけですか?便利なリンクが含まれています。ありがとう。

2
zipzit

私はこれの回避策を見つけました:

まず、カメラのルールをリセットします。

tccutil reset Camera

次に、サードパーティのソフトウェアを実行して、端末からカメラにアクセスしました。以下を実行することにより:

brew install imagesnap
imagesnap -w 1 snapshot.png

端末にカメラへのアクセスを許可するかどうかを尋ねられました。 「はい」をクリックしました。そして今私のC++プログラムはターミナルからカメラにアクセスできます。

注:ZipZitに表示されている写真は、端末がカメラの下にリストされていなかったことを除いて、非常によく似ていました。

しかし、サードパーティのプログラムを実行した後。その後、リストに追加されました。

0
Shawn Swanson

StackoverflowとGitHub全体にわたる一連の推奨事項に従うことで、ようやくこれを解決することができました。 MacOS Mojaveより前のバージョンでは問題なく動作していたにも関わらず、コードを再び動作させようとする私の日を焼くのは痛いバグでした。

ソリューション

ターゲットのProducts/BuildディレクトリにNSCameraUsageDescriptionフィールドを含むInfo.plistファイルを suggested として配置します(Xcodeプロジェクトの左ペインでProductを右クリックし、[Finderに表示]をクリックします)。

  • 「ターゲット」のInfo.plistの下にあるCopy Filesのリストに追加し、出力先を「製品」に変更することにより、Build Phasesをビルドディレクトリにコピー/貼り付けるこのプロセスを自動化します(この suggestion に従います)。ディレクトリ」と「。」へのサブパス

結果

  • ターゲットのUnix実行可能バイナリは、カメラへのアクセス許可を要求し、同意すると、バイナリは、System Preferences > Privacy > Camera。[.____で利用可能なカメラへのアクセスを許可されたアプリケーションのリストに追加されます。
    • 参考:このリストを強制的にクリアするには、Terminaltccutil reset Cameraと入力します
  • 許可を求められるか、カメラにアクセスする前に、ターゲットを数回実行する必要がある場合があります。

問題

Mojaveより前のMacOSバージョンでコードが正常に実行されていても、cv::VideoCapture(0)オブジェクトをインスタンス化してカメラのビデオストリームにアクセスすると、次のエラーがスローされます

OpenCV:ビデオをキャプチャする権限がありません(ステータス0)、要求しています...
OpenCV:カメラは正しく初期化できませんでした!

原因

MacOS Mojaveはプライバシー保護を強化しており、 こちら で説明されているように、カメラにアクセスする前にアプリケーションから明示的にプロンプ​​トを出し、許可を求める必要があります。

うまくいかなかった提案

さまざまなStackoverflow posts に記載されている以下の提案では、ビルドされたバイナリがカメラへのアクセス許可を求めるプロンプトを正常に表示しませんでした:-Info.plistをプロジェクトディレクトリに追加-パスをInfo.plistに設定Build Settings > Packaging > Info.plist Fileor-ターゲットのGeneral > Identity > Choose Info.plist File...で選択する

役に立ったかもしれない提案

opencvのクローズGitHub issue に示されているように、libopencvに'19年4月頃にいくつかの変更が加えられ、ビルドディレクトリで利用可能なInfo.plistの使用を促進して、カメラへのアクセス許可を持つユーザー。そのため、4.1.0を使用してopencvも最新の安定したbrew upgradeリリースにアップグレードしました。

追伸MacOS Mojave 10.14.5、Xcode 10.2.1、OpenCV 4.1.0を実行しています

0

Opencv 4.1.1-preでこの問題が発生しています。 4.0.1にロールバックすることで問題を解決しました。

0
Liam

バージョン:XCode 10.MacOS Mohave 10.14.6OpenCV 4.1.1_2

OpenCVプロジェクトは_C++_にあります

このクラスをプロジェクトに追加します。

ヘッダー(_.h_):

_class CameraIssue {


public:
    CameraIssue() {}
    ~CameraIssue() {}

    bool dealWithCamera();
};
_

_.mm_ファイル。 _.cpp_ではないことに注意してください。AVFoundationで操作したいので、それは_.mm_です。

_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;
}
_

VideoCaptureにアクセスする前に、このメソッドを次のように呼び出します。

_CameraIssue _camIssue;
_camIssue.dealWithCamera(); //do whatever you need with bool return
_

疑問に思うかもしれませんが、なぜ_C++_拡張(_Objective-C++_)を使用しているときに_.mm_クラスを作成するのですか?

Objective-Cクラスを作成するために、Foundationフレームワークをインポートしてインポートする必要がある場合があります。インポートすると、共有ロットを使用しているFoundationとサードパーティライブラリが原因で、シンボルの重複に関する多くのエラーが発生しました。名前の。したがって、_C++_クラスを作成しましたが、_.mm_拡張機能を使用して、AVFoundationフレームワークをインポートし、カメラへのアクセスを許可します。

メソッドdealWithCamera()は完全とはほど遠いですが、私のニーズにぴったり合っています。それを拡張したり、最適化したり、コールバックを追加したりしてください。

0
Eugene Alexeev