[QT-Kursdesign] Fünftens: Ändern Sie einige Inhalte, lesen Sie das Video mit opencv und führen Sie eine Bildverarbeitung durch

Frontend-Artikel und Navigationsindex

Navigationsindex-Beitrag vor
dem Artikel, der vierte Teil des Kursdesigns

Vorwort

Im vorherigen Artikel haben wir grundsätzlich die relevanten Funktionsanforderungen für die Bildverarbeitung abgeschlossen. In diesem Artikel werden einige Fehler im vorherigen Artikel korrigiert und der Videoteil gestartet.
=. =Die Aktualisierung meines Blogs hat sich in letzter Zeit stark verzögert, weil ich mir die Weltmeisterschaft angeschaut habe, daher habe ich vor, diesen Artikel sofort mit mehr Inhalten zu aktualisieren.

Fehlerbehebung

Numerisches Problem der Gammatransformation

falsche Beschreibung

Im vorherigen Artikel haben wir nicht berücksichtigt, dass es sich bei der Gammatransformation tatsächlich um eine doppelte Größe handelt, es sollte einen Dezimalteil geben und ein Übergangswert zwischen 0 und 1 erforderlich sein, um den „Verdunkelungs“-Effekt zu erzielen.

Fehlerkorrekturprozess

Bitte fügen Sie eine Bildbeschreibung hinzu
Ändern Sie hier zunächst den Maximalwert der Gammatransformation auf 250, um den Zieleffekt von 250/10 = 25 zu erreichen, sodass der tatsächliche Maximalwert immer noch 25 beträgt, und stellen Sie gleichzeitig sicher, dass in unserer nachfolgenden Bildverarbeitung Dezimalstellen vorhanden sind .
Sehen wir uns übrigens die Details an. Ändern Sie den aktuellen Standardwert auf 10. Ändern Sie auch den binären Standardwert in einen Standardwert, den Sie für angemessen halten. Ich werde die Karte hier nicht veröffentlichen.

Ändern Sie dann den Code, um sicherzustellen, dass die Funktion normal implementiert wird.


//调节条伽马变换
void MainWindow::on_GammaSlider_valueChanged(int value)
{
    
    
    if(srcDirPathList.isEmpty()){
    
    
        QMessageBox::information(this,tr("请先选择图片"),
                                 tr("请先选择图片!"));
        return;
    }
    else{
    
    

        QImage image=QImage(srcDirPathList.at(imagenum));//读取当前图片
        double values=value;
        QImage GammaImage=Gamma(image,values/10);//伽马变换
        ui->GammaLineEdit->setText(QString::number(values/10));//改变文本框内值为伽马因子
        ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(GammaImage,ui->piclabel)));//显示伽马变换图像
    }
}

Der Code hier sollte nicht schwer zu verstehen sein. Der Wert wird in einen doppelten Wert konvertiert, und dann wird der durch Werte/10 erhaltene reale Gammawert an die Gammatransformationsverarbeitungsfunktion gesendet und der Wert des Textfelds wird ausgefüllt die selbe Zeit.
Aus dem gleichen Grund muss auch der Textfeldteil den Code ändern.


//文本框伽马变换
void MainWindow::on_GammaLineEdit_textChanged(const QString &arg1)
{
    
    
    if(srcDirPathList.isEmpty()){
    
    
        QMessageBox::information(this,tr("请先选择图片"),
                                 tr("请先选择图片!"));
        return;
    }
    else{
    
    
        double value=arg1.toDouble();
        if (value>=0 && value<=25)
        {
    
    
        QImage image=QImage(srcDirPathList.at(imagenum));
        QImage GammaImage=Gamma(image,value);//都是和上面一样的
        value=value*10;
        ui->GammaSlider->setValue(value);//当文本框内数值改变时,动态变化调节条位置
        ui->piclabel->setPixmap(QPixmap::fromImage(ImageSetSize(GammaImage,ui->piclabel)));
        }
        else
        {
    
    
            QMessageBox::information(this,tr("请输入正确数值"),
                                     tr("请输入0-25!"));
            return;
        }
    }
}

Dieser Teil des Codes wird nicht mehr erklärt, er ist nicht schwierig.

Videobereich

Das Prinzip des Videoleseteils besteht darin, das Video Bild für Bild zu segmentieren und jedes Bild in Form eines Bildes auf das Etikett zu übertragen.
Schauen wir uns zunächst den Zieleffekt an.
Bitte fügen Sie eine Bildbeschreibung hinzu

Layout-Design

