红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)
需求
有10台服务器,每台8路摄像头,8路拼接处理后单个服务器输出8*1920*1080的图片数据,每台服务器输出各自的八路,实现缩放拽拖等。
ReadMe
最终采用的方案
步骤一:客户端获取每个服务器在本地的实际rect(每个服务器在本地的原始图片拼接范围);
步骤二:依据缩放比例系数和鼠标的位置计算出rectVirtual(按照指定点缩小放大后的图片拼接范围);
步骤三:每个服务器所处的rectVirtual与实际显示的窗口rect()取交集,更新的每个服务器显示的范围;
步骤四:分别组装获取指令(一个线程负责一个块区域),
将获取指令(x,y,width,height,scale)发送(Json);
步骤五:接收更新显示范围后的协议数据;
步骤六:解析协议获取rgb888数据:总长度(包括总长度4字节)(4字节)+ 图像宽度(2字节)+ 图像原始高度(2字节)+ 显示宽度(2字节) + 显示高度(2字节) + 图像数据(n字节);
步骤七:使用服务器获取的显示数据刷新对应的显示区域,重复步骤二。
注意:软件模拟时间主要耗在服务器对图像的变换,使用本地硬解码或者库之后(直接调库)或者从服务器获取,其时间达到20ms左右,可达到理想效果。
Demo
下载地址:javascript:void(0)
演示图
客户端关键代码(ImageWidget控件)
imagewidget.h
#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H
#include <QWidget>
#include <QThread>
#include <QRectF>
#include "tcpclient.h"
#include <QElapsedTimer>
/************************************************************\
* 类名:ImageWidget
* 描述:1-10路固定19200*1080图像拼接
* 使用:
* 1.构建一个ImageWidget类
* 2.设置主机地址setHostAddreess,填入一一对应的服务器ip地址list和port端口list
* 3.调用start
* 函数:
* isRunning() - 是否在运行
* setHostAddreess() - 设置服务器地址,如:127.0.0.1:20001,127.0.0.1:20002,则传入QList("127.0.0.1","127.0.01"),QList(20001,20002)
* start() - 开启运行
* stop() - 停止运行
* 作者:红模仿 QQ:21497936
* 版本 日期 描述
* v1.0 2018年3月12日 已优化
\************************************************************/
namespace Ui {
class ImageWidget;
}
class ImageWidget : public QWidget
{
Q_OBJECT
public:
explicit ImageWidget(QWidget *parent = 0);
~ImageWidget();
bool isRunning();
signals:
void signalfinished();
public slots:
void start();
void stop();
void setHostAddreess(QList<QString> listIp, QList<quint16> listPort);
void init();
protected slots:
void recvOneImage(int index, QByteArray& data, int fullWidth, int fullHeight, int width, int height, int time);
protected:
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
private slots:
void finished();
private:
Ui::ImageWidget *ui;
QList<TcpClient *> _listTcpClient;
QList<QThread *> _listTcpClientThread;
bool _ok;
QPoint _pointLast;
double _add_scale_step;
double _dec_scale_step;
double _scale;
QList<QRectF> _listRectRangeFullImage; // 图片的实际尺寸
QList<QRectF> _listRectRangeFullImageVirtual; // 虚拟显示框框
QList<QRectF> _listRectRangeGetImage; // 图像数据
QList<QRectF> _listRectRangeImageOldShow; // 旧区域
QList<QRectF> _listRectRangeImageShow; // 正常情况下的需要显示的部分
QList<QPixmap *> _listPixmap;
bool _initRectRangeFullImageVirtual;
QElapsedTimer _time;
int _serverNumber;
QList<QString> _listIp;
QList<quint16> _listPort;
QElapsedTimer _timerInverval;
};
#endif // IMAGEWIDGET_H
服务器代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QImage>
#include <QTcpServer>
#include <QTcpSocket>
#include <QByteArray>
#define SCALE_BASE (1000)
class QPaintEvent;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected slots:
void newConnection();
void readyRead();
void doImage(int x, int y, int width, int height, double scale);
void doImage(int x, int y, int width, int height, int vx, int vy, int vWidth, int vHeight);
protected:
void paintEvent(QPaintEvent *event) override;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QImage _image;
QTcpServer *_pTcpServer;
QTcpSocket * _pTcpSocket;
QByteArray _byteArrayJpg;
};
#endif // MAINWINDOW_H