QT-从UI捕获后,用鼠标绘制opencv -imshow,不工作

发布于 2025-01-29 19:01:51 字数 5261 浏览 2 评论 0原文

我有一个QT项目,可以在其中使用OpenCV MouseCallbacks捕获网络摄像头的图像,然后在IMShow上执行图形,而不是QgraphicsView)。 我可以捕获图像并使用我的按钮显示,但是我无法绘制任何内容(甚至在我单击图像后它甚至会崩溃)。

代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPixmap>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>

#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>

#include <vector>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

     static void DrawScanPoints(int event, int x, int y, int flag, void* param);
     void DrawScanPoints(int event, int x, int y);

private slots:
    void on_pbt_Capture_clicked();

    void on_pbt_Scan_clicked();

public slots:
    void UpdateFrame();

private:
    Ui::MainWindow *ui;
    cv::VideoCapture videoCap;
     cv::Mat liveImage, inputImage;
    bool camRun = true;
};
#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);
    videoCap.open(0);

    QTimer* timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(UpdateFrame()));
    timer->start(20);
}

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

void MainWindow::UpdateFrame()
{
    if(camRun)
    {
        videoCap.read(liveImage);

        QImage image = QImage(liveImage.data, liveImage.cols, liveImage.rows, QImage::Format_RGB888).rgbSwapped();
        QGraphicsScene* scene = new QGraphicsScene(this);
        scene->addPixmap(QPixmap::fromImage(image));

        ui->graphicsView->setScene(scene);
        ui->graphicsView->show();
    }
}

void MainWindow::DrawScanPoints(int event, int x, int y, int flag, void* param)
{
    MainWindow* mw = reinterpret_cast<MainWindow*>(param);
    mw->DrawScanPoints(event, x, y);
}

void MainWindow::DrawScanPoints(int event, int x, int y)
{
    if(event & cv::EVENT_LBUTTONDOWN)
    {
        cv::Point pt = cv::Point(x, y);
        cv::circle(inputImage, pt, 10, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
    }
}

void MainWindow::on_pbt_Capture_clicked()
{
    camRun = false;
    inputImage = liveImage;

    cv::namedWindow("Capture");
    cv::setMouseCallback("Capture", DrawScanPoints, this);

    while(1)
    {
        cv::imshow("Capture", inputImage);
        cv::waitKey(0);
        cv::destroyAllWindows();
    }
}

void MainWindow::on_pbt_Scan_clicked()
{

}


main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>608</width>
    <height>440</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QGraphicsView" name="graphicsView">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>501</width>
      <height>391</height>
     </rect>
    </property>
   </widget>
   <widget class="QPushButton" name="pbt_Capture">
    <property name="geometry">
     <rect>
      <x>520</x>
      <y>10</y>
      <width>81</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>Capture</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pbt_Scan">
    <property name="geometry">
     <rect>
      <x>520</x>
      <y>40</y>
      <width>80</width>
      <height>18</height>
     </rect>
    </property>
    <property name="text">
     <string>Scan</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>608</width>
     <height>17</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

I have this Qt Project where I can capture an Image from WebCam and afterwards draw on it using OpenCV MouseCallbacks (I perform the drawing on the imshow, not the QGraphicsView).
I can capture the Image and display it using my pushbutton, but I can't draw anything (it even crashes after I click on the Image).

Codes:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPixmap>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>

#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>

#include <vector>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

     static void DrawScanPoints(int event, int x, int y, int flag, void* param);
     void DrawScanPoints(int event, int x, int y);

private slots:
    void on_pbt_Capture_clicked();

    void on_pbt_Scan_clicked();

public slots:
    void UpdateFrame();

private:
    Ui::MainWindow *ui;
    cv::VideoCapture videoCap;
     cv::Mat liveImage, inputImage;
    bool camRun = true;
};
#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);
    videoCap.open(0);

    QTimer* timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(UpdateFrame()));
    timer->start(20);
}

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

void MainWindow::UpdateFrame()
{
    if(camRun)
    {
        videoCap.read(liveImage);

        QImage image = QImage(liveImage.data, liveImage.cols, liveImage.rows, QImage::Format_RGB888).rgbSwapped();
        QGraphicsScene* scene = new QGraphicsScene(this);
        scene->addPixmap(QPixmap::fromImage(image));

        ui->graphicsView->setScene(scene);
        ui->graphicsView->show();
    }
}

