打開攝像頭,服務器和客戶端傳輸攝像頭圖像數據

1:Camera Server

主要功能,打開攝像頭,接收客戶端請求

接收到客戶端請求“R”字符后開始傳輸攝像頭圖像。

#include "mainwindow.h"
#include "ui_mainwindow.h"#include<QDebug>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();for (const QCameraInfo &cameraInfo : availableCameras){ui->comboxCamera->addItem(cameraInfo.description());cameras.append(cameraInfo);}ca = new QCamera();//    foreach (const QCameraInfo &cameraInfo, cameras) {
//         if (cameraInfo.deviceName() == "mycamera")
//             ca = new QCamera(cameraInfo);
//     }foreach(const QCameraInfo &info, cameras){qDebug() << info.deviceName();}timer = new QTimer();connect(timer, &QTimer::timeout, [&](){cap->capture();});server = new QTcpServer(this);server->listen(QHostAddress::Any, 8888);connect(server, &QTcpServer::newConnection, this, &MainWindow::newConnect);//ServerListenSocket = new QTcpServer(this);	//服務器端監聽套接字 ServerListenSocketclientRequestSize = 0;socket = nullptr;}MainWindow::~MainWindow()
{delete ui;}void MainWindow::on_pushButton_open_clicked()
{//構造一下攝像頭對象ca = new QCamera(cameras[ui->comboxCamera->currentIndex()], this);//創建截圖對象的內存  截圖軟件要和攝像頭對象相互關聯cap = new QCameraImageCapture(ca);//將截圖信號與顯示截圖的槽函數關聯一下//連接  截圖信號和顯示截圖的槽函數  一旦發出imageCaptured截圖信號,就觸發截圖的槽函數connect(cap, &QCameraImageCapture::imageCaptured, this, &MainWindow::To_client);//將QCameraViewfinder綁定到一個控件上QCameraViewfinder *v = new QCameraViewfinder(ui->label);v->resize(ui->label->size());ca->setViewfinder(v);v->show();//啟動攝像頭ca->start();}void MainWindow::on_pushButton_start_clicked()
{//啟動時間循環timer->start(20);}void MainWindow::To_client(int index, QImage ima)
{//如果沒有鏈接的情況,就直接退出,不至于閃退if(socket == nullptr){return;}QByteArray byte;	//The QByteArray class provides an array of bytes.QBuffer buf(&byte);		//緩存區域//QString imageSize = "image size is:" + QString::number(frame.cols*frame.rows * 3) + " Bytes";//ui.info->addItem(imageSize);//圖像的大小(字節數)ima.save(&buf, "JPEG");	//將圖像以jpeg的壓縮方式壓縮了以后保存在 buf當中//QString jpegImageSize =  "jpeg image size is " + QString::number(buf.size()) + " Bytes";//ui.info->addItem(jpegImageSize);	//壓縮后的jpg圖像的大小(字節數)QByteArray ss = qCompress(byte, 1);//將壓縮后的jpg圖像 再用qCompress 壓縮 ,第二個參數1-9,9是最大壓縮率//QString ssSize="ss's size is "+ QString::number(ss.size()) + " Bytes";//ui.info->addItem(ssSize);//用qCompress 壓縮后的數據大小(字節數)//將壓縮后的字節串數據編碼成Base64方式,字節數會比壓縮前稍微變多一些QByteArray vv = ss.toBase64();  // QByteArray QByteArray::toBase64() const : Returns a copy of the byte array, encoded as Base64.//QString vvSize = "vv's size is "  + QString::number(vv.size()) + " Bytes";//ui.info->addItem(vvSize);	//編碼后的數據的大小QByteArray ba;QDataStream out(&ba, QIODevice::WriteOnly);	//二進制只寫輸出流out.setVersion(QDataStream::Qt_5_10);	//輸出流的版本/* 當操作復雜數據類型時,我們就要確保讀取和寫入時的QDataStream版本是一樣的,簡單類型,比如char,short,int,char* 等不需要指定版本也行 *//* 上面這些編解碼的過程肯定是會影響 時效性的,可以考慮只使用jpeg 壓縮后就進行發送 。 */out << (quint64)0;	//寫入套接字的經壓縮-編碼后的圖像數據的大小out << vv;			//寫入套接字的經壓縮-編碼后的圖像數據out.device()->seek(0);out << (quint64)(ba.size() - sizeof(quint64));//寫入套接字的經壓縮-編碼后的圖像數據的大小socket->write(ba);	//將整塊數據寫入套接字//update();	//更新界面}void MainWindow::newConnect()
{//ui->textEdit->append("An new client is connected!");socket = server->nextPendingConnection();	//返回已連接套接字對象connect(socket, SIGNAL(readyRead()), this, SLOT(readClientRequest()));	//將已連接套接字對象的準備好可讀信號readyRead與 readClientRequest()槽函數連接//connect(socket, SIGNAL(disconnected()), socket,SLOT(deleterLater()));	//已連接套接字的斷開信號與自身的稍后刪除信號相連接}void MainWindow::readClientRequest()
{QDataStream in(socket);      //綁定套接字in.setVersion(QDataStream::Qt_5_10);        //指定版本//如果客戶端發送過來的第一段數據塊的大小為0,說明確實是第一次交互if (clientRequestSize == 0){//客戶端發送過來的第一段數據塊的大小如果小于 64bit ,則說明:還未收到客戶端發送過來的前64bit的數據,這64bit的數據存儲了客戶端第一次請求包的大小(字節數)if (socket->bytesAvailable() < sizeof(quint16)){return;	//返回,繼續等待 接收數據,數據還在套接字緩存當中}else//如果 客戶端發送過來的第一段數據塊的大小>= 64bit 了{in >> clientRequestSize;//將數據的前64bit提取出來,存儲到quint64 類型的clientRequestSize}}if (socket->bytesAvailable() < clientRequestSize)//當前套接字緩沖區中存儲的數據如果小于clientRequestSize個字節{return;//返回,繼續等待 接收數據,數據還在套接字緩存當中}quint8 requestType;in >> requestType;//從套接字緩沖區中讀取 8bit的數據解釋為quint8類型,存儲到requestType中if (requestType == 'R')  //如果requestType是 'R'  字符R的ASCII值{connect(timer, &QTimer::timeout, [&](){cap->capture();});//將30ms時間到與發送數據的 SendData() 連接}}void MainWindow::on_pushButton_close_clicked()
{}void MainWindow::on_benSendImage_clicked()
{//啟動時間循環timer->start(20);
}

2客戶端

連接服務器,發送請求,接收數據后展示到界面上

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);imageBlockSize = 0;		//一次接收的圖像數據的大小(字節數)connect(&tcpSocket, SIGNAL(disconnect()), this, SLOT(connectionCloseByServer()));//套接字的斷開信號connect(&tcpSocket, SIGNAL(readyRead()), this, SLOT(ReceiveData()));//套接字一次可讀的觸發信號connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error()));//套接字的錯誤消息信號}MainWindow::~MainWindow()
{delete ui;
}//連接
void MainWindow::on_pushButton_clicked()
{connectToServer();bool k = connect(&tcpSocket, SIGNAL(connected()), this, SLOT(tcpConnected()));}//請求
void MainWindow::on_benRequest_clicked()
{sendRequest();
}void MainWindow::connectToServer()
{//連接到本機的8888端口tcpSocket.connectToHost(QHostAddress::LocalHost, 8888);//connectToHost是異步連接函數(不阻塞),一經調用結束立刻返回ui->textEdit->append("connecting to LocalHost port 8888...");//ui.connectToServer->setEnabled(false);}void MainWindow::sendRequest()//發送請求,請求視頻圖像序列
{QByteArray requestMessage;	//請求消息(字節數組)QDataStream out(&requestMessage, QIODevice::WriteOnly);//只讀輸出流out.setVersion(QDataStream::Qt_5_10);out << quint16(0) << quint8('R');//將請求消息的大小、長度(字節數)與請求消息 'R'寫入 輸出數據流outout.device()->seek(0);out << quint16(requestMessage.size() - sizeof(quint16));tcpSocket.write(requestMessage);//將輸出數據流中的數據寫入套接字ui->textEdit->append("Sending request...");//ui.requestVideo->setEnabled(false);}static int receiveCount = 0;//接收 readyRead()信號的觸發計數
static int imageCount = 0;	//接收到的圖像數據的計數void MainWindow::ReceiveData()
{receiveCount++;QString rCount = QString::number(receiveCount);//ui.receiveCount->setText(rCount);QByteArray message;//存放從服務器接收到的字節流數據QDataStream in(&tcpSocket);	//將客戶端套接字與輸入數據流對象in綁定in.setVersion(QDataStream::Qt_5_10);//設置數據流的版本/* 接收端的 這部分控制邏輯很重要 */if (imageBlockSize == 0){//如果imageBlockSize == 0 則說明,一幅圖像的大小信息還未傳輸過來//uint64是8字節的8 Bytes  64bit//判斷接收的數據是否有8字節(文件大小信息)//如果有則保存到basize變量中,沒有則返回,繼續接收數據if (tcpSocket.bytesAvailable() < (int)sizeof(quint64)){//一幅圖像的大小信息還未傳輸過來return;}in >> imageBlockSize;//一幅圖像的大小信息    //先接受圖片的大小if (imageBlockSize == (quint64)0xFFFFFFFFFFFFFFFF)//視頻結束的標注符{tcpSocket.close();QMessageBox::information(this, tr("warning"), tr("the video is end!"));return;}qDebug() << "imageBlockSize  is " << imageBlockSize;QString imageBlockS = "imageBlockSize  is " + QString::number(imageBlockSize) + "Bytes!";ui->textEdit->append(imageBlockS);message.resize(imageBlockSize);}//如果沒有得到一幅圖像的全部數據,則返回繼續接收數據if (tcpSocket.bytesAvailable() < imageBlockSize){return;}in >> message;//一幅圖像所有像素的完整字節流imageBlockSize = 0;//已經收到一幅完整的圖像,將imageBlockSize置0,等待接收下一幅圖像imageCount++;	//已接收的圖像計數QString iCount = QString::number(imageCount);//ui.imageCount->setText(iCount);ShowImage(message);	//顯示當前接收到的這一幅圖像}void MainWindow::connectionCloseByServer()//服務端主動斷開了已連接套接字
{ui->textEdit->append("Error:Connection closed by server!");tcpSocket.close();//關閉客戶端套接字//ui.connectToServer->setEnabled(true);
}void MainWindow::error()
{ui->textEdit->append(tcpSocket.errorString());tcpSocket.close();//ui.connectToServer->setEnabled(true);
}void MainWindow::tcpConnected()//套接字已經建立連接信號的處理槽函數
{//ui.requestVideo->setEnabled(true);
}void MainWindow::ShowImage(QByteArray ba)	//從接收到了字節流中,執行與服務器斷相反的操作:解壓縮、解釋為圖像數據
{QString ss = QString::fromLatin1(ba.data(), ba.size());QByteArray rc;rc = QByteArray::fromBase64(ss.toLatin1());QByteArray rdc = qUncompress(rc);QImage img;//img.loadFromData(rdc,"JPEG");//解釋為jpg格式的圖像img.loadFromData(rdc);//解釋為jpg格式的圖像ui->label->setPixmap(QPixmap::fromImage(img));ui->label->resize(img.size());update();
}

代碼下載連接

https://download.csdn.net/download/qianshanxue11/91264982

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87586.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87586.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87586.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android實現獲取前臺應用信息

Android實現獲取前臺應用信息 1.前言&#xff1a; 之前需要獲取在后臺運行的App信息&#xff0c;比如包名、版本這些常規的&#xff0c;今天是講解獲取在前臺的App信息&#xff0c;雖然App在前臺&#xff0c;但是具體的信息可能不知道&#xff0c;今天就嘗試獲取一下&#xf…

快訊|美團即時零售日訂單已突破1.2億,餐飲訂單占比過億

據美團內網公布信息顯示&#xff0c;截至22時54分&#xff0c;美團即時零售當日訂單已經突破了1.2億單&#xff0c;其中&#xff0c;餐飲訂單已超過1億單。 值得注意的是&#xff0c;就在當晚20時45分&#xff0c;美團內網曾顯示即時零售日訂單突破了1億。這也意味著&#xff…

pycharm2018配置gitee操作

一、gitee介紹及下載安裝 gitee介紹&#xff1a; gitee別名碼云&#xff0c;是中國的一個代碼托管平臺&#xff0c;類似于GitHub&#xff0c;基于Git技術&#xff0c;提供遠程倉庫托管、協作功能和開源社區服務&#xff0c;優勢包括訪問速度快、本地化服務和政策合規git和gite…

數據結構——棧的講解(超詳細)

數據結構——棧的講解&#xff08;超詳細&#xff09;-騰訊云開發者社區-騰訊云 #include"Stack.h" void STInit(ST* ps) {ps->arr NULL;ps->capacity ps->top 0; //總空間個數和有用空間個數都初始化為0 }void STDestroy(ST* ps) {if (ps -> arr) …

MySQL允許root用戶遠程連接

注意&#xff1a;在實際生產環境中&#xff0c;允許root用戶從任意主機&#xff08;‘%’&#xff09;連接存在安全風險&#xff0c;建議使用強密碼并限制訪問IP&#xff0c;或者創建具有必要權限的單獨用戶用于遠程連接。MySQL 配置遠程連接指南 1. 登錄 MySQL 服務器 mysql -…

STM32的 syscalls.c 和 sysmem.c

syscalls.c 是 STM32CubeIDE 自動生成的標準系統調用適配文件&#xff0c;用于裸機環境下支持 newlib 標準庫&#xff08;如 printf, scanf, malloc&#xff09;的運行。這份文件提供了標準庫運行所需的最小系統調用實現。現在我來逐段解析其作用&#xff0c;并補充你可能需要修…

Java零基礎筆記01(JKD及開發工具IDEA安裝配置)

1.Java簡介 Java是一種廣泛使用的計算機編程語言&#xff0c;由美國的Sun Microsystems公司&#xff08;Stanford University Network&#xff09;在1995年推出。Java以其跨平臺、面向對象、安全性高等特點&#xff0c;廣泛應用于企業級應用開發、移動應用開發等領域。2009年&a…

Spark SQL架構及高級用法

Spark SQL 架構概述 架構核心組件 API層&#xff08;用戶接口&#xff09; 輸入方式&#xff1a;SQL查詢&#xff1b;DataFrame/Dataset API。統一性&#xff1a; 所有接口最終轉換為邏輯計劃樹&#xff08;Logical Plan&#xff09;&#xff0c;進入優化流程。 編譯器層&…

【機器學習深度學習】什么是下游任務模型?

目錄 前言 一、什么是下游任務模型&#xff1f; 二、為什么需要下游任務模型&#xff1f; 三、下游任務模型都在干嘛&#xff1f; 四、下游模型怎么訓練出來的&#xff1f; 五、圖解理解&#xff1a;上游 vs 下游 六、一個現實案例&#xff1a;BERT做情感分析 原始數據…

補充:問題:CORS ,前后端訪問跨域問題

補充&#xff1a;問題&#xff1a;CORS &#xff0c;前后端訪問跨域問題 我這邊的解決方法是&#xff1a; myAxios.defaults.withCredentials true; // 配置為true&#xff0c;表示前端向后端發送請求的時候&#xff0c;需要攜帶上憑證cookie整體的&#xff1a; import axio…

洛谷 P13014 [GESP202506 五級] 最大公因數-普及-

題目描述 對于兩個正整數 a,ba,ba,b&#xff0c;他們的最大公因數記為 gcd?(a,b)\gcd(a,b)gcd(a,b)。對于 k>3k > 3k>3 個正整數 c1,c2,…,ckc_1,c_2,\dots,c_kc1?,c2?,…,ck?&#xff0c;他們的最大公因數為&#xff1a; gcd?(c1,c2,…,ck)gcd?(gcd?(c1,c2,……

前端-CSS-day1

目錄 1、初識CSS 2、CSS引入方式 3、標簽選擇器 4、類選擇器 5、id選擇器 6、通配符選擇器 7、畫盒子 8、字體大小 9、字體粗細 10、字體傾斜 11、行高 12、行高-垂直居中 13、字體族 14、font屬性 15、文本縮進 16、文本對齊方式 17、圖片對齊方式 18、文本…

解鎖萬能文件內容提取器:Apache Tika

01 引言 在日常工作中&#xff0c;你是否曾為這些場景頭疼過&#xff1f; 堆積如山的PDF、Word、Excel文檔&#xff0c;如何快速提取關鍵信息&#xff1f;用戶上傳的文件五花八門&#xff0c;如何自動識別類型并安全處理&#xff1f;構建搜索引擎時&#xff0c;如何讓系統“讀懂…

gemini-cli初體驗

目錄 準備配置環境變量運行使用基礎使用配置MCP調用MCP 參考 準備 NodeJS 18版本 配置環境變量 設置GEMINI_API_KEY 變量&#xff0c;在https://aistudio.google.com/apikey創建key 設置代理&#xff08;可選&#xff0c;取決于您的網絡&#xff09;,不配置可能會報錯 api e…

Java --類變量和類方法--main語句

1. 類變量和類方法 介紹&#xff1a; 類變量也叫靜態變量/靜態屬性&#xff0c;是該類的所有對象共享的變量&#xff0c;任何一個該類的對象去訪問它時&#xff0c;取到的都是相同的值&#xff0c;同樣任何一個該類的對象去修改它時&#xff0c;修改的也是同一個變量。 語法…

spring boot項目配置使用minion

一. Minio概述 Minio是一款開源的高性能對象存儲服務,兼容Amazon S3 API,適用于私有云、混合云及邊緣計算場景。它采用分布式架構設計,支持水平擴展,提供數據加密、版本控制、生命周期管理等企業級功能,適用于存儲非結構化數據(如圖片、視頻、日志等)。 核心特性 S3兼…

<5>_Linux進程控制

目錄 一&#xff0c;進程創建&#xff0c;fork/vfork 1&#xff0c;fork創建子進程&#xff0c;操作系統都做了什么 2&#xff0c;寫時拷貝的做了什么 二&#xff0c;進程終止&#xff0c;echo $&#xff1f; 1&#xff0c;進程終止時&#xff0c;操作系統做了什么 2&…

阿里云服務器正確配置 Docker 國內鏡像的方法

&#x1f4e6; 原理說明&#xff1a;什么是“Docker 鏡像加速器”&#xff1f; Docker 默認會從官方倉庫 registry-1.docker.io 拉取鏡像。由于網絡原因&#xff0c;在中國大陸訪問這個地址較慢甚至失敗。 鏡像加速器的作用是&#xff1a; 在國內部署一個緩存服務器&#xf…

PH熱榜 | 2025-07-05

1. todai 標語&#xff1a;你的第一份個性化快樂生活指數 介紹&#xff1a;Todai 是你個人的人工智能助手&#xff0c;幫助你獲得心理清晰和情感平衡。你可以隨時隨地記錄自己的情緒&#xff0c;發現情緒變化的規律&#xff0c;并獲取基于科學的工具。 產品網站&#xff1a;…

c++ duiLib環境集成

duiLib的Github鏈接&#xff1a;https://github.com/duilib/duilib 使用vcpkg快速安裝duilib以及配置。步驟如下&#xff1a; 1、用git下載vcpkg&#xff0c;下載報錯&#xff0c;這個錯誤通常表明在Git克隆過程中&#xff0c;與GitHub服務器的SSL連接被意外重置。改用http下…