日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt网络编程——使用OpenCV与TCP搭建图像处理服务器

發布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt网络编程——使用OpenCV与TCP搭建图像处理服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前面的博客有寫過如果使用TCP搭建一個客戶端與服務器,連接并互發信息,這里主是演示,如何把客戶端的圖像發往服務器,服務器得到圖像后,按指令做不同的處理,并返回給客戶端處理之后的結果,客戶端只負責打開和發送圖像,所有關于圖像的圖像的處理,比如灰度圖像,人臉檢測啊,都經過服務器處理之后返回給客戶端。而服務器用來處理圖像的是OpenCV庫,
代碼注釋比較多,具體流程可以看源碼,就應該了解。

代碼

1.客戶端
client.h

#ifndef CLIENT_H #define CLIENT_H#include <QMainWindow> #include <QTcpSocket> #include <QHostAddress> #include <QMessageBox> #include <QFile> #include <QFileDialog> #include <QCompleter> #include <QBuffer> #include <QDebug> #include <QTextEdit> #include <QImageReader> #include <QTextCursor> #include <QColor>QT_BEGIN_NAMESPACE namespace Ui { class Client; } QT_END_NAMESPACEclass Client : public QMainWindow {Q_OBJECTpublic:Client(QWidget *parent = nullptr);~Client();void initUI();void insertImage(QTextEdit *ui_text, QImage &image);void transformImage(QImage &image,qint64 mask);QByteArray getImageData(const QImage &image);void transformImage(QImage &image, QByteArray &block,int mask);QImage getImage(const QString &data);QByteArray imageToBuffer(QImage &image);private slots:void on_buttonConnect_clicked();//連接服務器void on_buttonDisconnect_clicked();//斷開連接void on_buttonOpenImage_clicked();//打開圖像void readServerMessage();//讀取消息void on_buttonFaceDetection_clicked();//人臉檢測void on_buttonGaryImage_clicked();//灰度圖像void on_buttonCannyImage_clicked();//邊緣檢測 private:QTcpSocket *tcpClient;QImage image;Ui::Client *ui;QByteArray outBlock; //數據緩沖區,即存放每次要發送的數據塊int totalBytes; // 發送數據的總大小int mask;QString fileName;int imageSize;int bytesReceived; }; #endif // CLIENT_H

client.cpp

