C++でカメラ画像取得をマルチスレッドやってみる:Semaphore版


概要

OpenCVを用いて、USBカメラから取得した画像を出力するプログラムを2つのスレッドで実行してみました。USBカメラは1つとして、1つのカメラから取得される画像をセマフォのように割り当て、画像出力もセマフォのように出力しています。

実行環境

次に実行環境を示します。

Soft and Hard バージョン
Visual Studio 2017
OpneCV 4.0.0

実装したプログラムついて

スレッド間の排他制御はセマフォのように、カウンタを使って実装しました。カウンタが0の時はスレッド1を実行、カウンタが1の時はスレッド2を実行のようにしています。次に、イメージ図を示します。

  • イメージ図

マーカID取得プログラム

次に作成したマーカID取得プログラムを示します。カメラはUSBカメラを使いました。

multi_thread_with_semaphore.cpp
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include<thread>
#include<time.h>
#include<mutex>

// Global Varidation
cv::VideoCapture cap(1);
cv::Mat frame_thread_first;
cv::Mat frame_thread_second;
int semaphonre_counter = 0;

void GetFrameFromCameraFunction1() {

    while (true) {
        if (semaphonre_counter == 0) {
            cap.read(frame_thread_first);
            semaphonre_counter++;
        }
    }
}

void GetFrameFromCameraFunction2() {

    while (true) {
        if (semaphonre_counter == 2) {
            cap.read(frame_thread_second);
            semaphonre_counter++;
        }
    }
}

void ShowFrameFromCameraFunction1() {

    while (true) {
        if (semaphonre_counter == 1) {
            cv::imshow("WIndow1", frame_thread_first);
            const int key = cv::waitKey(1);
            if (key == 27) {
                exit(EXIT_SUCCESS);
            }
            else if (key == 50) {
                cv::imwrite("th2.png", frame_thread_first);
            }
            semaphonre_counter++;
        }

    }
}

void ShowFrameFromCameraFunction2() {

    while (true) {
        if (semaphonre_counter == 3) {
            cv::imshow("WIndow2", frame_thread_second);
            const int key = cv::waitKey(1);
            if (key == 27) {
                exit(EXIT_SUCCESS);
            }
            else if (key == 52) {
                cv::imwrite("th4.png", frame_thread_second);
            }
            semaphonre_counter = 0;
        }
    }
}

void StartThread() {

    std::thread GetFrameThread1(GetFrameFromCameraFunction1);
    std::thread ShowFrameThread1(ShowFrameFromCameraFunction1);
    std::thread GetFrameThread2(GetFrameFromCameraFunction2);
    std::thread ShowFrameThread2(ShowFrameFromCameraFunction2);

    ShowFrameThread1.join();
    GetFrameThread1.join();
    ShowFrameThread2.join();
    GetFrameThread2.join();

}

int main(int argh, char* argv[])
{

    StartThread();

}

実装プログラム実行

上記のプログラムを実行した場合の結果を示します。

  • 全体画像

mutexを使うより格段に速くなりました。どうして、mutexが遅いのについては、調査してみたいと思います。

まとめ

1つのUSBカメラから単純に画像を2つのスレッドで分ける場合には、セマフォのように実装したほうが、画像の更新速度が速いことがわかりました。また、間違っているところや、追加したほうがいい、こういう書き方の方がいいよ!という箇所がありましたら、お教え頂けるととても嬉しいです。