void MainWindow::DrawScanPoints(int event, int x, int y, int flag, void* param)
{
    MainWindow* mw = reinterpret_cast<MainWindow*>(param);
    mw->DrawScanPoints(event, x, y);
}

void MainWindow::DrawScanPoints(int event, int x, int y)
{
    if(event & cv::EVENT_LBUTTONDOWN)
    {
        cv::Point pt = cv::Point(x, y);
        cv::circle(inputImage, pt, 10, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
    }
}

void MainWindow::on_pbt_Capture_clicked()
{
    camRun = false;
    inputImage = liveImage;

    cv::namedWindow("Capture");
    cv::setMouseCallback("Capture", DrawScanPoints, this);

    while(1)
    {
        cv::imshow("Capture", inputImage);
        cv::waitKey(0);
        cv::destroyAllWindows();
    }
}

void MainWindow::on_pbt_Scan_clicked()
{

}


main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>608</width>
    <height>440</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QGraphicsView" name="graphicsView">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>501</width>
      <height>391</height>
     </rect>
    </property>
   </widget>
   <widget class="QPushButton" name="pbt_Capture">
    <property name="geometry">
     <rect>
      <x>520</x>
      <y>10</y>
      <width>81</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>Capture</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pbt_Scan">
    <property name="geometry">
     <rect>
      <x>520</x>
      <y>40</y>
      <width>80</width>
      <height>18</height>
     </rect>
    </property>
    <property name="text">
     <string>Scan</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>608</width>
     <height>17</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

池木 2025-02-05 19:01:51

我无法在本地复制此此内容(我缺少一些源文件,例如Main和UI),但是您可能应该在setmousecallback中传递this作为最后一个参数。参见我应该如何通过opencv中的指针到会员功能到setMouseCallback?

进行了问题后更新了:

remove cv :: destrionallwindows来自on_pbt_capture_clicked ;替换CV :: Waitkey(0);带有cv :: waitkey(30);

void MainWindow::on_pbt_Capture_clicked()
{
    camRun = false;
    inputImage = liveImage;

    cv::namedWindow("Capture");
    cv::setMouseCallback("Capture", DrawScanPoints, this);

    while(1)
    {
        cv::imshow("Capture", inputImage);
        cv::waitKey(30);
    }
}

原因:您从未更新“捕获”窗口:waitkey(0)永远键输入) - 因此,只有在按下键盘上的任何键后,您的窗口才会更新。因此,如果您更改为Waitkey(30)更新将自动每30 [ms]发生一次(此后Waitkey退出)。

每次删除destroyallwindows时,无需破坏和重新创建窗口。如果您想知道何时更新on_pbt_capture_clicked中的窗口,请使用条件变量。在中等待它,而(1)notify_one它从drawscanpoints中。

I'm not able to reproduce this locally (I'm missing some of the source files, e.g. main and the UI) but probably you should pass this in setMouseCallback as the last parameter. See How should I pass a pointer-to-member-function to setMouseCallback in OpenCV?

Edit after question was updated:

Remove cv::destroyAllWindows from on_pbt_Capture_clicked; replace cv::waitKey(0); with cv::waitKey(30);:

void MainWindow::on_pbt_Capture_clicked()
{
    camRun = false;
    inputImage = liveImage;

    cv::namedWindow("Capture");
    cv::setMouseCallback("Capture", DrawScanPoints, this);

    while(1)
    {
        cv::imshow("Capture", inputImage);
        cv::waitKey(30);
    }
}

Reason: you've never updated the "capture" window: waitKey(0) waits forever (for any key input) - so your window will be updated with circles only after you press any key on the keyboard. So if you change to waitKey(30) the updates will be happening every 30 [ms] automatically (timeout after which waitKey exits).

No need to destroy and recreate window every time hence removing destroyAllWindows. If you want to be smart about when to update the window in on_pbt_Capture_clicked, use conditional variable. WAit for it inside while(1) and notify_one it from inside DrawScanPoints.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文