Displaying video in QLabel - c++

I am trying to display a video in QLabet in QT Creator. I am reading video using openCV. Here is my code:
mainwindow.cpp
#include "includes.h"
#include "vidreadthread.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
VidReadThread *thread1 = new VidReadThread("Video read thread");
thread1->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
vidreadthread.cpp
#include "vidreadthread.h"
#include "includes.h"
using namespace cv;
extern MainWindow *mainPtr;
VidReadThread::VidReadThread(QString s) : name(s)
{
}
void VidReadThread::run()
{
QThread::msleep(100);
VideoCapture cap;
cap.open("helicopter_with_stickers.mp4");
while(1)
{
Mat image1;
// Capture frame-by-frame
cap >> image1;
// If the frame is empty, break immediately
if (image1.empty())
break;
QImage image2 = QImage((uchar*) image1.data, image1.cols, image1.rows, image1.step, QImage::Format_RGB888);
mainPtr->ui->label1->setPixmap(QPixmap::fromImage(image2));
}
}
I am able to display the video but I can't set frame rate. Whole 60sec of video gets over in 4-5 frames. With only OpenCV I have command on frame rate with cvWaitkey(), but here msleep() doesn't seem to be working for a similar application. Please suggest a way to do so without frame skipping. I made a vidreadthread so that GUI doesn't get hanged while video is being read.
If there is any other way by which I can display OpenCV window inside my QT UI, then please recommend that as well.

try moveto thread may works better
.cpp
for (int i = 0; i<Camera::getCameraCount();)
ui->comboBox->addItem(QString::number(i++)); //name camera
camera = new Camera();
camera->moveToThread(&thread);
connect(this, SIGNAL(cameraOperate(int)), camera, SLOT(Operate(int)));
connect(camera, SIGNAL(updateImage(QImage)), this, SLOT(updateImage(QImage)));
void app0::updateImage(QImage image)
{
ui->videoviewer->setPixmap(QPixmap::fromImage(image));
}
camera thread:
void Camera::Operate(int _index)
{
if (open(_index)) { qDebug() << "Camera open success!";}
else { qDebug() << "Camera open failed!"; return; }
if (capture.get(28) == -1) { cout << "get 28 -1" << "\n";emit }
while (1)
{
qApp->processEvents();
Mat matin = read(); //read mat
matnow = matin;
QImage image = Mat2QImage(matin);
emit updateImage(image);
}
}
link:https://blog.csdn.net/Sun_tian/article/details/104236327

Related

Creating a progress bar for audio playback in Qt Widgets

I'm currently working on a Qt Widget (using Qt 6.3) that plays audio and shows a progressbar. But I'm struggling to find a way to connect the audio progress value with the progress bar status.
Here's my code:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
mMediaPlayer = new QMediaPlayer(this);
audio_output = new QAudioOutput(this);
//this is the part I need help with
connect(mMediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
void MainWindow::on_Button_open_media_clicked()
{
QString file_name = QFileDialog::getOpenFileName(this, "Open");
if(file_name.isEmpty()){
return;
}
mMediaPlayer->setSource(QUrl::fromLocalFile(file_name));
mMediaPlayer->setAudioOutput(audio_output);
audio_output->setVolume(ui->volume_slider->value());
on_play_button_clicked();
}
void MainWindow::on_stop_button_clicked()
{
mMediaPlayer->stop();
}
void MainWindow::on_pause_button_clicked()
{
mMediaPlayer->pause();
}
void MainWindow::on_play_button_clicked()
{
audio_output->setVolume(100);
mMediaPlayer->play();
}
void MainWindow::on_mute_button_clicked()
{
if(ui->mute_button->text() == "Mute"){
audio_output->setMuted(true);
ui->mute_button->setText("Unmute");
}
else{
audio_output->setMuted(false);
ui->mute_button->setText("Mute");
}
}
void MainWindow::on_volume_slider_valueChanged(int value)
{
audio_output->setVolume(value);
}
}
I couldn't find a way to do it using the documentation. It might be simple, but I need help.
Any help is gladly appreciated.

