QT + OPENCV实现视频的播放和画框对框内运动对象的显示光流

QT + OPENCV实现视频的播放和画框对框内运动对象的显示光流

最近实验室一个项目要求我做个界面
要求实现对视频的读取,对感兴趣部分画框并且处理,我就自学了Qt和opencv实现了一下
下面是部分相关代码
videodisplayingqt.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_videodisplayingqt.h"
#include <opencv2\opencv.hpp>
#include <QTimer>
#include <QFile>
#include <QFileDialog>

using namespace cv;
using namespace std;

class videodisplayingqt : public QMainWindow
{
    Q_OBJECT

public:
    videodisplayingqt(QWidget *parent = Q_NULLPTR);



private:

    Ui::videodisplayingqt ui;

    VideoCapture capture;
    Mat frame;
    QTimer *timer;
    QTimer *timer2;
    QString file_name;
    int i = 0;

private slots:
    void importFrame();
    void on_displayButton_clicked();
    void on_stopButton_clicked();
    void open_path_slot();
    void drawcropflow();
    void clickcrop();
    void makecolorwheel(vector<Scalar> &colorwheel);
    void motionToColor(Mat flow, Mat &color);
};

videodisplayingqt.cpp

#include "videodisplayingqt.h"
#include <opencv2/imgproc/types_c.h>
#include "myqlabel.h"


#define UNKNOWN_FLOW_THRESH 1e9


videodisplayingqt::videodisplayingqt(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    timer = new QTimer(this);
    timer2 = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(importFrame()));//import frame when timeout
    connect(timer2, SIGNAL(timeout()), this, SLOT(drawcropflow()));//import frame when timeout


}

