A.k.
A.k.

Reputation: 302

Change speed using timer in QT creator

I am trying to move a rectangular box on top of a background image in a line trajectory. I am using Qtimer in QT creator. I am using openCV to interact with images. To move it I am calling a generate_video() function at a time interval.

1.) I want to change the speed at which the rectangle is moving. For this, I am using a horizontal slider in QT named horizontalSlider_speed. Basically, I am lowering the interval at which I am calling generate_video(). When I increase slider I am able to increase the speed, but I can reduce speed from a higher speed even if I move the slider to lowest.

2.) I am also recording it using VideoWriter. But it is skipping frames even if I set FPS to 120.

#include <QTimer>
MainWindow *MainWindowPtr;
using namespace cv;
int heightImg,widthImg,intensity,initialX,initialY,xSin;
int velocity=1;
Mat imageBack,imageObject,frame;
extern void generate_video();
QTimer *timer;
VideoWriter outputVideo;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
 ui->setupUi(this);
    imageBack= imread(filenameImg);
    outputVideo.open("outcpp.avi",CV_FOURCC('M','J','P','G'),24, 
    Size(imageBack.cols,imageBack.rows));
}

void MainWindow::on_pushButton_Generate_clicked()
{
    QTimer *timer = new QTimer;

    // make the connection using the timer variable
    connect(timer, &QTimer::timeout, this, &generate_video);

    // start the timer object by first dereferencing that object first
    timer->setInterval(100-MainWindowPtr->ui->horizontalSlider_speed->value());

    timer->start();
}

void generate_video()
{
    heightImg = MainWindowPtr->ui->lineEdit_Height->text().toInt();
    widthImg = MainWindowPtr->ui->lineEdit_Width->text().toInt();

imageBack= imread(filenameImg);

    cvtColor(imageBack, imageBack, cv::COLOR_RGB2GRAY);

    //draw rectangular object
    rectangle(imageBack,Point(initialX,initialY),Point(initialX+widthImg,initialY+heightImg),Scalar(intensity),-1,8,0);
    imshow("image",imageBack);

    //line trajectory

    if(initialX>640)
    initialX=0;
    else
    initialX+=2;

    //start recording
    if(recordFlag==1)
    {
        cv::cvtColor(imageBack, frame, cv::COLOR_GRAY2BGR);
        outputVideo.write(frame);
    }

}

void MainWindow::on_pushButton_Record_clicked()
{
 recordFlag=1; //start recording
}

Upvotes: 0

Views: 1220

Answers (2)

Martin Hennings
Martin Hennings

Reputation: 16856

Great, you found the bug by yourself! :-)

You were creating a new QTimer every time you clicked on 'Generate'. All these timers were constantly firing, because none was stopped.

The solution is indeed to use a single timer, but you can go a step further than in your answer:

You only need to connect it once (in your MainWindow constructor).

Then, in on_pushButton_Generate_clicked, just set the interval to the current desired value and start the timer.

If you create your timer with new QTimer(this), it becomes a QObject child of your MainWindow and gets automatically deleted when MainWindow is destroyed. This prevents possible crashes when the timer tries to call the timeout slot generate_video() although your MainWindow is already deleted.

Furthermore, if you want to play the animation only once, you can just stop the timer when initialX reaches 640.

Upvotes: 1

A.k.
A.k.

Reputation: 302

I found a solution by using Qtimer disconnect. Also, we don't need to declare it every time I push button. So QTimer *timer = new QTimer; should be moved into MainWindow::MainWindow() as timer = new QTimer as we have already declared it as global. So new code should be like this.

void MainWindow::on_pushButton_Generate_clicked()
{
    timer->disconnect();

    // make the connection using the timer variable
    connect(timer, &QTimer::timeout, this, &generate_video);

    // start the timer object by first dereferencing that object first
    timer->setInterval(100-MainWindowPtr->ui->horizontalSlider_speed->value());

    timer->start();
}

Upvotes: 0

Related Questions