QObject::connect: No such signal - QT and OpenCV SIGNAL and connect() error

I'm working on a computer vision project, an interactable surface that must handle user interactions through the video feed recognising the user's hands. The system recognizes the user's finger and map it on a GUI. I've developed the solution in Visual Studio 2017 using OpenCV for the video processing stuff, QT 5 to build the GUI and arduino to check the click on the surface. At the moment I've to controll a QTPushButton using the arduino serial output, that controll a boolean (isChecked) in the main class of the C++ program, I've read a lot about SIGNAL and SLOT in QT but when I trigger a SIGNAL using arduino serial connection and I handle the signal with connect() method in the MainWindow interface the system responds with the error : QObject::connect: No such signal QPushButton::valueChangedButton1(unsigned int).
The program failed to connect(button1, SIGNAL(valueChangedButton1(unsigned int)), this, SLOT(button1clicked()));, in the
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) instance.
SerialPort.h is an utility class to handle serial output from arduino. I've tried to put the connect() method in the while cycle of openCV but doesn't work.
MainWindow.h
#define NSAMPLES 7
#define ORIGCOL2COL COLOR_BGR2HLS
#define COL2ORIGCOL COLOR_HLS2BGR
#define PI 3.14159
#include <QtWidgets/QMainWindow>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qtguiglobal.h>
#include <iostream>
#include "ui_MainWindow.h"
#include "opencv2/opencv.hpp"
#include "SerialPort.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
private:
void initializationClicked();
void stopCapture();
void button1clicked();
void button2clicked();
signals:
void valueChangedButton1(unsigned int value);
private:
QPushButton *startCapture;
QPushButton *releaseCapture;
QPushButton *button1;
QPushButton *button2;
QLabel *interactionLabel;
QLabel *interactionType;
QFont f, i;
char *PORT;
bool b1Over, b2Over, isChecked;
// opencv stuff
cv::VideoCapture cap;
cv::Mat src;
// arduino stuff
char output[MAX_DATA_LENGTH];
char incomingData[MAX_DATA_LENGTH];
int intFromArduino;
char *port;
int fromArduino;
}
MainWindow.cpp
#include "MainWindow.h"
using namespace cv;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
f = QFont("Arial", 12, QFont::Bold);
i = QFont("Arial", 10, QFont::Black);
PORT = "\\\\.\\COM5";
width = 600;
height = 380;
setMinimumSize(width, height);
startCapture = new QPushButton("INIT SYSTEM", this);
startCapture->setGeometry(QRect(QPoint(10, height - 120), QSize(100, 50)));
connect(startCapture, SIGNAL(clicked()), this, SLOT(initializationClicked()));
releaseCapture = new QPushButton("KILL SYSTEM", this);
releaseCapture->setGeometry(QRect(QPoint(10, height - 60), QSize(100, 50)));
connect(releaseCapture, SIGNAL(clicked()), this, SLOT(stopCapture()));
button1 = new QPushButton("BUTTON 1", this);
button1->setGeometry(QRect(QPoint(width / 2 - 100, height - 120), QSize(150, 100)));
b1 = Point(width / 2 - 100, height - 120);
// receive the signal
connect(button1, SIGNAL(valueChangedButton1(unsigned int)), this, SLOT(button1clicked()));
button2 = new QPushButton("BUTTON 2", this);
button2->setGeometry(QRect(QPoint(width / 2 + 100, height - 120), QSize(150, 100)));
b2 = Point(width / 2 + 100, height - 120);
interactionLabel = new QLabel(this);
interactionLabel->setText("log: ");
interactionLabel->setGeometry(QRect(QPoint(10, 15), QSize(200, 20)));
interactionLabel->setFont(f);
interactionType = new QLabel(this);
interactionType->setText("kind of interaction");
interactionType->setGeometry(QRect(QPoint(110,15), QSize(250, 20)));
interactionType->setFont(i);
}
void MainWindow::initializationClicked()
{
controllMainVideoFlow();
}
void MainWindow::controllMainVideoFlow()
{
SerialPort arduino(PORT);
cap = VideoCapture(0);
if(!cap.isOpen())
{
cout << "no video feed" << endl;
}else
{
if(arduino.isConnected())
{
while(cap.isOpen())
{
cap >> src;
arduino.readSerialPort(output, MAX_DATA_LENGTH);
fromArduino = strlen(output);
if(fromArduino == 0)
{
isChecked = false;
}
else if(fromArduino != 0)
{
isChecked = true;
// emit the signal
emitSignalB1();
}
imshow("SOURCE", src);
qApp->processEvents();
if (cv::waitKey(30) == 'q') break;
}
cap.release();
src.release();
}
}
}
void MainWindow::emitSignalB1()
{
// emit the signal
emit valueChangedButton1(fromArduino);
}
void MainWindow::stopCapture()
{
interactionType->setText("system killed");
cap.release();
src.release();
destroyAllWindows();
}
void MainWindow::button1clicked()
{
interactionType->setText("button 1 clicked");
}
void MainWindow::button2clicked()
{
interactionType->setText("button 2 clicked");
}
The error is here:
connect(button1, SIGNAL(valueChangedButton1(unsigned int)), this, SLOT(button1clicked()));
Actually, there is no such signal called valueChangedButton1() in QPushButton. You get this error because button1 is a QPushButton.
You defined this signal in the MainWindow class, so you have to connect the signal from a MainWindow instance, not from a QPushButton instance.
You could write instead:
connect(this, SIGNAL(valueChangedButton1(unsigned int)), this, SLOT(button1clicked()));
// ^
// Not button1
This will fix your error.
But as it's not clear for me what you really want to do, I'm not sure if it is what you really want.
By the way, I think this is a typo but, in your header, you declared your signal as signal: instead of signals: (a 's' is missing).
EDIT: I would advise you to not use the old macros SIGNAL() and SLOT() anymore. You should use the new syntax instead.
Moreover, as the new syntax makes explicit from where the signals and slots are called, the origin of this error would have been obvious.