void videodisplayingqt::importFrame()
{
    capture >> frame;
    cvtColor(frame, frame, CV_BGR2RGB);//only RGB of Qt
    QImage srcQImage = QImage((uchar*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);
    ui.label->setPixmap(QPixmap::fromImage(srcQImage));
    ui.label->resize(srcQImage.size());
    ui.label->show();
}

void videodisplayingqt::on_displayButton_clicked()
{
    capture.open(file_name.toStdString());
    timer->start(33);
}

void videodisplayingqt::on_stopButton_clicked()
{
    timer->stop();
    capture.release();

}

void videodisplayingqt::open_path_slot()
{
    //打开视频按钮的槽函数
    file_name = QFileDialog::getOpenFileName(this,tr("选择视频文件"),".",
                                                    tr("视频格式(*.avi *.mp4 *.flv *.mkv)"));
    QFile file(file_name);
    if(!file.open(QIODevice::ReadOnly))
    {

        return;
    }
    else{
        ui.lineEdit->setText(file_name);
    }
}

void videodisplayingqt::drawcropflow()
{
    i++;
    //画框的坐标
    int x1 = ui.label->getX1();
    int x2 = ui.label->getX2();
    int y1 = ui.label->getY1();
    int y2 = ui.label->getY2();


//    capture >> frame;
//    cvtColor(frame, frame, CV_BGR2RGB);//only RGB of Qt
//    QImage srcQImage = QImage((uchar*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);
//    QImage srcImage1 = srcQImage.copy(x1, y1, x2-x1, y2-y1);
//    ui.label_4->setPixmap(QPixmap::fromImage(srcImage1));
//    ui.label_4->resize(srcImage1.size());
//    ui.label_4->show();

//转换格式保存图片
//    Mat mat;
//    mat = cv::Mat(srcImage1.height(), srcImage1.width(), CV_8UC3, (void*)srcImage1.constBits(), srcImage1.bytesPerLine());
//    cvtColor(mat, mat, CV_BGR2RGB);

//    imwrite("C:/Users/wanghaoming/Desktop/pic/photo" + to_string(i) + ".jpg", mat);

    Mat prevgray, gray, flow, cflow, frame;
    namedWindow("运动光流", 1);

    Mat motion2color;

    for (;;)
    {
        capture >> frame;

        cvtColor(frame, frame, CV_BGR2RGB);//only RGB of Qt
        QImage srcQImage = QImage((uchar*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);
        QImage srcImage1 = srcQImage.copy(x1, y1, x2-x1, y2-y1);

        frame = cv::Mat(srcImage1.height(), srcImage1.width(), CV_8UC3, (void*)srcImage1.bits(), srcImage1.bytesPerLine());
        cvtColor(frame, frame, CV_BGR2RGB);


        if (frame.empty()) {
            break;
        }
        cvtColor(frame, gray, CV_BGR2GRAY);
        //imshow("original", frame);

        if (prevgray.data)
        {
            calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
            motionToColor(flow, motion2color);
            imshow("运动光流", motion2color);
        }
        if (waitKey(10) >= 0)
            break;
        swap(prevgray, gray);
    }

}

void videodisplayingqt::clickcrop()
{
    timer2->start(33);//间隔一秒
}

//绘制光流相关函数
void videodisplayingqt::makecolorwheel(vector<Scalar> &colorwheel)
{
    int RY = 15;
    int YG = 6;
    int GC = 4;
    int CB = 11;
    int BM = 13;
    int MR = 6;

    int i;

    for (i = 0; i < RY; i++) colorwheel.push_back(Scalar(255, 255 * i / RY, 0));
    for (i = 0; i < YG; i++) colorwheel.push_back(Scalar(255 - 255 * i / YG, 255, 0));
    for (i = 0; i < GC; i++) colorwheel.push_back(Scalar(0, 255, 255 * i / GC));
    for (i = 0; i < CB; i++) colorwheel.push_back(Scalar(0, 255 - 255 * i / CB, 255));
    for (i = 0; i < BM; i++) colorwheel.push_back(Scalar(255 * i / BM, 0, 255));
    for (i = 0; i < MR; i++) colorwheel.push_back(Scalar(255, 0, 255 - 255 * i / MR));
}

void videodisplayingqt::motionToColor(Mat flow, Mat &color)
{
    if (color.empty())
        color.create(flow.rows, flow.cols, CV_8UC3);

    //定义颜色的容器
    static vector<Scalar> colorwheel;
    if (colorwheel.empty())
        makecolorwheel(colorwheel);

    //确定运动范围
    float maxrad = -1;

    //找到最大流动来标准化fx和fy
    for (int i = 0; i < flow.rows; ++i)
    {
        for (int j = 0; j < flow.cols; ++j)
        {
            Vec2f flow_at_point = flow.at<Vec2f>(i, j);
            float fx = flow_at_point[0];
            float fy = flow_at_point[1];
            if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
                continue;
            float rad = sqrt(fx * fx + fy * fy);
            maxrad = maxrad > rad ? maxrad : rad;
        }
    }

    for (int i = 0; i < flow.rows; ++i)
    {
        for (int j = 0; j < flow.cols; ++j)
        {
            uchar *data = color.data + color.step[0] * i + color.step[1] * j;
            Vec2f flow_at_point = flow.at<Vec2f>(i, j);

            float fx = flow_at_point[0] / maxrad;
            float fy = flow_at_point[1] / maxrad;
            if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
            {
                data[0] = data[1] = data[2] = 0;
                continue;
            }
            float rad = sqrt(fx * fx + fy * fy);

            float angle = atan2(-fy, -fx) / CV_PI;
            float fk = (angle + 1.0) / 2.0 * (colorwheel.size() - 1);
            int k0 = (int)fk;
            int k1 = (k0 + 1) % colorwheel.size();
            float f = fk - k0;
            //f = 0; // 取消注释可查看原始色轮l

            for (int b = 0; b < 3; b++)
            {
                float col0 = colorwheel[k0][b] / 255.0;
                float col1 = colorwheel[k1][b] / 255.0;
                float col = (1 - f) * col0 + f * col1;
                if (rad <= 1)
                    col = 1 - rad * (1 - col); //随半径增大饱和度
                else
                    col *= .75; //超过范围处理
                data[2 - b] = (int)(255.0 * col);
            }
        }
    }
}

整体的界面如下图所示:
在这里插入图片描述
画框如下图所示:
在这里插入图片描述
显示运动光流如下图所示:
在这里插入图片描述
整个工程的重点有三点吧:
第一个是如何画框:这个是通过重写myqlabel类实现上,网上教程很多,如果不清楚的我后面在github上提供源代码。
第二个是如何对运动对象进行显示光流处理,这一部分的话在网上也是有许多显示光流的教程,学习下写一个方法。
第三个就是我在写代码的过程中还遇到类许多关于显示类型的问题,要注意qimage和cv::Mat类的相互转换。
最后奉上我的工程文件在的链接,有想看的朋友们可以直接看源码。
链接: https://github.com/whmJohn/CropVideoFlow.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值