0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

QtでOpenCV(Threadによる取得)

Last updated at Posted at 2022-12-17

はじめに

前回と前々回は、タイマを使用してUSBカメラの映像をLabelやGraphicsViewに出力しました。
今回はタイマをスレッドに変更してUSBカメラの映像を取得してLabelへ出力することにします。
前々回と前回を見ておられない方は、
前々回
前回
を参照してくだい。
特にUIの部分に関しては、ほぼ前々回の内容のままです。
今回も前回同様に要点のみ記載したいと思います。

スレッドって何?

wiki
上記のリンクを参照してください。

スレッドの処理

メインスレッドではGUIの処理を、サブスレッドでUSBカメラの取得処理をと言う具合にします。
プログラムが起動している間は、サブスレッドでUSBカメラより映像を取得し続けます。

プロジェクト

今回のプロジェクト名は「OpenCVthread」とします。

UI

前々回
と同様にLabelを配置してください。
今回は、前々回と区別するように、Labelの背景色を「水色」にしました。
Screenshot from 2022-12-16 17-07-42.png

実装

クラスの新規作成

USBカメラを取得するクラスを作成します。
左上の「ファイル」→「ファイル/プロジェクトの新規作成」をクリックします。(キャプチャできませんでした)
「C++」、「c++クラス」を選択し、「choose...」をクリックします。
Screenshot from 2022-12-17 08-33-04.png
下記の様に設定します。
Screenshot from 2022-12-17 10-38-56.png
「完了」をクリックします。
Screenshot from 2022-12-17 08-40-17.png
左上に「getUsbCamera.h」と「getUsbCamera.cpp」が追加されていることがわかります。
Screenshot from 2022-12-17 08-41-44.png

ソース修正

mainwindow.h、mainwindow.cpp、getUsbCamera.h、getUsbCamera.cppを下記の通りにします。

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMessageBox>								// 追加
#include <QThread>									// 追加
#include "getUsbCamera.h"							// 追加

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
	Q_OBJECT

public:
	MainWindow(QWidget *parent = nullptr);
	~MainWindow();
	getUsbCamera *getUsbCamT;						// 追加
private:
	Ui::MainWindow *ui;
	QImage qtImage;									// 追加
public slots:
	void onValueChangedCam(void);					// 追加
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

	// 追加(ここから)
	getUsbCamT = new getUsbCamera(this);
	if(getUsbCamT->initCam()){
		connect(getUsbCamT, SIGNAL(valueChangedCam(void)), this, SLOT(onValueChangedCam(void)));
		getUsbCamT->start();
	} else {
		QMessageBox msgBox(this);
		msgBox.setText(tr("カメラがオープンできませんでした。"));
		msgBox.setWindowTitle(tr("エラー"));
		msgBox.setStandardButtons(QMessageBox::Yes);
		msgBox.setDefaultButton(QMessageBox::Yes);
		msgBox.setIcon(QMessageBox::Warning);
		msgBox.exec();
		exit(0);
	}
	// 追加(ここまで)
}

MainWindow::~MainWindow()
{
	getUsbCamT->Stop = true;						// 追加
	delete ui;
}

// 追加(ここから)
void MainWindow::onValueChangedCam(void)
{
	cv::Mat dst;
	getUsbCamT->getImage(&dst);
	qtImage = QImage((const unsigned char*)(dst.data), dst.cols, dst.rows, QImage::Format_RGB888);
	ui->label->setPixmap(QPixmap::fromImage(qtImage));
}
// 追加(ここまで)
getUsbCamera.h
#ifndef GETUSBCAMERA_H
#define GETUSBCAMERA_H

#include <QThread>
#include <QObject>
// 追加(ここから)
#include <QMutex>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
// 追加(ここまで)

class getUsbCamera : public QThread
{
    Q_OBJECT
public:
//	getUsbCamera();									修正のため削除
// 追加(ここから)
	getUsbCamera(QObject *parent = 0, bool b = false);
	~getUsbCamera();
	bool initCam(void);
	void run(void);
	void getImage(cv::Mat*);
	bool Stop;
signals:
	void valueChangedCam(void);
private:
	cv::VideoCapture cap;
	cv::Mat frame, dst;
// 追加(ここまで)
};
#endif // GETUSBCAMERA_H
getUsbCamera.cpp
#include "getUsbCamera.h"

// 修正のため削除
//getUsbCamera::getUsbCamera()
// 追加(ここから)
getUsbCamera::getUsbCamera(QObject *parent, bool b) : QThread(parent), Stop(b)
{

}

getUsbCamera::~getUsbCamera()
{
	Stop = true;
}

bool getUsbCamera::initCam(void)
{
	bool ret = true;

	cap.open(0);
	if(cap.isOpened()){
		cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
		cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
	} else 	{
		ret = false;
	}

	return ret;
}

void getUsbCamera::run(void)
{
	QMutex mutex;

	while(1){
		mutex.lock();
		if(this->Stop) break;
		mutex.unlock();

		cap >> frame;
		cv::cvtColor(frame, dst, cv::COLOR_BGR2RGB);

		emit valueChangedCam();

		this->msleep(20);
    }
}


void getUsbCamera::getImage(cv::Mat *image)
{
	*image = dst.clone();
}
// 追加(ここまで)

.proファイル修正

こちら
と同様に追加を行います。

build&run

実装が完了しましたら、▶をクリックして、build & run します。
Screenshot from 2022-12-17 10-51-08.png
(映像が暗くてすみません)
スレッドで取得したUSBカメラの映像が表示しております。

まとめ

USBカメラの映像をタイマで取得するのが良いのか、スレッドで取得するのが良いのかは利用用途で異なると思います。
私の所感では、数秒毎に取得する場合にタイマで取得、連続的に取得するときは、スレッドでするのが良いと思います。

今後の予定

OpenCVのネタが少なくなってきました(笑)
画像の回転やフィルタのネタがありますので、今回のスレッドのプロジェクトを基に追記したいと思います。
その他予定しているものは、MySQLへの接続、テーブルへの追加/修正/削除、JoyPadの取得を考えております。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?