#include "client.h" #include "ui_client.h"Client::Client(QWidget *parent): QMainWindow(parent), ui(new Ui::Client) {ui->setupUi(this);initUI();tcpClient = new QTcpSocket(this);//取消原有連接tcpClient->abort();bytesReceived = 0;imageSize = 0;connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readServerMessage())); }//UI界面相關 void Client::initUI() {ui->buttonDisconnect->setEnabled(false); }Client::~Client() {delete ui; }//連接服務器 void Client::on_buttonConnect_clicked() {tcpClient->connectToHost(ui->lineEditServerIP->text(),ui->lineEditServerPorts->text().toInt());if(tcpClient->waitForConnected(1000)){ui->buttonConnect->setEnabled(false);ui->buttonDisconnect->setEnabled(true);ui->textEditStatus->append("連接服務器成功!");}else{ui->textEditStatus->append("連接失敗,請檢查IP地址和端口!");} }//斷開 void Client::on_buttonDisconnect_clicked() {tcpClient->disconnectFromHost();//斷開成功if (tcpClient->state() == QAbstractSocket::UnconnectedState || tcpClient->waitForDisconnected(1000)){ui->buttonConnect->setEnabled(true);ui->textEditStatus->append("連接已斷開!");ui->buttonDisconnect->setEnabled(false);ui->buttonConnect->setEnabled(true);}else{ui->textEditStatus->append("無法斷開與服務器的連接!");} }void Client::on_buttonFaceDetection_clicked() {}void Client::on_buttonGaryImage_clicked() {transformImage(image,outBlock,10);if(image.isNull()){ui->textEditStatus->append("當前圖像不能發送!");return;}if(outBlock.size() != 0){tcpClient->write(outBlock);ui->textEditStatus->append("圖像發送成功!");ui->textEditInput->clear();} }void Client::on_buttonCannyImage_clicked() {transformImage(image,outBlock,9);if(image.isNull()){ui->textEditStatus->append("當前圖像不能發送!");return;}if(outBlock.size() != 0){tcpClient->write(outBlock);ui->textEditStatus->append("圖像發送成功!");ui->textEditInput->clear();} }//接收服務器端的信息并顯示 void Client::readServerMessage() {QDataStream in(tcpClient);in.setVersion(QDataStream::Qt_5_7);QImage imageData;QString imageContent;// 如果已接收到的數據小于16個字節,保存到文件頭結構if (bytesReceived <= sizeof(int)*3){if((tcpClient->bytesAvailable() >= sizeof(int)*3)&& (imageSize == 0)){// 接收數據總大小信息和文件名大小信息in >>mask>> totalBytes >> imageSize;bytesReceived += sizeof(int) * 3;}if((tcpClient->bytesAvailable() >= imageSize) && (imageSize != 0)){// 接收文件,并建立文件in >> imageContent;imageData = getImage(imageContent);if(imageData.isNull()){ui->textEditStatus->append("沒有接收圖像數據!");}insertImage(ui->textEditAccept,imageData);bytesReceived += imageSize;if(bytesReceived == totalBytes){ui->textEditStatus->append("接收文件成功");totalBytes = 0;bytesReceived = 0;imageSize = 0;}}} }//QTextEdit顯示圖像 void Client::insertImage(QTextEdit *ui_text_edit, QImage &image) {QUrl Uri;QTextDocument * textDocument = ui_text_edit->document();textDocument->addResource( QTextDocument::ImageResource, Uri, QVariant ( image ) );QTextCursor cursor = ui_text_edit->textCursor();QTextImageFormat imageFormat;imageFormat.setWidth( image.width() );imageFormat.setHeight( image.height() );cursor.insertImage(imageFormat);}//打開圖像按鍵 void Client::on_buttonOpenImage_clicked() {fileName = QFileDialog::getOpenFileName(this);if (!fileName.isEmpty()){image = QImage(fileName);if(image.isNull()){ui->textEditStatus->append("打開圖像失敗!");return;}else{QBuffer buffer(&outBlock);buffer.open(QIODevice::WriteOnly);image.save(&buffer, "JPG");insertImage(ui->textEditInput,image);ui->textEditStatus->append("打開圖像成功!");}}else{ui->textEditStatus->append("打開路徑失敗,請確定是否是圖像路徑!");return;}}//圖像轉換 /*QImage &image 輸入圖像*QByteArray &block 輸出流*int mask 指令 */ void Client::transformImage(QImage &image, QByteArray &block,int mask) {int total_size = 0;QDataStream sendOut(&block, QIODevice::WriteOnly);sendOut.setVersion(QDataStream::Qt_5_7);//獲得圖片數據QString imageData = getImageData(image);// 保留總大小信息空間、圖像大小信息空間,然后輸入圖像信息sendOut << int(0) << int(0) << int(0) << imageData;// 這里的總大小是總大小信息、圖像大小信息和實際圖像信息的總和total_size += block.size();sendOut.device()->seek(0);int image_size = int((block.size() - sizeof(int)*3));// 返回outBolock的開始,用實際的大小信息代替兩個qint64(0)空間sendOut << mask << total_size << image_size; }//圖像轉Base 64 QByteArray Client::getImageData(const QImage &image) {QByteArray imageData;//開緩沖區QBuffer buffer(&imageData);//存入緩沖區image.save(&buffer, "jpg");//轉成Base64imageData = imageData.toBase64();return imageData; }//Base64 轉圖像 QImage Client::getImage(const QString &data) {QByteArray imageData = QByteArray::fromBase64(data.toLatin1());QImage image;image.loadFromData(imageData);return image; }

2.服務器端
server.h

#ifndef SERVER_H #define SERVER_H#include <QMainWindow> #include <QTcpServer> #include <QTcpSocket> #include <QNetworkInterface> #include <QMessageBox> #include <QFileDialog> #include <iostream> #include <QBuffer> #include <opencv2/opencv.hpp> #include <QTextEdit> #include <QFile>QT_BEGIN_NAMESPACE namespace Ui { class Server; } QT_END_NAMESPACEclass Server : public QMainWindow {Q_OBJECTpublic:Server(QWidget *parent = nullptr);~Server();void initUI();//界面初始化QImage base64ToQImage(const QString &data);//base64轉QImagevoid insertImage(QTextEdit *ui_text_edit, QImage &image);//QTextEdit顯示圖像cv::Mat QImage2cvMat(QImage &image);//QImage轉MatQImage cvMat2QImage(const cv::Mat& mat);//Mat轉QImagevoid transformImage(QImage &image, QByteArray &block,int mask);//封裝發送數據QByteArray QImageToBase64(const QImage &image);//QImage轉Base64void edgeDetection(cv::Mat &cv_src,cv::Mat &cv_dst);private:QTcpServer *tcpServer;//服務器類QList<QTcpSocket*> tcpClient;QTcpSocket *currentClient;int mask,total_size;int total_bytes;int bytes_received;int image_size;QString image_content;QByteArray out_block; //數據緩沖區,即存放每次要發送的數據塊QImage image_data;QString file_name;QImage image;QByteArray buffer_all;private slots:void on_buttonMonitor_clicked();//監聽事件void on_buttonDisconnect_clicked();//斷開事件void newConnectionSlot();//新客戶端連接事件void readMessageData();//接收信息void on_buttonOpenImage_clicked();//打開圖像void on_buttonSendMessage_clicked();//發送圖像private:Ui::Server *ui; }; #endif // SERVER_H