Schauen Sie sich wie immer einfach die Bilder an und entwerfen Sie selbst etwas Ähnliches. Sie können völlig Ihre eigenen Ideen verwenden (mein Design ist eigentlich sehr hässlich).
Bitte fügen Sie eine Bildbeschreibung hinzu

Bitte fügen Sie eine Bildbeschreibung hinzu

Verwendung von opencv

Das Vorlesen von Videodateien zeigt, dass OpenCV, Python usw. verfügbar sind. Wir werden hier etwas OpenCV verwenden, um den Komfort zu erhöhen. (Aufgrund des Anzeigeeffekts werde ich später OpenCV verwenden, um einige Inhalte zu verarbeiten. Im Prinzip gilt: es erfüllt nicht die relevanten Anforderungen, aber um den Effekt zu zeigen, bitte verstehen)

Opencv-Kompilierung und -Konfiguration

Von diesem Teil gibt es viele im Internet, und der Prozess ist etwas umständlich. Ich werde hier direkt einen Artikel zitieren. Wenn Sie interessiert sind, können Sie ihn direkt lesen.

Qt-Konfiguration OpenCV-Tutorial, persönlich getestet und getestet (ausführliche Version) Originalautor: Wi~


Ich werde die kompilierte OpenCV-Datei an das kompilierte OpenCV-Komprimierungspaket aller senden .
Ich habe sie so eingestellt, dass 0 Punkte erforderlich sind.
Wenn CSDN Punkte oder eine Mitgliedschaft erfordert, um das Herunterladen zu ermöglichen, hinterlassen Sie mir bitte eine private Nachricht und hinterlassen Sie Ihre E-Mail-Adresse. Ich werde sie senden so schnell wie möglich, wenn ich es sehe.
=. =Wenn es Ihnen gefallen kann, mögen Sie es bitte.

Qt und OpenCV müssen jeweils einen Pfad konfigurieren. Folgen Sie Ihrem eigenen Pfad. Ich werde meinen hier veröffentlichen.

QT-Pfad

E:\Qt\Tools\mingw730_32\bin

OpenCV-Pfad

E:\QT\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\x86\mingw\bin

Bitte überprüfen Sie unbedingt Ihren eigenen Pfad, um sicherzustellen, dass Sie keinen Fehler machen. Fügen
Sie dann den Code zu Ihrer Projektprofildatei hinzu.

INCLUDEPATH +=E:\QT\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include\
            E:\QT\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include\
            E:\QT\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include\opencv2
LIBS += E:\QT\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\x86\mingw\bin\libopencv_*.dll

Das Gleiche hier, ich habe mein eigenes gepostet, machen Sie keinen Fehler, sonst können Sie es nicht lesen
. Beachten Sie, dass der Pfad hier ein Backslash und kein Schrägstrich ist.

Video öffnen

#include "opencv2/opencv.hpp"
using namespace cv;

Denken Sie zunächst daran, die OpenCV-Headerdatei und den Namespace hinzuzufügen.
Dann gibt es noch andere Header-Dateien usw.

#include <QTimer>
//mainwindow.h中添加
    QString videoSrcDir;//视频路径
    VideoCapture capture; //用来读取视频结构
    QTimer timer;//视频播放的定时器
    int beishu;//调节播放速率
    int delay;//帧延迟时间
    bool isstart=false;
    int type=0;//视频操作类型

Hier verrate ich Ihnen vorab, was Sie vorab über QTimer wissen müssen.

Einführung in Qtimer

Offizielle Originalübersetzung
Fügen Sie hier eine Bildbeschreibung ein
:

Die QTimer-Klasse bietet sich wiederholende und einmalige Timer. Die QTimer-Klasse bietet eine High-Level-Programmierschnittstelle für Timer.
Erstellen Sie eine QTimer-Instanz, verbinden Sie ihr timeout()-Signal mit dem entsprechenden Slot und rufen Sie start() auf. Anschließend wird in regelmäßigen Abständen das timeout()-Signal ausgegeben.

Freunde aus Zhejiang, die VB studiert haben, sollten sich ein wenig mit dem QTimer-Klassen-Timer vertraut fühlen. Für diejenigen, die noch nicht damit vertraut sind, ist es verständlich, dass der QTimer-Timer x Millisekunden einmal wiederholt werden kann. Daher haben wir ihn ausgewählt, um zu helfen Wir realisieren die Videowiedergabe. Effekt.

Videolesung

Wir verwenden die folgende Codemethode, um das Video zu lesen. Die Idee ist eigentlich dieselbe wie beim Öffnen des Bildes.