Displaying multiple OpenCV VideoCapture objects in QT

I'm capturing webcam streams from two raspberry pis and I'm trying to carry out some image processing on both streams. I have two Qlabels I'm trying to use to display the images from the pis. However, whilst one stream displays in real time, the other has a 4-5 second delay. The same result occurs if I try to display one stream on both Qlabel objects. Is this a threading issue? Can you guys please help out?
VideoCapture capWebcam;
VideoCapture EyeintheSky;
Mat matEyeInTheSky;
QImage qimgEyeInTheSky;
Mat matOriginal;
QImage qimgOriginal;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
capWebcam.open("http://192.168.0.102:8080/?action=stream?dummy=param.mjpg"); //from MJPG STreamer image processing
EyeintheSky.open("http://192.168.0.100:8080/?action=stream?dummy=param.mjpg");
if (capWebcam.isOpened() == false) {
return;
}
if(EyeintheSky.isOpened() == false) {
return;
}
}
void MainWindow::processFrameAndUpdateGUI() {
capWebcam.read(matOriginal);
EyeintheSky.read(matEyeInTheSky);
if(matOriginal.empty() == true) {
qDebug() << "Empty Picture";
return;
}
else {
// start of visual processing
// Output Tri Track images to screen
// map QImage to QLabel
cvtColor(matOriginal,matOriginal,COLOR_BGR2RGB);
QImage qimgOriginal((uchar*)matOriginal.data,matOriginal.cols,matOriginal.rows, matOriginal.step,QImage::Format_RGB888);
ui->lblInputImage->setPixmap(QPixmap::fromImage(qimgOriginal));
// Output Eye in the Sky to screen
// map QImage to QLabel
cvtColor(matEyeInTheSky, matEyeInTheSky, COLOR_BGR2RGB);
QImage qimgEyeInTheSky((uchar*)matEyeInTheSky.data, matEyeInTheSky.cols, matEyeInTheSky.rows, matEyeInTheSky.step, QImage::Format_RGB888);
ui->sky_input->setPixmap(QPixmap::fromImage(qimgEyeInTheSky));
// Process IK code.
}
}