server.cpp

#include "server.h" #include "ui_server.h"Server::Server(QWidget *parent): QMainWindow(parent), ui(new Ui::Server) {ui->setupUi(this);initUI();tcpServer = new QTcpServer(this);image_size = 0;total_bytes = 0;bytes_received = 0;//有新的連接時的槽函數connect(tcpServer,SIGNAL(newConnection()),this, SLOT(newConnectionSlot())); }void Server::initUI() {ui->buttonDisconnect->setEnabled(false); }Server::~Server() {delete ui; }//啟動服務器開始監聽 void Server::on_buttonMonitor_clicked() {//監聽所有IP地址bool monitor = tcpServer->listen(QHostAddress::Any,ui->lineEditServerPorts->text().toInt());//按鍵狀態if(monitor){ui->buttonMonitor->setEnabled(false);ui->buttonDisconnect->setEnabled(true);ui->textEditStatus->append("開始監端口......");}else{ui->textEditStatus->append("啟動服務器失敗!");} }//有新客戶端連接時 void Server::newConnectionSlot() {//返回套接字指針currentClient = tcpServer->nextPendingConnection();tcpClient.append(currentClient);ui->comboBoxIP->addItem(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1])\.arg(currentClient->peerPort()));//讀取消息處理connect(currentClient, SIGNAL(readyRead()), this, SLOT(readMessageData())); }//斷開與所有客戶端的連接 void Server::on_buttonDisconnect_clicked() {//如果有客戶端連接if(tcpClient.length() > 0){for(int i = 0; i < tcpClient.length();i++){//斷開tcpClient.at(i)->disconnectFromHost();//等待bool dis = tcpClient.at(i)->waitForDisconnected(1000);if(dis){//刪除客戶端tcpClient.removeAt(i);tcpServer->close();ui->buttonMonitor->setEnabled(true);ui->buttonDisconnect->setEnabled(false);ui->textEditStatus->append("斷開連接成功!");ui->buttonMonitor->setEnabled(true);}else{ui->textEditStatus->append("斷開連接失敗!");}}}else{ui->textEditStatus->append("當前沒有連接的客戶端!");ui->buttonMonitor->setEnabled(true);} }//接收消息并顯示到界面 void Server::readMessageData() {//由于readyRead信號并未提供SocketDecriptor,所以需要遍歷所有客戶端//遍歷所有連接的客戶端for(int i=0; i<tcpClient.length(); i++){QDataStream in(tcpClient.at(i));// 如果已接收到的數據小于16個字節,保存到文件頭結構if (bytes_received <= sizeof(int)*3){if((currentClient->bytesAvailable() >= sizeof(int)*3)&& (image_size == 0)){// 接收數據總大小信息和文件名大小信息in >>mask>>total_bytes >> image_size;bytes_received += sizeof(int) * 3;ui->textEditStatus->append("開始接收圖像......");}if((currentClient->bytesAvailable() >= image_size) && (image_size != 0)){// 接收文件,并建立文件in >> image_content;image_data = base64ToQImage(image_content);insertImage(ui->textEditAccept,image_data);bytes_received += image_size;if(!image_data.isNull()){ui->textEditStatus->append("接收文件成功");//判斷轉過來的指令,對圖像進行處理switch (mask){case 9:{QByteArray out;//使用opencv處理圖像cv::Mat cv_src = QImage2cvMat(image_data);cv::Mat cv_dst;edgeDetection(cv_src,cv_dst);QImage qt_image = cvMat2QImage(cv_dst);//處理完成之后返回給客戶端transformImage(qt_image,out,9);//返回給之前發送信息的客戶端tcpClient.at(i)->write(out);ui->textEditStatus->append("處理并返回圖像成功!");mask = 0;break;}case 10:{QByteArray out;//使用opencv處理圖像cv::Mat cv_src = QImage2cvMat(image_data);cv::Mat cv_dst;cv::cvtColor(cv_src,cv_dst,cv::COLOR_BGR2GRAY);QImage qt_image = cvMat2QImage(cv_dst);//處理完成之后返回給客戶端transformImage(qt_image,out,10);//返回給之前發送信息的客戶端tcpClient.at(i)->write(out);ui->textEditStatus->append("處理并返回圖像成功!");mask = 0;break;}}}if(bytes_received == total_bytes){total_bytes = 0;bytes_received = 0;image_size = 0;}}}} }void Server::edgeDetection(cv::Mat &cv_src, cv::Mat &cv_dst) {cv::Mat cv_gray,cv_edge;cv::cvtColor(cv_src,cv_gray,cv::COLOR_BGR2GRAY);cv::blur(cv_gray, cv_gray, cv::Size(3, 3));//調用Canny算子cv::Canny(cv_edge, cv_dst, 10, 30, 3); }//Base64轉QImage QImage Server::base64ToQImage(const QString &data) {QByteArray imageData = QByteArray::fromBase64(data.toLatin1());QImage image;image.loadFromData(imageData);return image; }//QTextEdit顯示圖像 void Server::insertImage(QTextEdit *ui_text_edit, QImage &image) {QUrl Uri;QTextDocument * textDocument = ui_text_edit->document();textDocument->addResource( QTextDocument::ImageResource, Uri, QVariant ( image ) );QTextCursor cursor = ui_text_edit->textCursor();QTextImageFormat imageFormat;imageFormat.setWidth( image.width() );imageFormat.setHeight( image.height() );cursor.insertImage(imageFormat);}// QImage轉換成cv::Mat cv::Mat Server::QImage2cvMat(QImage &image) {cv::Mat mat;switch (image.format()){case QImage::Format_ARGB32:case QImage::Format_RGB32:case QImage::Format_ARGB32_Premultiplied:mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());break;case QImage::Format_RGB888:mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB);break;case QImage::Format_Indexed8:mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());break;}return mat; }// cv::Mat轉換成QImage QImage Server::cvMat2QImage(const cv::Mat& mat) {if (mat.type() == CV_8UC1) // 單通道{QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);image.setColorCount(256); // 灰度級數256for (int i = 0; i < 256; i++){image.setColor(i, qRgb(i, i, i));}uchar *pSrc = mat.data; // 復制mat數據for (int row = 0; row < mat.rows; row++){uchar *pDest = image.scanLine(row);memcpy(pDest, pSrc, mat.cols);pSrc += mat.step;}return image;}else if (mat.type() == CV_8UC3) // 3通道{const uchar *pSrc = (const uchar*)mat.data; // 復制像素QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888); // R, G, B 對應 0,1,2return image.rgbSwapped(); // rgbSwapped是為了顯示效果色彩好一些。}else if (mat.type() == CV_8UC4) // 4通道{const uchar *pSrc = (const uchar*)mat.data; // 復制像素QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32); // B,G,R,A 對應 0,1,2,3return image.copy();}else{return QImage();} }//轉換封裝圖像數據 void Server::transformImage(QImage &image, QByteArray &block,int mask) {int total = 0;QDataStream sendOut(&block, QIODevice::WriteOnly);sendOut.setVersion(QDataStream::Qt_5_7);//獲得圖片數據QString imageData = QImageToBase64(image);// 保留總大小信息空間、圖像大小信息空間,然后輸入圖像信息sendOut << int(0) << int(0) << int(0) << imageData;// 這里的總大小是總大小信息、圖像大小信息和實際圖像信息的總和total += block.size();sendOut.device()->seek(0);// 返回outBolock的開始,用實際的大小信息代替兩個qint64(0)空間sendOut << mask << total << int((block.size() - sizeof(int)*3)); }QByteArray Server::QImageToBase64(const QImage &image) {QByteArray imageData;//開緩沖區QBuffer buffer(&imageData);//存入緩沖區image.save(&buffer, "jpg");//轉成Base64imageData = imageData.toBase64();return imageData; }//打開圖像 void Server::on_buttonOpenImage_clicked() {file_name = QFileDialog::getOpenFileName(this);if (!file_name.isEmpty()){image = QImage(file_name);if(image.isNull()){ui->textEditStatus->append("打開圖像失敗!");return;}else{insertImage(ui->textEditInput,image);ui->textEditStatus->append("打開圖像成功!");ui->buttonSendMessage->setEnabled(true);}}else{ui->textEditStatus->append("打開路徑失敗,請確定是否是圖像路徑!");return;} } void Server::on_buttonSendMessage_clicked() {transformImage(image_data,out_block,10);//如果選擇全部發送信息if(ui->comboBoxIP->currentIndex() == 0){for(int i = 0; i < tcpClient.length(); i++){tcpClient.at(i)->write(out_block);ui->textEditStatus->append("信息發送成功!");ui->textEditInput->clear();}}//指定接收的客戶端/*else{//得到選擇的IP地址QString client_IP = ui->comboBoxIP->currentText().split(":").at(0);//得到端口int client_port = ui->comboBoxIP->currentText().split(":").at(1).toInt();//遍歷連接到的客戶端for(int i = 0; i < tcpClient.length(); i++){if(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]==client_IP\&& tcpClient[i]->peerPort()==client_port){tcpClient.at(i)->write(input_data.toLatin1());ui->textEditStatus->append("發送信息到:"+client_IP+"成功!");//ui->textEditInput->clear();input_data.clear();return; //ip:port唯一,無需繼續檢索}}}*/}