QString video_path = QFileDialog::getOpenFileName(this,
                                                    tr("选择视频"),
                                                    "E:/Qt/qtworks/MainWindow/images",
                                                    tr("Video (*.WMV *.mp4 *.rmvb *.flv)"));

Dann müssen wir es vorverarbeiten. Hier verwenden wir die openCV-Methode .open() , um das Video in der Aufnahme zu speichern, die wir in der Header-Datei vorbereitet haben.

 if(video_path!=nullptr){
    
    
    //打开视频文件:其实就是建立一个VideoCapture结构
    capture.open(video_path.toStdString());

Überprüfen Sie, ob das Video normal geöffnet wird

    //检测是否正常打开:成功打开时,isOpened返回ture
    if (!capture.isOpened())
         QMessageBox::warning(nullptr, "提示", "打开视频失败!", QMessageBox::Yes |  QMessageBox::Yes);

    //读入视频后解锁相关按键,切换到视频tab
     ui->tabWidget->setCurrentIndex(1);
     ui->PlayBtn->setEnabled(true);
     ui->pushButton_1->setEnabled(true);
      ui->pushButton_2->setEnabled(true);
       ui->pushButton_3->setEnabled(true);
        ui->pushButton_4->setEnabled(true);
         ui->pushButton_5->setEnabled(true);
          ui->pushButton_6->setEnabled(true);
     ui->horizontalSlider->setEnabled(true);
     ui-> horizontalSlider_suofang->setEnabled(true);
     ui-> SpeedhorizontalSlider->setEnabled(true);

Sie können hier einen Blick darauf werfen. Um zu verhindern, dass andere Tasten gedrückt werden, ohne das Video zu lesen, habe ich beschlossen, den aktivierten Wert aller anderen bedienbaren Inhalte außer der Schaltfläche „Video öffnen“ direkt auf „false“ zu ändern und ihn nach dem Öffnen auf „true“ zurückzusetzen das Video. Erzielen Sie den gewünschten Effekt.
Bitte fügen Sie eine Bildbeschreibung hinzu
Verwenden Sie die openCV-Funktion, um die Gesamtzahl der Frames zu ermitteln.

    //获取整个帧数
    long totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);
    
	//设置开始帧()
    long frameToStart = 0;
    capture.set(CAP_PROP_POS_FRAMES, frameToStart);


    //获取帧率
    double rate = capture.get(CAP_PROP_FPS);
    double speed = ui->SpeedhorizontalSlider->value()/100;
    rate=rate*speed;


    delay = 1000 / rate;
    timer.start(delay);
    type=0;
    //timer.start();
    isstart=!isstart;
    ui->PlayBtn->setText("暂停");

Es sollte leicht zu verstehen sein, dass der Anfangswert des Startrahmens 0 ist. Die Bildrate ist hier die Rate. Verwenden Sie zunächst direkt die von opencv bereitgestellte Funktion, um den FPS-Wert zu lesen, der die Anzahl der Bilder des Originalvideos darstellt.
Aber wir haben einen Einstellbalken zum Ändern der Wiedergabegeschwindigkeit, also ist der tatsächliche Zielwert des rateX-Einstellbalkens = die tatsächliche Anzahl der Bilder.
Die Verzögerung löst den Timer einmal in Millisekunden aus, was leicht zu verstehen ist.
Machen Sie sich vorerst keine Gedanken über den Typ. Er wird verwendet, um den Modus für die anschließende Verarbeitung von Videos auszuwählen. Typ=0 wählt das Originalgemälde aus.
Wenn dann die Wiedergabe beginnt, ändern Sie den Text der Wiedergabeschaltfläche in „Pause“.
Bitte fügen Sie eine Bildbeschreibung hinzu
Bitte fügen Sie eine Bildbeschreibung hinzu
Die Einstellungsparameter der Zoom-Größenleiste und der Geschwindigkeitsleiste habe ich hier gepostet. Sie können auch Ihre eigenen Präferenzen festlegen. Ich habe hier den Zoom auf das 0-2-fache der Größe und das 0,5- bis 3-fache der Geschwindigkeit eingestellt.

Alle Codes:

//视频读取
void MainWindow::on_openVideoBtn_clicked()
{
    
    
    QString video_path = QFileDialog::getOpenFileName(this,
                                                    tr("选择视频"),
                                                    "E:/Qt/qtworks/MainWindow/images",
                                                    tr("Video (*.WMV *.mp4 *.rmvb *.flv)"));
    if(video_path!=nullptr){
    
    
    //打开视频文件:其实就是建立一个VideoCapture结构
    capture.open(video_path.toStdString());
    //检测是否正常打开:成功打开时,isOpened返回ture
    if (!capture.isOpened())
         QMessageBox::warning(nullptr, "提示", "打开视频失败!", QMessageBox::Yes |  QMessageBox::Yes);

    //读入视频后解锁相关按键,切换到视频tab
     ui->tabWidget->setCurrentIndex(1);
     ui->PlayBtn->setEnabled(true);
     ui->pushButton_1->setEnabled(true);
      ui->pushButton_2->setEnabled(true);
       ui->pushButton_3->setEnabled(true);
        ui->pushButton_4->setEnabled(true);
         ui->pushButton_5->setEnabled(true);
          ui->pushButton_6->setEnabled(true);
     ui->horizontalSlider->setEnabled(true);
     ui-> horizontalSlider_suofang->setEnabled(true);
     ui-> SpeedhorizontalSlider->setEnabled(true);
    //获取整个帧数
    long totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);

    //设置开始帧()
    long frameToStart = 0;
    capture.set(CAP_PROP_POS_FRAMES, frameToStart);


    //获取帧率
    double rate = capture.get(CAP_PROP_FPS);
    double speed = ui->SpeedhorizontalSlider->value()/100;
    rate=rate*speed;


    delay = 1000 / rate;
    timer.start(delay);
    type=0;
    //timer.start();
    isstart=!isstart;
    ui->PlayBtn->setText("暂停");
  }

}

Timer-Trigger-Funktion

Wir verwenden die Methode, jedes Mal, wenn der Timer ausgelöst wird, zum nächsten Bild zu wechseln, um den Wiedergabeeffekt zu erzielen.
Zuerst müssen wir die Funktion zum Lesen des nächsten Frames implementieren

 Mat frame;
    //读取下一帧
    double rate = capture.get(CAP_PROP_FPS);
    double nowframe=capture.get(CAP_PROP_POS_FRAMES );
    int nows=nowframe/rate;
    cout<<"nows:"<<nows<<endl;
    long totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);
    int totals=totalFrameNumber/rate;
    cout<<"totals:"<<totals<<endl;
    ui->timelabel->setText(stom(nows)+"/"+stom(totals));
	QImage image=MatToQImage(frame);

Sie sollten es verstehen können, wenn Sie es hier sorgfältig lesen. Der Frame der Mat-Klasse wird zum Speichern des nächsten Frames des abzuspielenden Bildes verwendet. Der Codeteil in Großbuchstaben wird von OpenCV bereitgestellt,
wobei rate die Anzahl der Frames und nowframe ist die aktuelle Frame-Position, nows ist die aktuelle Zeit und totalFrameNumber ist die Gesamtzahl der Frames, totals ist die Gesamtdauer.

Zeiteinstellungsfunktion

Dann geben wir die aktuelle Zeit/Gesamtzeit über Timelabel aus. Dann brauchen wir eine Funktion (Stom), um die Zeit umzurechnen:

//秒转分函数
QString MainWindow::stom(int s){
    
    
    QString m;
    if(s/60==0){
    
    
        m=QString::number (s%60);
    }else{
    
    
        m=QString::number (s/60)+":"+QString::number (s%60);
    }
    return m;
}

Schließlich benötigen wir noch eine Funktion (), um Mat für die Ausgabe in QImage umzuwandeln

Matte zum Bild

Dieser Teil der Mattenbildkonvertierung wird hier nicht erläutert. Ich werde einen separaten Artikel öffnen, um ihn im Detail zu erläutern, wenn ich Gelegenheit dazu habe. Wenn der Artikellink bis dahin aktualisiert ist, werde ich ihn hier veröffentlichen.