Memory leak using opencv : VideoCapture

I have developed an application with Qt Creator 2.4.1 (Qt 4.8.4) and OpenCV 2.4.2 that reads images from a folder and displays them.
It uses cv::VideoCapture and QGraphicsScene/QGraphicsView. It runs well, however I encounter a memory leak : if I look at the consumed memory in task manager, memory goes up each time a new image is read and end up crashing.
My main window was created with Qt Designer, it's a class that inherits QMainWindow. There is a QGraphicsView view_src on it and also a push button : buttonStart
Here is a sample of code : Class declaration :
using namespace std;
using namespace cv;
namespace Ui {
class FenetrePrinc;
}
class FenetrePrinc : public QMainWindow {
Q_OBJECT
public:
explicit FenetrePrinc(QWidget *parent = 0);
~FenetrePrinc();
public slots:
virtual void start();
virtual void tick();
virtual void stop_timer();
private:
Ui::FenetrePrinc *ui;
QString filename;
QGraphicsScene *scene_src;
QGraphicsItem *img_src;
VideoCapture sequence;
Mat src;
};
Class definition :
FenetrePrinc::FenetrePrinc(QWidget *parent) : QMainWindow(parent), ui(new Ui::FenetrePrinc){
ui->setupUi(this);
scene_src = new QGraphicsScene();
timer = new QTimer(this);
img_src = scene_src->addPixmap(QPixmap("vide.jpg"));
ui->view_src->setScene(scene_src);
connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
}
FenetrePrinc::~FenetrePrinc(){
delete scene_src;
delete img_src;
delete ui;
}
void FenetrePrinc::start(){
if(src.empty())
sequence.open(filename.toStdString());
connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
timer->start(1000/24); //24 frames per second
disconnect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(stop_timer()));
}
void FenetrePrinc::tick(){
sequence >> src;
if(src.empty())
{
sequence.release();
stop_timer();
return;
}
scene_src->removeItem(img_src);
img_src = scene_src->addPixmap(convert16uc1(src));
src.release();
}
void FenetrePrinc::stop_timer(){
timer->stop();
disconnect(timer, SIGNAL(timeout()), this, SLOT(tick()));
disconnect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(stop_timer()));
connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
}
I don't understand why does memory usage goes up and up each time an image is read, I do release the image each time it is read, and release sequence once finished. But maybe I missed something ?
EDIT : The function QPixmap convert16uc1(Mat img) is the cause of the memory leak. I have to use this function because I am working with 16bits grayscale images, which Qt cannot read. I open images and perform image processing with OpenCV and display the images with Qt.
The code of the function is the following :
QPixmap FenetrePrinc::convert16uc1(const cv::Mat& source)
{
quint16* pSource = (quint16*) source.data;
int pixelCounts = source.cols * source.rows;
QImage dest(source.cols, source.rows, QImage::Format_RGB32);
char* pDest = (char*) dest.bits();
for (int i = 0; i < pixelCounts; i++)
{
quint8 value = (quint8) ((*(pSource)) >> 8);
*(pDest++) = value; // B
*(pDest++) = value; // G
*(pDest++) = value; // R
*(pDest++) = 0; // Alpha
pSource++;
}
return QPixmap::fromImage(dest);
}
Most probably it is convert16uc1.
If you can't post convert16uc1 here, try saving the image temporarily in opencv using imwrite and loading the image in Qt. If the the memleak disappears. analyze convert16uc1.
Or don't call convert16uc1(src) but call addPixmap using some other constant image previously loaded in Qt.
I found what causes the problem and how to fix it, reading this thread.
From the Qt documentation:
void QGraphicsScene::removeItem ( QGraphicsItem * item )
Removes the item item and all its children from the scene. The ownership of item is passed on to the caller (i.e., QGraphicsScene will no longer delete item when destroyed).
See also addItem().
Once QGraphicsScene::removeItem(QGraphicsItem *item)` has been called, QGraphicsScene will no longer delete the item whenn destroyed.
Fix : call delete img_src after removeItem(img_src) : in function FenetrePrinc::tick() :
void FenetrePrinc::tick(){
sequence >> src;
if(src.empty())
{
sequence.release();
stop_timer();
return;
}
scene_src->removeItem(img_src);
delete img_src;
img_src = scene_src->addPixmap(convert16uc1(src));
src.release();
}

Qt OpenCV Webcam Stream Opening and Closing

I have created a very simple UI using Qt which consists of a simple button and a label. When the button's clicked() signal is emitted, a function which captures a frame from a webcam using OpenCV is called. The code I am currently using to achieve this is:
cv::Mat MainWindow::captureFrame(int width, int height)
{
//sets the width and height of the frame to be captured
webcam.set(CV_CAP_PROP_FRAME_WIDTH, width);
webcam.set(CV_CAP_PROP_FRAME_HEIGHT, height);
//determine whether or not the webcam video stream was successfully initialized
if(!webcam.isOpened())
{
qDebug() << "Camera initialization failed.";
}
//attempts to grab a frame from the webcam
if (!webcam.grab()) {
qDebug() << "Failed to capture frame.";
}
//attempts to read the grabbed frame and stores it in frame
if (!webcam.read(frame)) {
qDebug() << "Failed to read data from captured frame.";
}
return frame;
}
After a frame has been captured, it must be converted into a QImage in order to be displayed in the label. In order to achieve this, I use the following method:
QImage MainWindow::getQImageFromFrame(cv::Mat frame) {
//converts the color model of the image from RGB to BGR because OpenCV uses BGR
cv::cvtColor(frame, frame, CV_RGB2BGR);
return QImage((uchar*) (frame.data), frame.cols, frame.rows, frame.step, QImage::Format_RGB888);
}
The constructor for my MainWaindow class looks like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
resize(1280, 720);
move(QPoint(200, 200));
webcam.open(0);
fps = 1000/25;
qTimer = new QTimer(this);
qTimer->setInterval(fps);
connect(qTimer, SIGNAL(timeout()), this, SLOT(displayFrame()));
}
The QTimer is supposed to display a frame by calling dislayFrame()
void MainWindow::displayFrame() {
//capture a frame from the webcam
frame = captureFrame(640, 360);
image = getQImageFromFrame(frame);
//set the image of the label to be the captured frame and resize the label appropriately
ui->label->setPixmap(QPixmap::fromImage(image));
ui->label->resize(ui->label->pixmap()->size());
}
each time its timeout() signal is emitted.
However, while this appears to work to a degree, what actually happens is that the video capture stream from my webcam (a Logitech Quickcam Pro 9000) repeatedly opens and closes. This is evidenced by the fact that the blue ring, which indicates that the webcam is on, repeatedly flashes on and off. This leads to the refresh rate for the webcam video stream label to be very low, and is not desirable. Is there some way to make it so that the webcam stream remains open in order to prevent this "flickering" from occurring?
I seem to have solved the problem of the webcam stream opening and closing by removing the lines:
webcam.set(CV_CAP_PROP_FRAME_WIDTH, width);
webcam.set(CV_CAP_PROP_FRAME_HEIGHT, height);
from the captureFrame() function and setting the width and height of the frame to be captured in the MainWindow constructor.