———————-.pro—————————–
QT += core gui
QT += core gui widgets # 确保 widgets 模块被包含
CONFIG += link_pkgconfig
PKGCONFIG += opencv4
QT += multimedia multimediawidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
CameraWorker.cpp \
main.cpp \
mainwindow.cpp \
picDecode.c \
tcpsend.cpp \
udpsendthread.cpp
HEADERS += \
CameraWorker.h \
includes.h \
mainwindow.h \
picDecode.h \
tcpsend.h \
udpsendthread.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
————–CameraWorker.h——————————
#ifndef CAMERAWORKER_H
#define CAMERAWORKER_H
#include
#include
#include
#include
#include
class CameraWorker : public QObject {
Q_OBJECT
public:
CameraWorker(QObject *parent = nullptr);
~CameraWorker();
void startCamera(int deviceIndex);
void stopCamera();
signals:
void frameCompress(const QByteArray &frameCompressData);
private:
cv::VideoCapture capture;
QMutex mutex;
bool isRunning;
void process();
void compressImageToMemory(const QImage &image);
};
#endif // CAMERAWORKER_H
—————————–includes.h——————————
#ifndef INCLUDES_H
#define INCLUDES_H
#define BASEPORT
#ifdef SKYPORT
#define LOCAL_IP “192.168.0.108”
#define LOCAL_PORT 12345
#define TARGET_IP “192.168.0.107”
#define TARGET_PORT 12000
#endif
#ifdef BASEPORT
#define LOCAL_IP “192.168.0.107”
#define LOCAL_PORT 12000
#define TARGET_IP “192.168.0.108”
#define TARGET_PORT 12345
#endif
#endif // INCLUDES_H
———————mainwindow.h—————————————
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include “CameraWorker.h” // 添加这一行以包含 CameraWorker
#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 updateCameraFrame(const QImage &image);
void debugslot(const QByteArray &data);
private:
Ui::MainWindow *ui;
CameraWorker *cameraWorker; // 确保这个声明是正确的
QThread *cameraThread;
void bindThreadToCPU3(QThread *thread);
};
#endif // MAINWINDOW_H
—————————tcpsend.h————实际没用上—————
#ifndef TCPSEND_H
#define TCPSEND_H
#include
#include
#include
#include
class TcpSend : public QThread
{
Q_OBJECT
public:
explicit TcpSend(QObject *parent = nullptr);
~TcpSend();
void setTargetIp(const QString &ip);
void setTargetPort(quint16 port);
signals:
void dataReceived(const QByteArray &data);
protected:
void run() override;
private:
QTcpSocket *tcpSocket;
QString targetIp;
quint16 targetPort;
public slots:
void sendData(); // 实现发送功能
};
#endif // TCPSEND_H
——————————udpsendthread.h———————-
// udpsendthread.h
#ifndef UDPSENDTHREAD_H
#define UDPSENDTHREAD_H
#include
#include
#include
class UdpSendThread : public QObject
{
Q_OBJECT
public:
unsigned int times_rcv = 0;
int flag_rcv = 0;
int udpbagflag;
unsigned int datasize_max;
int connect_flag =0;
QByteArray picData;
public:
explicit UdpSendThread(QObject *parent = nullptr);
~UdpSendThread();
public slots:
void process(); // 模拟数据接收并触发dataReceived信号
void sendData(const QByteArray &data); // 实现UDP发送功能
void dataReceived(); // 当接收到数据时发出此信号
signals:
void frameCaptured(const QImage &image);
private:
QUdpSocket* udpSocket;
QString targetIP;
quint16 targetPort;
QImage decompressImageFromMemory( QByteArray &compressedData);
signals:
void dataRec(const QByteArray &data);
public slots:
void processData();
};
#endif // UDPSENDTHREAD_H
———————————–CameraWorker.cpp————————-
#include “CameraWorker.h”
#include
#include
#include
#include
#include
#include “includes.h”
CameraWorker::CameraWorker(QObject *parent) : QObject(parent), isRunning(false) {}
CameraWorker::~CameraWorker() {
stopCamera();
}
void CameraWorker::startCamera(int deviceIndex) {
if (capture.isOpened()) return;
capture.open(deviceIndex);
if (!capture.isOpened()) {
qDebug() << "无法打开摄像头"; // 这里可以正常使用 qDebug()
return;
}
capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度
capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度
capture.set(cv::CAP_PROP_FPS, 25); // 设置帧率
capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整)
capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整)
QThread::msleep(100); // 暂停以让设置生效
isRunning = true;
QThread *thread = QThread::create([this]() { process(); });
connect(thread, &QThread::finished, this, &CameraWorker::deleteLater);
thread->start();
}
void CameraWorker::stopCamera() {
QMutexLocker locker(&mutex);
isRunning = false;
capture.release();
}
void CameraWorker::process() {
#ifdef SKYPORT
while (true) {
{
QMutexLocker locker(&mutex);
if (!isRunning) break;
}
cv::Mat frame;
capture >> frame;
if (frame.empty()) continue;
cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);
size_t memory_usage_qimage = image.width() * image.height() * image.depth() / 8;
// qDebug() << "QImage memory usage: " << memory_usage_qimage / 1024.0 / 1024.0 << " MB";
compressImageToMemory(image);
//emit frameCaptured(image);
QThread::msleep(50); // 限制帧率
}
#endif
}
void CameraWorker::compressImageToMemory(const QImage &image) {
// 创建一个 QBuffer 对象,它将充当内存缓冲区
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
// 创建 QImageWriter 对象,用于将图像压缩并写入内存缓存
QImageWriter writer(&buffer, "JPEG"); // 使用 JPEG 格式进行压缩,可以选择其他格式
// 设置压缩质量(如果适用)
writer.setQuality(80); // 设定压缩质量,范围是 0-100
// 将 QImage 压缩并写入缓存
if (writer.write(image)) {
// 压缩成功后,获取压缩后的数据大小
size_t compressedSize = buffer.size();
//qDebug() << "Compressed image size: " << compressedSize / 1024.0 / 1024.0 << " MB";
// 你可以从缓存中获取压缩后的数据
QByteArray compressedData = buffer.data();
// 例如,可以将数据保存到文件,或者发送到网络
emit frameCompress(compressedData);
}
else
{
qDebug() << "Image compression failed!";
}
}
----------------------------------main.cpp------------------------
#include "mainwindow.h"
#include
#include
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
int cpu = sched_getcpu();
qDebug() << "Running on CPU: " << cpu ;
return a.exec();
}
--------------------------------CameraWorker.cpp-------------------
#include "CameraWorker.h"
#include
#include
#include
#include
#include
#include “includes.h”
CameraWorker::CameraWorker(QObject *parent) : QObject(parent), isRunning(false) {}
CameraWorker::~CameraWorker() {
stopCamera();
}
void CameraWorker::startCamera(int deviceIndex) {
if (capture.isOpened()) return;
capture.open(deviceIndex);
if (!capture.isOpened()) {
qDebug() << "无法打开摄像头"; // 这里可以正常使用 qDebug()
return;
}
capture.set(cv::CAP_PROP_FRAME_WIDTH, 640); // 设置宽度
capture.set(cv::CAP_PROP_FRAME_HEIGHT, 480); // 设置高度
capture.set(cv::CAP_PROP_FPS, 25); // 设置帧率
capture.set(cv::CAP_PROP_EXPOSURE, -4); // 设置曝光(根据需要调整)
capture.set(cv::CAP_PROP_GAIN, 0); // 设置增益(根据需要调整)
QThread::msleep(100); // 暂停以让设置生效
isRunning = true;
QThread *thread = QThread::create([this]() { process(); });
connect(thread, &QThread::finished, this, &CameraWorker::deleteLater);
thread->start();
}
void CameraWorker::stopCamera() {
QMutexLocker locker(&mutex);
isRunning = false;
capture.release();
}
void CameraWorker::process() {
#ifdef SKYPORT
while (true) {
{
QMutexLocker locker(&mutex);
if (!isRunning) break;
}
cv::Mat frame;
capture >> frame;
if (frame.empty()) continue;
cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage image(frame.data, frame.cols, frame.rows, frame.step[0], QImage::Format_RGB888);
size_t memory_usage_qimage = image.width() * image.height() * image.depth() / 8;
// qDebug() << "QImage memory usage: " << memory_usage_qimage / 1024.0 / 1024.0 << " MB";
compressImageToMemory(image);
//emit frameCaptured(image);
QThread::msleep(50); // 限制帧率
}
#endif
}
void CameraWorker::compressImageToMemory(const QImage &image) {
// 创建一个 QBuffer 对象,它将充当内存缓冲区
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
// 创建 QImageWriter 对象,用于将图像压缩并写入内存缓存
QImageWriter writer(&buffer, "JPEG"); // 使用 JPEG 格式进行压缩,可以选择其他格式
// 设置压缩质量(如果适用)
writer.setQuality(80); // 设定压缩质量,范围是 0-100
// 将 QImage 压缩并写入缓存
if (writer.write(image)) {
// 压缩成功后,获取压缩后的数据大小
size_t compressedSize = buffer.size();
//qDebug() << "Compressed image size: " << compressedSize / 1024.0 / 1024.0 << " MB";
// 你可以从缓存中获取压缩后的数据
QByteArray compressedData = buffer.data();
// 例如,可以将数据保存到文件,或者发送到网络
emit frameCompress(compressedData);
}
else
{
qDebug() << "Image compression failed!";
}
}
-------------------mainwindow.cpp--------------------------------
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include “udpsendthread.h”
#include “tcpsend.h”
#include
#include “UdpReceiver.h”
#include “includes.h”
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), cameraWorker(new CameraWorker)
{
ui->setupUi(this);
#ifdef SKYPORT
// 创建线程
cameraThread = new QThread;
cameraWorker->moveToThread(cameraThread);
connect(cameraThread, &QThread::started, [this]() {
cameraWorker->startCamera(0); // 打开默认摄像头
});
connect(cameraThread, &QThread::finished, cameraWorker, &CameraWorker::deleteLater);
bindThreadToCPU3(cameraThread);
cameraThread->start();
#endif
// 创建线程和数据发送对象
QThread* udpthread = new QThread();
UdpSendThread* udpSendThread = new UdpSendThread();
// 将 udpSendThread 移动到新线程
udpSendThread->moveToThread(udpthread);
// 使用lambda函数启动信号槽
QObject::connect(udpthread, &QThread::started, udpSendThread, &UdpSendThread::process);
// 绑定信号槽,当udpSendThread接收到数据后发送数据
//QObject::connect(udpSendThread, &UdpSendThread::dataReceived, udpSendThread, &UdpSendThread::sendData);
QObject::connect(udpSendThread, &UdpSendThread::frameCaptured, this, &MainWindow::updateCameraFrame);
QObject::connect(udpSendThread, &UdpSendThread::dataRec, [](const QByteArray &data) {
qDebug() << "Received data:" << data;
});
bindThreadToCPU3(udpthread);
// 启动线程
udpthread->start();
connect(cameraWorker, &CameraWorker::frameCompress, udpSendThread, &UdpSendThread::sendData);
}
MainWindow::~MainWindow() {
cameraThread->quit();
cameraThread->wait();
delete ui;
}
void MainWindow::updateCameraFrame(const QImage &image) {
ui->cameraLabel->setPixmap(QPixmap::fromImage(image)); // 假设你在 UI 中有一个 QLabel 名为 cameraLabel
}
void MainWindow::bindThreadToCPU3(QThread *thread) {
// 获取当前线程的原生线程句柄
pthread_t nativeThread = pthread_self(); // 使用 pthread_self() 获取当前线程的句柄
// 创建 CPU 亲和性掩码
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(3, &cpuset); // 绑定到 CPU3
// 设置线程 CPU 亲和性
if (pthread_setaffinity_np(nativeThread, sizeof(cpu_set_t), &cpuset) != 0) {
qDebug() << "无法设置线程的 CPU 亲和性";
} else {
qDebug() << "线程成功绑定到 CPU3";
}
}
void MainWindow::debugslot(const QByteArray &data)
{
qDebug()<<"hello";
}
--------------------------------tcpsend.cpp------------------------------------
#include "tcpsend.h"
#include
#include
#include
TcpSend::TcpSend(QObject *parent) : QThread(parent), targetPort(0), tcpSocket(nullptr) {
tcpSocket = new QTcpSocket(this);
}
TcpSend::~TcpSend() {
if (tcpSocket->isOpen()) {
tcpSocket->close();
}
}
void TcpSend::setTargetIp(const QString &ip) {
targetIp = ip;
}
void TcpSend::setTargetPort(quint16 port) {
targetPort = port;
}
void TcpSend::run() {
// Bind thread to CPU3 (core 3)
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(3, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
// Connect to TCP server
tcpSocket->connectToHost(QHostAddress(targetIp), targetPort);
if (!tcpSocket->waitForConnected(3000)) {
qDebug() << "Error: Unable to connect to server!";
return;
}
/*
connect(this, &TcpSend::dataReceived, [this](const QByteArray &data) {
if (tcpSocket->isOpen()) {
tcpSocket->write(data);
tcpSocket->flush();
qDebug() << "Data sent: " << data;
}
});
*/
exec(); // Start the event loop for the thread
}
void TcpSend::sendData()
{
QByteArray data = "Hello from tcpsend"; // 要发送的数据
if (tcpSocket->isOpen()) {
tcpSocket->write(data);
tcpSocket->flush();
qDebug() << "tcp Data sent: " << data;
}
int cpu = sched_getcpu();
qDebug() << "Running on CPU: " << cpu ;
}
--------------------------------udpsendthread.cpp------------------------
// udpsendthread.cpp
#include "udpsendthread.h"
#include
#include
#include
#include
#include
#include “includes.h”
#include
#include
#include
#include
UdpSendThread::UdpSendThread(QObject *parent) : QObject(parent),
udpSocket(new QUdpSocket(this))
{
if (!udpSocket->bind(QHostAddress(LOCAL_IP), LOCAL_PORT))
{
qDebug() << "Bind failed!";
} else
{
qDebug() << "Bind successful!";
}
qDebug()<<"start startReceiving";
connect(udpSocket, &QUdpSocket::readyRead, this, &UdpSendThread::processData);
}
UdpSendThread::~UdpSendThread()
{
udpSocket->close();
delete udpSocket;
}
void UdpSendThread::process()
{
#ifdef BASEPORT
// 模拟数据接收,可以使用 QTimer 定时发出 dataReceived 信号
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &UdpSendThread::dataReceived);
timer->start(2); // 每5ms触发一次 dataReceived 信号
#endif
}
void UdpSendThread::sendData(const QByteArray & data)
{
//QByteArray datas = “Hello from udpsend”; // 要发送的数据
//udpSocket->writeDatagram(data, QHostAddress(targetIP), targetPort);
//qDebug() << "Data sent to" << targetIP << ":" << targetPort;
//int cpu = sched_getcpu();
//qDebug() << "Running on CPU: " << cpu ;
const int maxPacketSize = 65500; // UDP 单个数据包的最大数据量
int dataSize = data.size();
int offset = 0;
if (datasize_max < dataSize)
{
datasize_max = dataSize;
qDebug()<< "mx = " <
if (result == -1) {
qDebug() << "Failed to send data:" << udpSocket->errorString();
QThread::msleep(10); // 短暂等待后再重试,避免过多的 CPU 占用
continue;
}
bytesSent += result;
}
offset += packetSize; // 更新偏移量
QThread::msleep(10); // 短暂等待后再重试,避免过多的 CPU 占用
/*
int packetSize = qMin(maxPacketSize, dataSize – offset); // 每次发送的字节数
QByteArray packet = data.mid(offset, packetSize); // 获取分包数据
qint64 bytesSent = udpSocket->writeDatagram(packet, QHostAddress(TARGET_IP), TARGET_PORT);
offset += packetSize;
if (udpSocket->waitForBytesWritten(3000)) {
;
} else {
qDebug() << "Timeout or error while writing data.";
}
//QThread::msleep(2); // 限制帧率
*/
}
auto end = std::chrono::high_resolution_clock::now();
// 计算时间差
auto duration = std::chrono::duration_cast
//qDebug()<< "发送耗时: " << duration << "us" ;
}
void UdpSendThread::processData()
{
QImage rcvimage ;
QNetworkDatagram datagram ;
while (udpSocket->hasPendingDatagrams())
{
times_rcv = 0;
flag_rcv = 1;
datagram = udpSocket->receiveDatagram();
picData.append(datagram.data());
}
/*
QByteArray lastTwoBytes ;
if (datagram.data().size()>=2)
{
lastTwoBytes = datagram.data().right(2);
if ((lastTwoBytes[0]==0xFF)&&(lastTwoBytes[1]==0xD9))
{
udpbagflag = 1;
}
}
if (udpbagflag!=0)
{
rcvimage = decompressImageFromMemory(picData);
emit frameCaptured(rcvimage);
picData.clear();
udpbagflag = 0;
}
*/
//int cpu = sched_getcpu();
//qDebug() << "Running on CPU: " << cpu ;
}
QImage UdpSendThread::decompressImageFromMemory(QByteArray &compressedData)
{
int i = 0;
QBuffer buffer(&compressedData);
buffer.open(QIODevice::ReadOnly); // 打开为只读模式
// 使用 QImageReader 从 QBuffer 中读取压缩的图像
QImageReader reader(&buffer);
QImage image = reader.read();
if (image.isNull()) {
qDebug() << "Failed to decompress the image.";
}
return image;
}
void UdpSendThread::dataReceived()
{
QImage rcvimage ;
if (times_rcv < 60000)
{
times_rcv++;
}
if (times_rcv < 10)
{
return;
}
if (flag_rcv ==0)
{
return;
}
flag_rcv = 0;
rcvimage = decompressImageFromMemory(picData);
emit frameCaptured(rcvimage);
picData.clear();
}