//Mat转图像
QImage MainWindow::MatToQImage(const cv::Mat& mat)
{
    
    
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if (mat.type() == CV_8UC1)
    {
    
    
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for (int i = 0; i < 256; i++)
        {
    
    
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for (int row = 0; row < mat.rows; row++)
        {
    
    
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if (mat.type() == CV_8UC3)
    {
    
    
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if (mat.type() == CV_8UC4)
    {
    
    
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
    
    
        return QImage();
    }
}

Größe anpassen

Anschließend müssen Sie die Größe anpassen, um die Ausgabe zu unterstützen

 //大小适应
   double scale=ui->horizontalSlider_suofang->value()/100.0;

    QSize qs = ui->VideoLabel->rect().size()*scale;
    ui->VideoLabel->setPixmap(QPixmap::fromImage(image).scaled(qs));
    ui->VideoLabel->setAlignment(Qt::AlignCenter);
    ui->VideoLabel->repaint();
    ui->PlayBtn->setText("暂停");
Einstellungen für den Wiedergabemodus

Wir haben diese Funktionen bereits bei der Bildverarbeitung ausgeführt, erinnern Sie sich?
Wir können den Code hier wiederverwenden

if(type==1){
    
    
        //image1=gray(image1);
        cvtColor(frame,frame,CV_BGR2GRAY);
    }
    else if(type==2){
    
    
        //image1=avg(image1)
        cvtColor(frame, frame, CV_BGR2GRAY);
            //高斯滤波
            GaussianBlur(frame, frame, Size(3, 3),
                0, 0, BORDER_DEFAULT);
            //Canny检测
            int edgeThresh =100;
            Mat Canny_result;
            Canny(frame, frame, edgeThresh, edgeThresh * 3, 3);
    }else if(type==3)
    {
    
    
         GaussianBlur(frame, frame, Size(3, 3), 0, 0);
    }
    else if(type==4){
    
    
        cvtColor(frame,frame,CV_BGR2GRAY);
        threshold(frame, frame, 96, 255, THRESH_BINARY);
    }else if (type==5) {
    
    
        frame=masaike(frame);
    }

Als ich mit dem Schreiben halb fertig war, habe ich einen Test durchgeführt und festgestellt, dass die Verwendung der von mir geschriebenen Methode dazu führen würde, dass das Projekt sehr hängen bleibt. Deshalb habe ich die von openCV bereitgestellte Methode aufgerufen, um damit umzugehen. Das Prinzip ist eigentlich dasselbe. Sie können versuchen, es aufzurufen selbst. Vergleichen Sie den Teil, den Sie geschrieben haben, mit dem von openCV.

Alle Codes:
//timer触发函数
void MainWindow::onTimeout()
{
    
    
    Mat frame;
    //读取下一帧
    double rate = capture.get(CAP_PROP_FPS);
    double nowframe=capture.get(CAP_PROP_POS_FRAMES );
    int nows=nowframe/rate;
    cout<<"nows:"<<nows<<endl;
    long totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);
    int totals=totalFrameNumber/rate;
    cout<<"totals:"<<totals<<endl;
    ui->timelabel->setText(stom(nows)+"/"+stom(totals));

    if (!capture.read(frame))
    {
    
    
        //ui->textEdit->append(QString::fromLocal8Bit("fail to load video"));
        return;
    }


    //QImage image1 =MatToQImage(frame);
    if(type==1){
    
    
        //image1=gray(image1);
        cvtColor(frame,frame,CV_BGR2GRAY);
    }
    else if(type==2){
    
    
        //image1=avg(image1)
        cvtColor(frame, frame, CV_BGR2GRAY);
            //高斯滤波
            GaussianBlur(frame, frame, Size(3, 3),
                0, 0, BORDER_DEFAULT);
            //Canny检测
            int edgeThresh =100;
            Mat Canny_result;
            Canny(frame, frame, edgeThresh, edgeThresh * 3, 3);
    }else if(type==3)
    {
    
    
         GaussianBlur(frame, frame, Size(3, 3), 0, 0);
    }
    else if(type==4){
    
    
        cvtColor(frame,frame,CV_BGR2GRAY);
        threshold(frame, frame, 96, 255, THRESH_BINARY);
    }else if (type==5) {
    
    
        frame=masaike(frame);
    }


    QImage image=MatToQImage(frame);

    //大小适应
   double scale=ui->horizontalSlider_suofang->value()/100.0;

    QSize qs = ui->VideoLabel->rect().size()*scale;
    ui->VideoLabel->setPixmap(QPixmap::fromImage(image).scaled(qs));
    ui->VideoLabel->setAlignment(Qt::AlignCenter);
    ui->VideoLabel->repaint();
    ui->PlayBtn->setText("暂停");

}

//秒转分函数
QString MainWindow::stom(int s){
    
    
    QString m;
    if(s/60==0){
    
    
        m=QString::number (s%60);
    }else{
    
    
        m=QString::number (s/60)+":"+QString::number (s%60);
    }
    return m;
}

//Mat转图像
QImage MainWindow::MatToQImage(const cv::Mat& mat)
{
    
    
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if (mat.type() == CV_8UC1)
    {
    
    
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for (int i = 0; i < 256; i++)
        {
    
    
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for (int row = 0; row < mat.rows; row++)
        {
    
    
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if (mat.type() == CV_8UC3)
    {
    
    
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if (mat.type() == CV_8UC4)
    {
    
    
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
    
    
        return QImage();
    }
}

Bind-Trigger-Funktion

Nachdem die Timer-Triggerfunktion geschrieben wurde, müssen Sie die Bindungsbeziehung zwischen der Timer-Triggerfunktion und anderen Anforderungen in der Definition von MainWindow hinzufügen.

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    
    
    ui->setupUi(this);
    //视频
    connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    connect(&timer, SIGNAL(timeout()), this, SLOT(updatePosition()));
}

Mosaikfunktion

Tatsächlich wird der Effekt, das Video selbst zu mosaikieren, hier nicht erreicht. Ich habe mir vorerst keine besonders gute Methode ausgedacht. Wenn Sie Ideen haben, können Sie eine private Nachricht oder einen Kommentar senden.
Hier ist eine feste Position für die Änderung der Pixelfarbe.

//马赛克
void MainWindow::on_pushButton_6_clicked()
{
    
    
     type=5;
}
Mat MainWindow::masaike(Mat src){
    
    
        int width = src.rows;	//图片的长度
        int height = src.cols;	//图片的宽度

        //10*10的像素点进行填充
        int arr = 10;

        //i和j代表了矩形区域的左上角的像素坐标
        for (int i = width/2.5; i < width/1.5; i+=arr) {
    
    
            for (int j = height/2.5; j < height/1.5; j+=arr) {
    
    
            //对矩形区域内的每一个像素值进行遍历
                for (int k = i; k < arr + i && k < width; k++) {
    
    
                    for (int m = j; m < arr + j && m < height; m++) {
    
    
                        //在这里进行颜色的修改
                        src.at<Vec3b>(k, m)[0] = src.at<Vec3b>(i, j)[0];
                        src.at<Vec3b>(k, m)[1] = src.at<Vec3b>(i, j)[1];
                        src.at<Vec3b>(k, m)[2] = src.at<Vec3b>(i, j)[2];
                    }
                }
            }
        }
        return src;
}

Perfekte Details und Funktionen

//进度条跟随
void MainWindow::updatePosition(){
    
    
    long totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);
    ui->horizontalSlider->setMaximum(totalFrameNumber);
    long frame=capture.get(CAP_PROP_POS_FRAMES );
    ui->horizontalSlider->setValue(frame);
}
//暂停or播放
void MainWindow::on_PlayBtn_clicked()
{
    
    
    if(isstart)
    {
    
    
        timer.stop();
        isstart=false;
        ui->PlayBtn->setText("播放") ;
    }else {
    
    
        timer.start(delay);
        isstart=true;
        ui->PlayBtn->setText("暂停");
    }
}
//原画
void MainWindow::on_pushButton_2_clicked()
{
    
    
    type=0;
}

//平滑
void MainWindow::on_pushButton_3_clicked()
{
    
    
    type=3;
}

//灰度化
void MainWindow::on_pushButton_4_clicked()
{
    
    
     type=1;
}

//二值化
void MainWindow::on_pushButton_5_clicked()
{
    
    
    type=4;
}

//拖拽进度条
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
    
    
        capture.set(CAP_PROP_POS_FRAMES, value);

}


//缩放倍数显示
void MainWindow::on_horizontalSlider_suofang_valueChanged(int value)
{
    
    
    double va = value;
    string v= "缩放倍数:"+to_string(va/100);

    ui->Suofanglabel->setText(QString::fromStdString(v));
}

//倍速倍数显示与调整
void MainWindow::on_SpeedhorizontalSlider_valueChanged(int value)
{
    
    
    double va = value;
    string v= "倍速"+to_string(va/100);

    ui->speedlabel->setText(QString::fromStdString(v));

    double rate = capture.get(CAP_PROP_FPS);
    double speed = va/100;
    rate=rate*speed;

    delay = 1000 / rate;
    timer.start(delay);

}

Zusammenfassen

Zu diesem Zeitpunkt sind die meisten Funktionen des Videos abgeschlossen. Danach werde ich die Deep-Learning-Lösung für die Münzerkennung und -beschriftung sowie andere Funktionen wie plattform- und sprachübergreifend vervollständigen. Den Code werde ich später gemeinsam veröffentlichen.

Guess you like

Origin blog.csdn.net/weixin_43035795/article/details/128108052