From e0496edc228a0caa64178299e7ef3ba8295da3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=BA=AC?= <2402638909@qq.com> Date: Tue, 20 Jun 2023 21:00:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=80=E5=86=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mjpg_streamer/getpixmap.cpp | 44 ++++ mjpg_streamer/getpixmap.h | 38 +++ mjpg_streamer/loginwindow.cpp | 82 ++++++ mjpg_streamer/loginwindow.h | 37 +++ mjpg_streamer/main.cpp | 13 + mjpg_streamer/mainwindow.cpp | 97 +++++++ mjpg_streamer/mainwindow.h | 44 ++++ mjpg_streamer/mainwindow.ui | 46 ++++ mjpg_streamer/mjpg_stream_browser.pro | 47 ++++ mjpg_streamer/mjpg_stream_browser.pro.user | 279 +++++++++++++++++++++ mjpg_streamer/最小路径.txt | 137 ++++++++++ 任务规划.h | 124 +++++++++ 任务队列简单示例/示例main.txt | 34 +++ 任务队列简单示例/类.h | 44 ++++ 发送端.h | 56 +++++ 接收端.h | 78 ++++++ 机器狗视频传输.h | 42 ++++ 17 files changed, 1242 insertions(+) create mode 100644 mjpg_streamer/getpixmap.cpp create mode 100644 mjpg_streamer/getpixmap.h create mode 100644 mjpg_streamer/loginwindow.cpp create mode 100644 mjpg_streamer/loginwindow.h create mode 100644 mjpg_streamer/main.cpp create mode 100644 mjpg_streamer/mainwindow.cpp create mode 100644 mjpg_streamer/mainwindow.h create mode 100644 mjpg_streamer/mainwindow.ui create mode 100644 mjpg_streamer/mjpg_stream_browser.pro create mode 100644 mjpg_streamer/mjpg_stream_browser.pro.user create mode 100644 mjpg_streamer/最小路径.txt create mode 100644 任务规划.h create mode 100644 任务队列简单示例/示例main.txt create mode 100644 任务队列简单示例/类.h create mode 100644 发送端.h create mode 100644 接收端.h create mode 100644 机器狗视频传输.h diff --git a/mjpg_streamer/getpixmap.cpp b/mjpg_streamer/getpixmap.cpp new file mode 100644 index 00000000..91493284 --- /dev/null +++ b/mjpg_streamer/getpixmap.cpp @@ -0,0 +1,44 @@ +#include "getpixmap.h" +#include + +GetPixmap::GetPixmap(QObject *parent) : + QObject(parent) +{ + +} + +GetPixmap::~GetPixmap() +{ + +} + +void GetPixmap::mjpeg_streamer_reply(QNetworkReply *reply) +{ + QByteArray byteArr = reply->readAll(); + + QPixmap pix; + pix.loadFromData(byteArr); + + emit get_getOnePixmap(pix); + + manager->get(*request); + reply->deleteLater(); +} + + + +void GetPixmap::run() +{ + QString url; + + url.append("http://" + get_ipAddr + ":" + get_port + "/?action=snapshot"); + qDebug() << url; + +// qDebug() << "ipAddr:" << get_ipAddr; +// qDebug() << "port:" << get_port; + + manager = new QNetworkAccessManager(); + request = new QNetworkRequest(QUrl(url)); + connect(manager,SIGNAL(finished(QNetworkReply*)), this, SLOT(mjpeg_streamer_reply(QNetworkReply*))); + manager->get(*request); +} diff --git a/mjpg_streamer/getpixmap.h b/mjpg_streamer/getpixmap.h new file mode 100644 index 00000000..eabc259a --- /dev/null +++ b/mjpg_streamer/getpixmap.h @@ -0,0 +1,38 @@ +#ifndef GETPIXMAP_H +#define GETPIXMAP_H + +#include +#include +#include +#include +#include +#include +#include + +class GetPixmap : public QObject +{ + Q_OBJECT + +public: + GetPixmap(QObject *parent = nullptr); + ~GetPixmap(); + +public: + QString get_ipAddr; + QString get_port; + + void run(); + +private slots: + void mjpeg_streamer_reply(QNetworkReply*); + +signals: + void get_getOnePixmap(QPixmap); + + +private: + QNetworkAccessManager *manager; + QNetworkRequest *request; +}; + +#endif // GETPIXMAP_H diff --git a/mjpg_streamer/loginwindow.cpp b/mjpg_streamer/loginwindow.cpp new file mode 100644 index 00000000..74322b2e --- /dev/null +++ b/mjpg_streamer/loginwindow.cpp @@ -0,0 +1,82 @@ +#include "loginwindow.h" +#include "ui_loginwindow.h" +#include + +LoginWindow::LoginWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::LoginWindow) +{ + ui->setupUi(this); + + waitCnt = 0; + text.append("Login"); + + init(); +} + +LoginWindow::~LoginWindow() +{ + delete ui; +} + +void LoginWindow::init() +{ + this->setWindowTitle("Please to Login"); + ui->le_ipAddr->setText("219.216.115.53"); + ui->le_port->setText("8080"); +} + +void LoginWindow::timerFinish() +{ + if(tcpClient->state() == QTcpSocket::ConnectedState){ + waitCnt = 0; + time->stop(); + + this->close(); + + main = new MainWindow; + main->main_ipAddr = login_ipAddr; + main->main_port = login_port; + main->init(); + main->show(); + + }else{ + waitCnt++; + + if(waitCnt%10 == 3) + text = "Login."; + else if(waitCnt%10 == 6) + text = "Login.."; + else if(waitCnt%10 == 9) + text = "Login..."; + ui->btn_login->setText(text); + + if(waitCnt == 50){ + time->stop(); + waitCnt = 0; + ui->btn_login->setText("Login"); + + QMessageBox::warning(this, "Warning", "Please to Check params\nand Login again!", QMessageBox::Ok); + } + } +} + +void LoginWindow::on_btn_login_clicked() +{ + login_ipAddr = ui->le_ipAddr->text(); + login_port = ui->le_port->text(); + + tcpClient = new QTcpSocket(this); + tcpClient->connectToHost(login_ipAddr, login_port.toInt()); + + time = new QTimer(this); + time->setInterval(100); + + connect(time, SIGNAL(timeout()), this, SLOT(timerFinish())); + time->start(); +} + +void LoginWindow::on_btn_logout_clicked() +{ + this->close(); +} diff --git a/mjpg_streamer/loginwindow.h b/mjpg_streamer/loginwindow.h new file mode 100644 index 00000000..c9735da5 --- /dev/null +++ b/mjpg_streamer/loginwindow.h @@ -0,0 +1,37 @@ +#ifndef LOGINWINDOW_H +#define LOGINWINDOW_H + +#include +#include +#include +#include "mainwindow.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class LoginWindow; } +QT_END_NAMESPACE + +class LoginWindow : public QMainWindow +{ + Q_OBJECT + +public: + LoginWindow(QWidget *parent = nullptr); + ~LoginWindow(); + +private slots: + void timerFinish(); + void on_btn_login_clicked(); + void on_btn_logout_clicked(); + +private: + Ui::LoginWindow *ui; + QString login_ipAddr; + QString login_port; + int waitCnt; + QTimer *time; + QString text; + QTcpSocket *tcpClient; + MainWindow *main; + void init(); +}; +#endif // LOGINWINDOW_H diff --git a/mjpg_streamer/main.cpp b/mjpg_streamer/main.cpp new file mode 100644 index 00000000..74953e8b --- /dev/null +++ b/mjpg_streamer/main.cpp @@ -0,0 +1,13 @@ +#include "loginwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + LoginWindow w; + + w.setWindowFlags(Qt::FramelessWindowHint); + w.show(); + return a.exec(); +} diff --git a/mjpg_streamer/mainwindow.cpp b/mjpg_streamer/mainwindow.cpp new file mode 100644 index 00000000..b67f8cbe --- /dev/null +++ b/mjpg_streamer/mainwindow.cpp @@ -0,0 +1,97 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + main_btnStartSta = true; + main_state = true; +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::init() +{ + ui->lb_vedio->setScaledContents(main_state); + this->setWindowTitle("Camera Client"); + this->setWindowFlags(this->windowFlags()&~(Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint)); +} + +void MainWindow::on_btn_start_clicked() +{ + QString name; + + if ((main_btnStartSta = !main_btnStartSta) == false) + { + name = "Stop"; + getPixmap = new GetPixmap; + thread = new QThread(); + getPixmap->get_ipAddr = main_ipAddr; + getPixmap->get_port = main_port; + + getPixmap->moveToThread(thread); + + void (GetPixmap:: *sig_getOnePixmap)(QPixmap) = &GetPixmap::get_getOnePixmap; + void (MainWindow:: *slot_getOnePixmap)(QPixmap) = &MainWindow::main_getOnePixmap; + + connect(getPixmap,sig_getOnePixmap,this,slot_getOnePixmap); + thread->start(); + connect(thread,&QThread::started,getPixmap,&GetPixmap::run); + } + else + { + name = "Start"; + thread->exit(); + disconnect(getPixmap,SIGNAL(get_getOnePixmap(QPixmap)),this,NULL); + delete getPixmap; + } + + ui->btn_start->setText(name); +} + +void MainWindow::on_btn_screenshot_clicked() +{ + save_pix = show_pix; + + if (save_pix.isNull()) + { + QMessageBox::information(this,tr("Info"),tr("There are no images to save.")); + } + else + { + QString fileName = QFileDialog::getSaveFileName(this,tr("Save File"),QDir::homePath(),tr("jpegfile(*.jpg)")); + + if (fileName.isEmpty()) + { + QMessageBox::information(this,"Infor",tr("Save Cancel")); + return; + } + + save_pix.save(fileName); + } +} + + +void MainWindow::on_btn_quit_clicked() +{ + this->close(); +} + + +void MainWindow::main_getOnePixmap(QPixmap pix) +{ + show_pix = pix; + + ui->lb_vedio->setPixmap(show_pix); + ui->lb_vedio->show(); +} diff --git a/mjpg_streamer/mainwindow.h b/mjpg_streamer/mainwindow.h new file mode 100644 index 00000000..b5245e16 --- /dev/null +++ b/mjpg_streamer/mainwindow.h @@ -0,0 +1,44 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include "getpixmap.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + QString main_ipAddr; + QString main_port; + + void init(); + + +private slots: + void on_btn_start_clicked(); + void on_btn_screenshot_clicked(); + void on_btn_quit_clicked(); + void main_getOnePixmap(QPixmap); + +private: + Ui::MainWindow *ui; + bool main_state = false; + bool main_btnStartSta = false; + GetPixmap *getPixmap; + QThread *thread; + + QPixmap show_pix; + QPixmap save_pix; +}; + +#endif // MAINWINDOW_H + diff --git a/mjpg_streamer/mainwindow.ui b/mjpg_streamer/mainwindow.ui new file mode 100644 index 00000000..eaa70142 --- /dev/null +++ b/mjpg_streamer/mainwindow.ui @@ -0,0 +1,46 @@ + + + MainWindow + + + + 0 + 0 + 658 + 384 + + + + MainWindow + + + + + + 0 + 0 + 658 + 28 + + + + + ros + + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/mjpg_streamer/mjpg_stream_browser.pro b/mjpg_streamer/mjpg_stream_browser.pro new file mode 100644 index 00000000..68caf19c --- /dev/null +++ b/mjpg_streamer/mjpg_stream_browser.pro @@ -0,0 +1,47 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2023-04-16T19:37:18 +# +#------------------------------------------------- + +QT += core gui +QT += network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = mjpg_stream_browser +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 + +SOURCES += \ + getpixmap.cpp \ + loginwindow.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + getpixmap.h \ + loginwindow.h \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +QMAKE_CXXFLAGS += -std=c++0x diff --git a/mjpg_streamer/mjpg_stream_browser.pro.user b/mjpg_streamer/mjpg_stream_browser.pro.user new file mode 100644 index 00000000..ddb82d0a --- /dev/null +++ b/mjpg_streamer/mjpg_stream_browser.pro.user @@ -0,0 +1,279 @@ + + + + + + EnvironmentId + {2308cb99-24d4-4815-a674-8d51d824ca03} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + 桌面 + 桌面 + {2651a340-77c7-4d40-971c-de5a4e32646d} + 0 + 0 + 0 + + /home/wangjing/build-mjpg_stream_browser-unknown-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/wangjing/build-mjpg_stream_browser-unknown-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + 部署 + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + mjpg_stream_browser + + Qt4ProjectManager.Qt4RunConfiguration:/home/wangjing/mjpg_stream_browser/mjpg_stream_browser.pro + + 3768 + false + true + true + false + false + true + + /home/wangjing/build-mjpg_stream_browser-unknown-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 21 + + + Version + 21 + + diff --git a/mjpg_streamer/最小路径.txt b/mjpg_streamer/最小路径.txt new file mode 100644 index 00000000..2d2c222a --- /dev/null +++ b/mjpg_streamer/最小路径.txt @@ -0,0 +1,137 @@ +下面是一个简单的使用Qt Creator和OpenCV搭建可以播放RTSP视频的界面的示例。本例中为了展示更多读者可能需要的部分,比例较为详细: + +首先,在Qt Creator中创建一个新的Qt Widgets应用程序。 + +添加QLabel作为显示视频图像的容器,并将该标签放置在MainWindow的UI界面上。 + +使用信号/槽机制连接QPushButton控件以提供“Play”和“Stop”按钮的功能。 + +在窗口的构造函数中,初始化OpenCV中的VideoCapture对象。此处调用set函数配置FrameRingBuffer的长度,从而满足读取较慢反应不够,其余只调用isOpened方法判断是否可正常读入即可。 + +稍后,你可以编写一个槽函数来读取视频流并将帧显示在QLabel中。 + +mainwindow.h文件: + +cpp +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +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_playButton_clicked(); + + void on_stopButton_clicked(); + + void readFrame(); + +private: + Ui::MainWindow *ui; + cv::VideoCapture mCapture; // Video capture object for reading RTSP stream + cv::Mat mFrame; // Mat object to store the video frame + bool mPlaying; // Flag to indicate if video playback is in progress +}; + +#endif // MAINWINDOW_H +mainwindow.cpp文件: + +cpp +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + // Set up VideoCapture object for reading RTSP stream + //调节参数 取决于对视频流带宽要求以及本机性能 适点即可 + mCapture.set(cv::CAP_PROP_BUFFERSIZE,5); + mCapture.open("rtsp://localhost:8554/unicast"); //修改RTSP地址 + + if (!mCapture.isOpened()) + { + qCritical() << "Failed to open RTSP stream."; + return; + } + + //初始化mFrame和mPlaying标记 + mPlaying = false; + + //设置Paly按钮为不可用状态 + ui->playButton->setEnabled(true); + ui->stopButton->setEnabled(false); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_playButton_clicked() +{ + if (!mPlaying) + { + mPlaying = true; + + // 每20毫秒读取一帧并在QLabel显示该帧图像 + QTimer *timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, &MainWindow::readFrame); + timer->start(20); + + //设置控件状态 + ui->playButton->setEnabled(false); + ui->stopButton->setEnabled(true); + } +} + +void MainWindow::readFrame() +{ + if (mCapture.read(mFrame)) + { + QImage frameImage((uchar*)mFrame.data, mFrame.cols, mFrame.rows, QImage::Format_RGB888); + QPixmap framePixmap = QPixmap::fromImage(frameImage.rgbSwapped()); + // .rgbSwapped()因为OpenCV默认使用BGR,而Qt使用RGB,必须交换颜色通道才能正确地显示 + + ui->videoLabel->setPixmap(framePixmap.scaled(ui->videoLabel->size(), Qt::KeepAspectRatio)); + } +} + +void MainWindow::on_stopButton_clicked() +{ + if (mPlaying) + { + mPlaying = false; + + //停止计时器,断开信号/槽连接 + QObject::disconnect(this, &MainWindow::readFrame, nullptr, nullptr); + + //设置控件状态 + ui->playButton->setEnabled(true); + ui->stopButton->setEnabled(false); + + //清除QLabel + ui->videoLabel->clear(); + } +} +注意,上述代码中的RTSP地址需要根据实际情况进行修改。在这里只是将RTSP的地址写为本机地址从而获得源不被限制的可播放视频。 + +此示例仅演示了如何从RTSP流读取一帧并在QLabel中显示该帧图像。你可以使用QSpinBox或QSlider等Qt控件来添加FPS和播放进度条的功能。以及像界面美化,异常处理,带宽控制和多线程优化等其余实现可能 Related Post 中可能会涉及。 + diff --git a/任务规划.h b/任务规划.h new file mode 100644 index 00000000..5a89ca17 --- /dev/null +++ b/任务规划.h @@ -0,0 +1,124 @@ +#include +#include +#include +#include + +using namespace std; + +// 坐标类 +class Point { +public: + double x, y; + Point(double nx, double ny) : x(nx), y(ny) {} +}; + +// 图类 +class Graph { +public: + Graph(vector points) { + for (int i = 0; i < points.size(); i++) { + vector row; + for (int j = 0; j < points.size(); j++) { + if (i == j) { + row.push_back(0); + } else { + double dis = sqrt(pow(points[i].x - points[j].x, 2) + pow(points[i].y - points[j].y, 2)); + row.push_back(dis); + } + } + matrix.push_back(row); + } + } + + // Dijkstra算法求解最短路径,网上嫖的 + vector get_shortest_path(int start_index, int end_index) { + int node_num = matrix.size(); + vector visited(node_num, false); + vector prev(node_num, -1); + vector dist(node_num, INFINITY); + dist[start_index] = 0; + + // Dijkstra算法 + for (int i = 0; i < node_num; i++) { + int u = -1; + double min_dist = INFINITY; + // 找到未访问过的距离最小的节点u + for (int j = 0; j < node_num; j++) { + if (!visited[j] && dist[j] < min_dist) { + u = j; + min_dist = dist[j]; + } + } + if (u == -1) break; + visited[u] = true; + // 更新u的邻接节点v的距离和前驱 + for (int v = 0; v < node_num; v++) { + if (!visited[v] && matrix[u][v] < INFINITY) { + double new_dist = dist[u] + matrix[u][v]; + if (new_dist < dist[v]) { + dist[v] = new_dist; + prev[v] = u; + } + } + } + } + + // 输出最短路径 + vector path; + int u = end_index; + while (prev[u] != -1) { + path.push_back(points[u]); + u = prev[u]; + } + reverse(path.begin(), path.end()); + + return path; + } + +private: + vector> matrix; // 邻接矩阵,用来存放 + vector points; // 顶点坐标列表 + const double INFINITY = std::numeric_limits::infinity(); // 无穷大 +}; + +// 顶点序列类 +class VertexSequence { +public: + // 构造函数 + VertexSequence(vector points, Graph graph) { + this->points = points; + this->graph = graph; + start_index = 0; // 初始起点为第一个点 + end_index = -1; // 结尾没有定义 + sequence = graph.get_shortest_path(start_index, end_index); // 计算最短路径 + } + + // 重新排序方法 + void sort(Point current_point) { + // 计算起点到各顶点的距离 + vector distances; + for (int i = 0; i < sequence.size(); i++) { + double dis = sqrt(pow(current_point.x - sequence[i].x, 2) + pow(current_point.y - sequence[i].y, 2)); + distances.push_back(dis); + } + // 对顶点序列进行重新排序 + sort(sequence.begin(), sequence.end(), [&distances](const Point& lhs, const Point& rhs) { + int index_lhs = &lhs - &distances[0]; + int index_rhs = &rhs - &distances[0]; + return distances[index_lhs] < distances[index_rhs]; + }); + } + + Point pop() { + Point next_point = sequence.front(); + sequence.erase(sequence.begin()); + return next_point; + } + +private: + vector points; // 顶点坐标 + Graph graph; // 连通图 + int start_index; // 起点 + int end_index; // 结尾 + vector sequence; // 顶点序列 +}; diff --git a/任务队列简单示例/示例main.txt b/任务队列简单示例/示例main.txt new file mode 100644 index 00000000..a5e6822d --- /dev/null +++ b/任务队列简单示例/示例main.txt @@ -0,0 +1,34 @@ +#include "类.h" + +int main() { + PositionQueue queue; + + string input_data; + while (true) { + getline(cin, input_data); + if (input_data.empty()) continue; // 如果输入为空,跳过 + + // 解析json + size_t pos1 = input_data.find("x"); + size_t pos2 = input_data.find(",", pos1+3); + size_t pos3 = input_data.find("y", pos2+1); + size_t pos4 = input_data.find(",", pos3+3); + size_t pos5 = input_data.find("z", pos4+1); + size_t pos6 = input_data.find("}", pos5+3); + + if (pos1 == string::npos || pos2 == string::npos || pos3 == string::npos || pos4 == string::npos || pos5 == string::npos || pos6 == string::npos) { + cout << "输入格式错误,请重新输入" << endl; //string::nops就是最大格式长度 + continue; + } + + double x = stod(input_data.substr(pos1+3, pos2-pos1-3)); + double y = stod(input_data.substr(pos3+3, pos4-pos3-3)); + double z = stod(input_data.substr(pos5+3, pos6-pos5-3)); + + queue.insert(Position(x, y, z)); + + queue.output_sorted(); + } + + return 0; +} \ No newline at end of file diff --git a/任务队列简单示例/类.h b/任务队列简单示例/类.h new file mode 100644 index 00000000..436ffdf3 --- /dev/null +++ b/任务队列简单示例/类.h @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +using namespace std; + +// 位置信息类 +class Position { +public: + Position(double x, double y, double z) : _x(x), _y(y), _z(z) { } + double distance() const { return sqrt(_x*_x + _y*_y + _z*_z); } + friend bool operator<(const Position& a, const Position& b) { return a.distance() > b.distance(); } // 定义比较函数,用于排序 + friend ostream& operator<<(ostream& os, const Position& pos) { + os << "{\"x\":" << pos._x << ",\"y\":" << pos._y << ",\"z\":" << pos._z << "}"; + return os; + } +private: + double _x; + double _y; + double _z; +}; + +// 队列类 +class PositionQueue { +public: + PositionQueue() { } + void insert(const Position& pos) { _queue.push(pos); } // 插入 + void output_sorted() { // 输出 + vector positions; + while (!_queue.empty()) { + positions.push_back(_queue.top()); + _queue.pop(); + } + for (auto& pos : positions) { + cout << pos << endl; + } + } +private: + priority_queue _queue; +}; + + diff --git a/发送端.h b/发送端.h new file mode 100644 index 00000000..1df890f6 --- /dev/null +++ b/发送端.h @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 1024 // JSON数据分片大小,对应的是接收端的那个size + +using namespace std; + +int main() { + int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建socket + if (sockfd < 0) { + perror("socket error"); + exit(1); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 目的主机IP + addr.sin_port = htons(8888); // 目的主机端口号 + + if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { // 连接目标主机 + perror("connect error"); + exit(1); + } + + Json::Value json_data; + json_data["x"] = 0"; + json_data["y"] = "1"; + json_data["z"] = "1"; + string json_str = json_data.toStyledString(); // 编码 + + char buf[BUF_SIZE]; + int len = json_str.length(), count = 0; + + sprintf(buf, "%d", len); + send(sockfd, buf, strlen(buf), 0); + + for (int i = 0; i < len; i += BUF_SIZE) { + int size = min(BUF_SIZE, len - i); + memcpy(buf, json_str.c_str() + i, size); + send(sockfd, buf, size, 0); + printf("Send JSON packet %d\n", ++count); + usleep(10000); // 10msxunhuan + } + + close(sockfd); + + return 0; +} diff --git a/接收端.h b/接收端.h new file mode 100644 index 00000000..f9f4b786 --- /dev/null +++ b/接收端.h @@ -0,0 +1,78 @@ +//接收端 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +int main() { + //创建 + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket error"); + exit(1); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(8888); // 绑定端口号,改! + + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("error"); + exit(1); + } + + if (listen(sockfd, 5) < 0) { // 监听socket + perror("listen error"); + exit(1); + } + + int connfd; + struct sockaddr_in cliaddr; + socklen_t clilen = sizeof(cliaddr); + + if ((connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen)) < 0) { // 接受连接 + perror("accept error"); + exit(1); + } + + char buf[BUF_SIZE]; + int len, count = 0; + + memset(buf, 0, sizeof(buf)); + recv(connfd, buf, size, 0); // 接收JSON数据长度size,改! 通常是1024 + len = atoi(buf); + + string json_str; + for (int i = 0; i < len; i += BUF_SIZE) { // 分批接收JSON数据 + int size = min(BUF_SIZE, len - i); + recv(connfd, buf, size, 0); + printf("Receive JSON packet %d\n", ++count); // 打印接收的JSON数据包编号 + json_str.append(buf, size); + usleep(10000); // 10ms循环 + } + + Json::Value json_data; + Json::Reader reader; + if (!reader.parse(json_str, json_data)) { // 解码为JSON对象 + cerr << "parse error" << endl; + exit(1); + } + + cout << "x: " << json_data["x"].asString() << endl; + cout << "y: " << json_data["y"].asString() << endl; + cout << "z: " << json_data["z"].asString() << endl; + + close(connfd); + close(sockfd); + + return 0; +} diff --git a/机器狗视频传输.h b/机器狗视频传输.h new file mode 100644 index 00000000..e636dabd --- /dev/null +++ b/机器狗视频传输.h @@ -0,0 +1,42 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + const std::string stream_url = "http://localhost:8080/?action=stream"; + + cv::VideoCapture cap(stream_url); + if (!cap.isOpened()) + { + qDebug() << "Failed to open MJPEG Streamer video capture"; + return; + } + + QTimer* timer = new QTimer(this); + connect(timer, &QTimer::timeout, [=]() + { + cv::Mat frame; + cap.read(frame); + if (frame.empty()) + { + qDebug() << "Failed to capture MJPEG Streamer video frame"; + return; + } + + QImage qimg((uchar*)frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); + + ui->label->setPixmap(QPixmap::fromImage(qimg)); + }); + + timer->start(33); +} + +MainWindow::~MainWindow() +{ + delete ui; +} \ No newline at end of file