簡體   English   中英

OpenCV Video Capture 作為類成員不起作用 (C++)

[英]OpenCV Video Capture nonfunctional as class member (C++)

我的應用程序要求將 OpenCV VideoCapture 對象用作成員變量。 沒有辦法繞過這個要求。

cv::VideoCapture用作用戶定義類的成員時,我遇到了奇怪的行為。 我已經運行了以下代碼:

#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64


class Foo {
public:
    Foo() = default;
    void run(void) {
        cv::VideoCapture* cap = new cv::VideoCapture();
        cv::VideoCapture g_cap = *cap;
        if (not g_cap.open(0)) {
            std::cerr << "Cannot open camera 0" << std::endl;
            exit(-1);
        }
        for (int i = 0; i < 10; i++) {
            if (not g_cap.isOpened())
                std::cerr << "Video capture is not open here!" << std::endl;
            cv::Mat f;
            g_cap >> f;
            if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
            std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
            bool b = cv::imwrite(filename, f);
            if (not b) std::cerr << "Error in writing image" << std::endl;
            //cv::waitKey(25);
        }
    };

};

int main(void) {
    cv::VideoCapture cap;

    if (not cap.open(0)) {
        std::cerr << "Cannot open camera 0" << std::endl;
        return -1;
    }

    for (int i =0; i < 10; i++) {
        cv::Mat frame; 
        cap >> frame;
        if (frame.empty()) {
            std::cerr << "frame is empty" << std::endl;
            break;
        }
        // Else write the image to a file
        std::string filename = "test_" + std::to_string(i) + ".tiff";
        bool res = cv::imwrite(filename, frame);
        if (not res) 
            std::cerr << "Error in writing image" << std::endl;

    }

    cap.release();

    Foo f;
    f.run();

    return 0;
}

它只為 N = [0,9] 生成 test_N.tiff,即,生成的唯一圖像來自main( )cv::VideoCapture對象,而不是來自Foo類。

我試圖實例化一個cv::VideoCapture類型的全局變量g_cap ,但我仍然只能從主函數中的對象讀取/寫入圖像。 如上面的代碼所示,我還嘗試將 VideoCapture 對象實例化為一個指針(如果你願意的話,這是一個指針),但這也不起作用。 但是請注意,將main( )聲明的cap設置為對g_cap的引用(顯然當g_cap在全局范圍內時)給出了相同的輸出——根據需要從main( )而不是從Foo::run( )內獲取圖像。

請注意另一個奇怪的行為是控制台中沒有出現錯誤消息。 這表明FooVideoCapture類型成員實際上是打開的,並且將圖像幀加載到cv::Mat類型的f中並沒有返回空幀。 類似地, imwrite函數不會返回 false 表示操作成功。 但是,如前所述,沒有生成名為 Foo_test_N.tiff 的文件。

如何解釋這種行為? 是否有一些要求cv::VideoCapture可能在某個不同的范圍內? 如果圖像未保存或視頻流未正確打開,是否會在編寫上述代碼時產生錯誤消息?

編輯 20201110_1:回應 Viktor Latypov 在下面的評論:我已經實施了提議的更改,並且仍然觀察到相同的行為。 編輯:


class Foo {
public:
        Foo() = default;
        void run(void) {
                cv::VideoCapture* cap = new cv::VideoCapture();
                //cv::VideoCapture g_cap = *cap;
                if (not cap -> open(0)) {
                        std::cerr << "Cannot open camera 0" << std::endl;
                        exit(-1);
                }
                for (int i = 0; i < 10; i++) {
                        if (not cap -> isOpened())
                                std::cerr << "Video capture is not open here!" << std::endl;
                        cv::Mat f;
                        *cap >> f;
                        if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
                        std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
                        bool b = cv::imwrite(filename, f);
                       if (not b) std::cerr << "Error in writing image" << std::endl;
                       //cv::waitKey(25);
                }
                cap -> release();
        };

};

編輯 20201110_2:OpenCV 版本為 4.2.0

我嘗試從 (a) 函數中捕獲圖像幀,以及 (b) 將在main( )實例化的 OpenCV VideoCapture 對象作為副本傳遞給參數化構造函數,並以仍然相同的結果傳遞指針。 完整代碼如下所示:

#define int64 opencv_broken_int
#include <opencv2/opencv.hpp>
#undef int64


class Foo {
public:
        Foo() = default;
        void run(void) {
                cv::VideoCapture* cap = new cv::VideoCapture();
                //cv::VideoCapture g_cap = *cap;
                if (not cap -> open(0)) {
                        std::cerr << "Cannot open camera 0" << std::endl;
                        exit(-1);
                }
                for (int i = 0; i < 10; i++) {
                        if (not cap -> isOpened())
                                std::cerr << "Video capture is not open here!" << std::endl;
                        cv::Mat f;
                        *cap >> f;
                        if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
                        std::string filename = "Foo_test_" + std::to_string(i) + ".tiff";
                        bool b = cv::imwrite(filename, f);
                       if (not b) std::cerr << "Error in writing image" << std::endl;
                       //cv::waitKey(25);
                }
                cap -> release();
        };

};


class Bar {
public:
        Bar(cv::VideoCapture* c) : cap(c) {};

        void run(void) {
                //cv::VideoCapture* cap = new cv::VideoCapture();
                //cv::VideoCapture g_cap = *cap;
                if (not cap -> open(0)) {
                        std::cerr << "Cannot open camera 0" << std::endl;
                        exit(-1);
                }
                for (int i = 0; i < 10; i++) {
                        if (not cap -> isOpened())
                                std::cerr << "Video capture is not open here!" << std::endl;
                        cv::Mat f;
                        *cap >> f;
                        if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;
                        std::string filename = "Bar_test_" + std::to_string(i) + ".tiff";
                        bool b = cv::imwrite(filename, f);
                       if (not b) std::cerr << "Error in writing image" << std::endl;
                       //cv::waitKey(25);
                }
                cap -> release();
        };

        cv::VideoCapture* cap;
};


void test(void) {
        cv::VideoCapture cap(0);

        if (not cap.open(0)) {
                std::cerr << "Cannot open camera 0" << std::endl;
                exit(-1);
        }

        for (int i =0; i < 10; i++) {
                cv::Mat frame;
                cap >> frame;
                if (frame.empty()) {
                        std::cerr << "frame is empty" << std::endl;
                        break;
                }
                // Else write the image to a file
                std::string filename = "testFunc_test_" + std::to_string(i) + ".tiff";
                bool res = cv::imwrite(filename, frame);
                if (not res)
                        std::cerr << "Error in writing image" << std::endl;

        }

        cap.release();
}

int main(void) {
        cv::VideoCapture cap;

        if (not cap.open(0)) {
                std::cerr << "Cannot open camera 0" << std::endl;
                return -1;
        }

        for (int i =0; i < 10; i++) {
                cv::Mat frame;
                cap >> frame;
                if (frame.empty()) {
                        std::cerr << "frame is empty" << std::endl;
                        break;
                }
                // Else write the image to a file
                std::string filename = "main_test_" + std::to_string(i) + ".tiff";
                bool res = cv::imwrite(filename, frame);
                if (not res)
                        std::cerr << "Error in writing image" << std::endl;

        }

        cap.release();

        Bar b(&cap); b.run();

        Foo f; f.run();

        test();

        return 0;
}        

該程序的輸出如下所示: OpenCVTest 可執行文件的輸出 請注意,在FooBar的類成員函數中沒有保存圖像!

編輯1:

真正的問題是在這一行

  if (f.empty()) std::cerr << "Frame was empty" << std::endl; break;

我忽略了這個明顯的問題。 無論f.empty()檢查返回什么, break語句都會執行。

它應該是

  if (f.empty())
  {
       std::cerr << "Frame was empty" << std::endl;
       break;
  }

====================

以前的答案(問題 N2):

分配cap對象后

    cv::VideoCapture* cap = new cv::VideoCapture();

您正在調用賦值運算符

    cv::VideoCapture g_cap = *cap;

這可能會執行比您實際想要的更多的操作。

去掉g_cap變量,直接使用cap

例如,線

    if (not g_cap.open(0)) {

應該

    if (not cap->open(0)) {

和線

        g_cap >> f;

會成為

        *cap >> f;   // or  cap->read(f);

在這些簡單的修改之后, run()方法會生成帶有抓取幀的圖像文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM