首页 新闻 会员 周边 捐助

Qt5 SDL2读取摄像头画面闪怎么处理?

0
悬赏园豆:20 [已关闭问题] 关闭于 2022-07-12 17:25

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>

#include <opencv2/videoio.hpp>

using namespace cv;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_actOpen_triggered();//打开摄像头

    void on_actClose_triggered();//关闭摄像头

    void timeOut();//timer超时

private:
    Ui::MainWindow *ui;
    VideoCapture cap;
    QTimer *timer = new QTimer(this);
};
#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);

    connect(timer, SIGNAL(timeout()), this, SLOT(timeOut()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actOpen_triggered()
{
    cap = VideoCapture();
    cap.open(0);

    timer->setInterval(40);
    timer->start();

    ui->actOpen->setEnabled(false);
    ui->actClose->setEnabled(true);
}

void MainWindow::on_actClose_triggered()
{
    timer->stop();
    ui->actOpen->setEnabled(true);
    ui->actClose->setEnabled(false);
}

void MainWindow::timeOut()
{
    Mat mat;
    cap.read(mat);
    ui->label->setData(mat);//这个是我重写的一个widget控件

    this->update();
}

SDLWidget.h

#ifndef SDLWIDGET_H
#define SDLWIDGET_H

#include <QMutex>
#include <QWidget>

#include <opencv2/core/mat.hpp>
#include <SDL2/SDL.h>
using namespace cv;

class SDLWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SDLWidget(QWidget *parent = nullptr);
    ~SDLWidget();

    void setData(Mat mat);

signals:
private:
    Mat mat;
    QMutex mtx;

    SDL_Window *window = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Texture *texture = NULL;

    // QWidget interface
protected:
    void paintEvent(QPaintEvent *event) override;
};

#endif // SDLWIDGET_H

SDLWidget.cpp

#include "SDLWidget.h"
#include <QDebug>

SDLWidget::SDLWidget(QWidget *parent) : QWidget(parent)
{
    SDL_Init(SDL_INIT_VIDEO);
    window = SDL_CreateWindowFrom((void *)this->winId());
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);//硬件加速
    SDL_ShowWindow(window);
}

SDLWidget::~SDLWidget()
{
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
}

void SDLWidget::setData(Mat mat)
{
    mtx.lock();
    mat.copyTo(this->mat);
    mtx.unlock();
    if (texture == NULL) {
        texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, mat.cols, mat.rows);
    }
}

void SDLWidget::paintEvent(QPaintEvent *event)
{
    if (!this->mat.empty()) {
        Mat frame;
        mtx.lock();
        this->mat.copyTo(frame);
        mtx.unlock();

        qDebug() << "clear \t" << SDL_RenderClear(renderer); // 0 on success, or -1 on error
        qDebug() << "color \t" << SDL_SetRenderDrawColor(renderer, 187, 159, 93, 255); //用renderer画背景图 0 on success, or -1 on error
        qDebug() << "update \t" << SDL_UpdateTexture(texture, NULL, frame.data, frame.cols * 3); //更新纹理 0 on success, or -1 if the texture is not valid.
        qDebug() << "copy \t" << SDL_RenderCopy(renderer, texture, NULL, NULL); // 0 on success, or -1 on error
        SDL_RenderPresent(renderer); //渲染
    }
    QWidget::paintEvent(event);
}

界面

Question

  • 视频可以播放,就是闪得厉害,感觉就是这帧画完了,然后刷新掉,露出空间底色,一直都是这么闪,里面的视频也是在动着的
问题补充:

设备没问题,代码应该也没有问题,这段c++代码可以正常播放.

#include <stdio.h>
#include <SDL2/SDL.h>
#include <opencv2/opencv.hpp>
using namespace cv;

int main(int argc, char *argv[])
{
    bool res = SDL_Init(SDL_INIT_VIDEO); //枚举变量值可以叠加,返回值为0/1;
    /** 这两段代码差这句话,Qt直接把他当成控件处理,所以不需要create,C++这块需要create一个window **/
    SDL_Window *window = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080, SDL_WINDOW_OPENGL);//
    printf("%d\n", SDL_GetWindowID);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); //使用硬件加速
    SDL_Texture *texture = nullptr;
    VideoCapture cap = VideoCapture();
    cap.open(0);
    bool isRunning = true;
    Mat mat;
    int winWidth = 0;
    int winHeight = 0;
    SDL_GetWindowSize(window, &winWidth, &winHeight);
    while (isRunning)
    {
        SDL_RenderClear(renderer);
        SDL_SetRenderDrawColor(renderer, 187, 159, 93, 255); //用renderer画黑图
        printf("clear");
        isRunning = cap.read(mat);
        if (!isRunning)
        {
            break;
        }
        texture = texture == nullptr ? SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, mat.cols, mat.rows) : texture;
        SDL_Rect rect;
        rect.x = 0;
        rect.y = 0;
        rect.w = 640;
        rect.h = 480;
        res = SDL_UpdateTexture(texture, NULL, mat.data, mat.cols * 3);
        printf("update %d\n", res);
        res = SDL_RenderCopy(renderer, texture, NULL, &rect);
        printf("copy %d\n", res);
        SDL_RenderPresent(renderer); //这个是用来显示画面的
        waitKey(40);
    }
    cap.release();
    SDL_Quit();
    return 0;
}
echo_lovely的主页 echo_lovely | 小虾三级 | 园豆:1548
提问于:2022-05-13 15:53
< >
分享
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册