LoginSignup
0
0

More than 1 year has passed since last update.

QtでOpenCV(映像の回転)

Last updated at Posted at 2022-12-17

はじめに

前回はスレッドでUSBカメラから映像を取得して表示をしました。
スレッドの処理の章で、

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

と記載しましたが、GUIの処理を付加しておりませんでしたので、「PushButton」をクリックして映像を反転させる処理を追加したいと思います。
今まで、前回や前々回と記載してややこしくなっていますので、今回から投稿したタイトルで表記します。
QtでOpenCV(Threadによる取得)
がベースとなっております。
こちらで作成したプロジェクトに機能を追加します。

仕様

上PushButton:回転しないで映像を表示
下PushButton:180度回転した映像を表示
左PushButton:270度回転した映像を表示
右PushButton:90度回転した映像を表示
とします。

UI

PushButtonの追加と名称やオブジェクト名修正

仕様の通り、4つの「PushButton」を追加します。mainwindow.uiを開きます。
Screenshot from 2022-12-17 13-18-18.png
「PushButton」を配置するのに、スペースが足りませんので、「Label」を左に移動します。
Screenshot from 2022-12-17 13-19-27.png
これで右側にスペースができましたので、「PushButton」を配置します。
QtでHello world!
を参考に、「PushButton」を4つ配置してください。
Screenshot from 2022-12-17 13-21-50.png
配置した「PushButton」のテキストがすべて「PushButton」の表記で、操作する人が分かりませんので変更します。
先ず、1番上の「PushButton」をクリックして、左下にある「Text」の「PushButton」を「rotateUp」にします。変更すると「PushButton」の表記か「rotateUp」に変わります。
Screenshot from 2022-12-17 13-26-22.png
「objectName」も変更します。
「pushButton」、「pushButton_2」、「pushButton_3」、「pushButton_4」となっておりますので、実装するときに分かり易い名称へ変更します。
「pushButton」を「pushButtonUp」へ変更します。
Screenshot from 2022-12-17 13-30-35.png
「pushButton_2」、「pushButton_3」、「pushButton_4」も同様に変更します。
全て修正すると、下記のようになると思います。
Screenshot from 2022-12-17 13-36-04.png

イベントを発生させる

「rotateUp」、「rotateDown」、「rotateLeft」、「rotateRight」にクリックのイベントを発生させるようにします。詳しくは、
QtでHello world!
の「イベントを発生させる」を参照してください。
今回の操作で、mainwindo.hとmainwindow.cppに下記が追加されます。

mainwindow.h
private slots:
	void on_pushButtonUp_clicked();
	void on_pushButtonDown_clicked();
	void on_pushButtonLeft_clicked();
	void on_pushButtonRight_clicked();
mainwindow.cpp
void MainWindow::on_pushButtonUp_clicked()
{

}


void MainWindow::on_pushButtonDown_clicked()
{

}


void MainWindow::on_pushButtonLeft_clicked()
{

}


void MainWindow::on_pushButtonRight_clicked()
{

}

Ctrl+sで保存し、mainwindow.uiを閉じます。

実装

追加は、「追加rotate」と記載しております。
修正は、「修正rotate」と記載しております。

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;									// 追加
	unsigned char btnRotate;						// 追加rotate
public slots:
	void onValueChangedCam(void);					// 追加
private slots:
	void on_pushButtonUp_clicked();
	void on_pushButtonDown_clicked();
	void on_pushButtonLeft_clicked();
	void on_pushButtonRight_clicked();
};
#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()){
		btnRotate = POSITION_UP;					// 追加rotate
		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);
	getUsbCamT->getImage(&dst, btnRotate);			// 修正rotate
	qtImage = QImage((const unsigned char*)(dst.data), dst.cols, dst.rows, QImage::Format_RGB888);
	ui->label->setPixmap(QPixmap::fromImage(qtImage));
}
// 追加(ここまで)

void MainWindow::on_pushButtonUp_clicked()
{
	btnRotate = POSITION_UP;						// 追加rotate
}


void MainWindow::on_pushButtonDown_clicked()
{
	btnRotate = POSITION_DOWN;						// 追加rotate
}


void MainWindow::on_pushButtonLeft_clicked()
{
	btnRotate = POSITION_LEFT;						// 追加rotate
}


void MainWindow::on_pushButtonRight_clicked()
{
	btnRotate = POSITION_RIGHT;						// 追加rotate
}
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>
// 追加(ここまで)

#define POSITION_UP		0							// 追加rotate
#define POSITION_DOWN	1							// 追加rotate
#define POSITION_LEFT	2							// 追加rotate
#define POSITION_RIGHT	3							// 追加rotate

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*);						修正rotateのため削除
	void getImage(cv::Mat*, unsigned char);			// 修正rotate
	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);
    }
}

/* 修正rotateのため削除
void getUsbCamera::getImage(cv::Mat *image)
{
	*image = dst.clone();
}
*/
void getUsbCamera::getImage(cv::Mat *image, unsigned char mode)	// 修正rotate
{
	// 追加rotate(ここから)
	switch(mode){
		case POSITION_UP:
			*image = dst.clone();
			break;
		case POSITION_DOWN:
			cv::rotate(dst, *image, cv::ROTATE_180);
			break;
		case POSITION_LEFT:
			cv::rotate(dst, *image, cv::ROTATE_90_COUNTERCLOCKWISE);
			break;
		case POSITION_RIGHT:
			cv::rotate(dst, *image, cv::ROTATE_90_CLOCKWISE);
			break;
	}
	// 追加rotate(ここまで)
}
// 追加(ここまで)

build&run

実装が完了しましたら、▶をクリックして、build & run します。
USBカメラの映像(上)
Screenshot from 2022-12-17 14-26-10.png
USBカメラの映像(下)
Screenshot from 2022-12-17 14-26-33.png
USBカメラの映像(左)
Screenshot from 2022-12-17 14-26-42.png
USBカメラの映像(右)
Screenshot from 2022-12-17 14-26-49.png
あれっ?って気が付かれている方もおられると思います。
左右のPushButtonをクリックしたときに、Labelの背景が表示しています。
また、上下のときと比べて左右の映像が切れております。
更に映像が左に寄っています。
UIでLabelのgeometryは下記に設定しました。

幅.
640
高さ.
480

映像を左右にすると、Labelの高さが映像の幅になりますので、映像が左右切れてしまいました。
修正してみましょう。

UI修正

windowの高さを下記のように変更

高さ.
600 → 700

labelの高さを下記のように変更

高さ.
480 → 640

labelのalignmentを下記のように変更

alignment.
左揃え → 中央揃え(横方向)

Labelの位置も適切な位置にします。
Screenshot from 2022-12-17 14-35-56.png
Screenshot from 2022-12-17 14-36-29.png
Screenshot from 2022-12-17 14-44-26.pngCtrl+sで保存し、mainwindow.uiを閉じます。

再度build&run

USBカメラの映像(上)
Screenshot from 2022-12-17 14-42-09.png
USBカメラの映像(下)
Screenshot from 2022-12-17 14-42-15.png
USBカメラの映像(左)
Screenshot from 2022-12-17 14-42-20.png
USBカメラの映像(右)
Screenshot from 2022-12-17 14-42-24.png
映像が切れることなく表示しました。
また映像もLabelの中央になっています。

まとめ

映像を回転させるときは、Labelの背景色は無い方が無難だと思います。

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