3.運行效果

總結

以上是生活随笔為你收集整理的Qt网络编程——使用OpenCV与TCP搭建图像处理服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 精品熟妇视频一区二区三区 | 新超碰在线 | 亚洲欧美日韩偷拍 | 国产伦精品一区二区三区网站 | 97视频免费在线 | 后宫秀女调教(高h,np) | 日本免费一区二区三区四区五六区 | 精品丰满人妻无套内射 | 欧美a√ | av在线视| 天堂中文字幕免费一区 | 六月色婷婷 | 亚洲综合久 | 久久99精品久久久久婷婷 | 欧美午夜视频在线观看 | 日韩在线一二三区 | 中文字幕在线观看网 | 国产在线色视频 | 自拍偷拍福利 | 午夜色福利 | 成人公开免费视频 | 寂寞少妇让水电工爽hd | 国产乱子一区二区 | 999国内精品永久免费视频 | wwwav视频| 日韩在线第一 | 好了av在线 | 伊人中文字幕在线 | 亚洲天堂一区二区 | 国产精品乱码一区二三区小蝌蚪 | 日日操夜夜爽 | 日韩一二三四 | 午夜精品在线 | 午夜福利电影一区二区 | 国产成人资源 | 国产精品美女久久久久久久久 | 国产真实伦对白全集 | 无码日韩精品一区二区 | 五月色婷 | 婷婷亚洲天堂 | 天天干天天爱天天操 | 日韩色在线观看 | 一级片欧美 | 国产乱一区二区三区 | 新婚夫妇白天啪啪自拍 | 日本在线不卡一区二区 | 男男h黄动漫啪啪无遮挡软件 | 国产网红女主播精品视频 | 高潮又黄又刺激 | 国产成人av无码精品 | 亚洲黄片一区 | 日韩精品中文字幕一区 | 羞羞的视频在线观看 | 国产熟女一区二区 | 亚洲免费视频一区二区 | 操碰视频在线 | 黄色一级免费视频 | 玖玖玖国产精品 | 黄色片在线观看视频 | 国产网址在线观看 | 国产婷婷色一区二区三区 | 欧美啪啪网站 | 久久免费看少妇 | 午夜激情电影院 | 国产精品黑丝 | 东京av在线 | 国产亚洲精品久久久久久777 | 久久亚洲一区二区 | 少妇15p | 性开放耄耋老妇hd | 午夜之声l性8电台lx8电台 | 四虎tv | 色姑娘天天操 | 天天摸天天操天天爽 | 久久精品综合网 | 97超碰人人澡人人爱学生 | 夫妻性生活黄色大片 | 中文字幕在线观看第一页 | 亚洲色图首页 | 日韩精品一区二区三区不卡在线 | 成人性生交免费看 | 天天干夜夜艹 | 懂色av一区二区三区在线播放 | 秘密基地动漫在线观看免费 | 国产成人精品无码片区在线 | 欧美男女性生活视频 | av日韩在线免费观看 | 97伊人超碰 | 尤物精品| 91黄色大片 | 国产a∨精品一区二区三区仙踪林 | 亚洲成人免费网站 | 国产女人18水真多毛片18精品 | 欧美精品国产一区二区 | 免费黄色观看 | 日本a级c片免费看三区 | 美女隐私黄www网站动漫 | 91视频看看 | 国产一卡二卡三卡 |