基于Socket和OpenCV的实时视频传输(On Linux)

原文链接

上一篇介绍了在Windows上实现基于Socket和openCV的实时视频传输,这一篇将继续讲解在Linux上的实现。


环境:

Server: Ubuntu 14.04 LTS + OpenCV2.4.10 

Client:: Ubuntu 14.04 LTS + OpenCV2.4.10 


我采用的仍是TCP协议的通信,Linux上的实现和Windows大同小异

Linux中OpenCV的编译安装可以参考 http://blog.csdn.net/pengz0807/article/details/49915573

TCP协议通信的一般步骤我再重新说一下:

客户端:

       1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt();* 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选 
  4、设置要连接的对方的IP地址和端口等属性; 
  5、连接服务器,用函数connect(); 
  6、收发数据,用函数send()和recv(),或者read()和write(); 
  7、关闭网络连接;

服务器端:

       1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt(); * 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind(); 
  4、开启监听,用函数listen(); 
  5、接收客户端上来的连接,用函数accept(); 
  6、收发数据,用函数send()和recv(),或者read()和write(); 
  7、关闭网络连接; 
  8、关闭监听; 


我把图像的发送和接收分别封装在了两个类中:

采集与发送:

SocketMatTransmissionClient.h

  1. /*M/// 
  2. // 
  3. //  基于OpenCV和Socket的图像传输(发送) 
  4. //   
  5. //  By 彭曾 , at CUST, 2016.08.07 
  6. // 
  7. //  website: www.pengz0807.com  email: pengz0807@163.com  
  8. //   
  9. //M*/  
  10.   
  11. #ifndef __SOCKETMATTRANSMISSIONCLIENT_H__  
  12. #define __SOCKETMATTRANSMISSIONCLIENT_H__  
  13.   
  14. #include "opencv2/opencv.hpp"  
  15. #include <stdio.h>  
  16. #include <stdlib.h>  
  17. #include <string.h>  
  18. #include <errno.h>  
  19. #include <unistd.h>  
  20. #include <sys/types.h>  
  21. #include <sys/socket.h>  
  22. #include <netinet/in.h>  
  23. #include <arpa/inet.h>  
  24.   
  25. using namespace cv;  
  26.   
  27. //待传输图像默认大小为 640*480,可修改  
  28. #define IMG_WIDTH 640   // 需传输图像的宽  
  29. #define IMG_HEIGHT 480  // 需传输图像的高  
  30. #define PACKAGE_NUM 2  
  31. //默认格式为CV_8UC3  
  32. #define BUFFER_SIZE IMG_WIDTH*IMG_HEIGHT*3/PACKAGE_NUM  
  33.   
  34. struct sentbuf  
  35. {  
  36.     char buf[BUFFER_SIZE];  
  37.     int flag;  
  38. };  
  39.   
  40. class SocketMatTransmissionClient  
  41. {  
  42. public:  
  43.     SocketMatTransmissionClient(void);  
  44.     ~SocketMatTransmissionClient(void);  
  45.   
  46. private:  
  47.     int sockClient;  
  48.     struct sentbuf data;  
  49.   
  50. public:  
  51.   
  52.     // 打开socket连接  
  53.     // params : IP      服务器的ip地址  
  54.     //          PORT    传输端口  
  55.     // return : -1      连接失败  
  56.     //          1       连接成功  
  57.     int socketConnect(const char* IP, int PORT);  
  58.   
  59.   
  60.     // 传输图像  
  61.     // params : image 待传输图像  
  62.     // return : -1      传输失败  
  63.     //          1       传输成功  
  64.     int transmit(cv::Mat image);  
  65.   
  66.   
  67.     // 断开socket连接  
  68.     void socketDisconnect(void);  
  69. };  
  70.   
  71. #endif  


SocketMatTransmissionClient.cpp
  1. /*M/// 
  2. // 
  3. //  基于OpenCV和Socket的图像传输(发送) 
  4. //   
  5. //  By 彭曾 , at CUST, 2016.08.07  
  6. // 
  7. //  website: www.pengz0807.com  email: pengz0807@163.com  
  8. //   
  9. //M*/  
  10.   
  11.   
  12. #include "SocketMatTransmissionClient.h"  
  13.   
  14. SocketMatTransmissionClient::SocketMatTransmissionClient(void)  
  15. {  
  16. }  
  17.   
  18.   
  19. SocketMatTransmissionClient::~SocketMatTransmissionClient(void)  
  20. {  
  21. }  
  22.   
  23.   
  24. int SocketMatTransmissionClient::socketConnect(const char* IP, int PORT)  
  25. {  
  26.     struct sockaddr_in    servaddr;  
  27.   
  28.     if ((sockClient = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  29.     {  
  30.         printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);  
  31.         return -1;  
  32.     }  
  33.   
  34.     memset(&servaddr, 0, sizeof(servaddr));  
  35.     servaddr.sin_family = AF_INET;  
  36.     servaddr.sin_port = htons(PORT);  
  37.     if (inet_pton(AF_INET, IP, &servaddr.sin_addr) <= 0)   
  38.     {  
  39.         printf("inet_pton error for %s\n", IP);  
  40.         return -1;  
  41.     }  
  42.   
  43.     if (connect(sockClient, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)   
  44.     {  
  45.         printf("connect error: %s(errno: %d)\n", strerror(errno), errno);  
  46.         return -1;  
  47.     }  
  48.     else   
  49.     {  
  50.         printf("connect successful!\n");  
  51.     }  
  52. }  
  53.   
  54.   
  55. void SocketMatTransmissionClient::socketDisconnect(void)  
  56. {  
  57.     close(sockClient);  
  58. }  
  59.   
  60. int SocketMatTransmissionClient::transmit(cv::Mat image)  
  61. {  
  62.     if (image.empty())  
  63.     {  
  64.         printf("empty image\n\n");  
  65.         return -1;  
  66.     }  
  67.   
  68.     if(image.cols != IMG_WIDTH || image.rows != IMG_HEIGHT || image.type() != CV_8UC3)  
  69.     {  
  70.         printf("the image must satisfy : cols == IMG_WIDTH(%d)  rows == IMG_HEIGHT(%d) type == CV_8UC3\n\n", IMG_WIDTH, IMG_HEIGHT);  
  71.         return -1;  
  72.     }  
  73.   
  74.     for(int k = 0; k < PACKAGE_NUM; k++)   
  75.     {  
  76.         int num1 = IMG_HEIGHT / PACKAGE_NUM * k;  
  77.         for (int i = 0; i < IMG_HEIGHT / PACKAGE_NUM; i++)  
  78.         {  
  79.             int num2 = i * IMG_WIDTH * 3;  
  80.             uchar* ucdata = image.ptr<uchar>(i + num1);  
  81.             for (int j = 0; j < IMG_WIDTH * 3; j++)  
  82.             {  
  83.                 data.buf[num2 + j] = ucdata[j];  
  84.             }  
  85.         }  
  86.   
  87.         if(k == PACKAGE_NUM - 1)  
  88.             data.flag = 2;  
  89.         else  
  90.             data.flag = 1;  
  91.   
  92.         if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)  
  93.         {  
  94.             printf("send image error: %s(errno: %d)\n", strerror(errno), errno);  
  95.             return -1;  
  96.         }  
  97.     }  
  98. }  


接收与显示:

SocketMatTransmissionServer.h

  1. /*M/// 
  2. // 
  3. //  基于OpenCV和Socket的图像传输(接收) 
  4. //   
  5. //  By 彭曾 , at CUST, 2016.08.07 
  6. // 
  7. //  website: www.pengz0807.com  email: pengz0807@163.com  
  8. //   
  9. //M*/  
  10.   
  11. #ifndef __SOCKETMATTRANSMISSIONSEVER_H__  
  12. #define __SOCKETMATTRANSMISSIONSEVER_H__  
  13.   
  14. #include "opencv2/opencv.hpp"  
  15. #include <stdio.h>  
  16. #include <stdlib.h>  
  17. #include <string.h>  
  18. #include <errno.h>  
  19. #include <unistd.h>  
  20. #include <sys/shm.h>  
  21. #include <sys/types.h>  
  22. #include <sys/socket.h>  
  23. #include <netinet/in.h>  
  24. #include <arpa/inet.h>  
  25.   
  26. using namespace cv;  
  27.   
  28. #define PACKAGE_NUM 2  
  29.   
  30. #define IMG_WIDTH 640  
  31. #define IMG_HEIGHT 480  
  32.   
  33. #define BLOCKSIZE IMG_WIDTH*IMG_HEIGHT*3/PACKAGE_NUM  
  34.   
  35. struct recvBuf  
  36. {  
  37.     char buf[BLOCKSIZE];  
  38.     int flag;  
  39. };  
  40.   
  41.   
  42. class SocketMatTransmissionServer  
  43. {  
  44. public:  
  45.     SocketMatTransmissionServer(void);  
  46.     ~SocketMatTransmissionServer(void);  
  47.     int sockConn;  
  48. private:  
  49.     struct recvBuf data;  
  50.   
  51.     int needRecv;  
  52.     int count;  
  53.   
  54. public:  
  55.   
  56.     // 打开socket连接  
  57.     // params : PORT    传输端口  
  58.     // return : -1      连接失败  
  59.     //          1       连接成功  
  60.     int socketConnect(int PORT);  
  61.   
  62.   
  63.     // 传输图像  
  64.     // params : image   待接收图像  
  65.     //      image   待接收图像  
  66.     // return : -1      接收失败  
  67.     //          1       接收成功  
  68.     int receive(cv::Mat& image);  
  69.   
  70.   
  71.     // 断开socket连接  
  72.     void socketDisconnect(void);  
  73. };  
  74.   
  75. #endif  

SocketMatTransmissionServer.cpp

  1. /*M/// 
  2. // 
  3. //  基于OpenCV和Socket的图像传输(接收) 
  4. //   
  5. //  By 彭曾 , at CUST, 2016.08.07  
  6. // 
  7. //  website: www.pengz0807.com  email: pengz0807@163.com  
  8. //   
  9. //M*/  
  10.   
  11.   
  12. #include "SocketMatTransmissionServer.h"  
  13.   
  14. SocketMatTransmissionServer::SocketMatTransmissionServer(void)  
  15. {  
  16. }  
  17.   
  18.   
  19. SocketMatTransmissionServer::~SocketMatTransmissionServer(void)  
  20. {  
  21. }  
  22.   
  23.   
  24. int SocketMatTransmissionServer::socketConnect(int PORT)  
  25. {  
  26.     int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);  
  27.   
  28.     struct sockaddr_in server_sockaddr;  
  29.     server_sockaddr.sin_family = AF_INET;  
  30.     server_sockaddr.sin_port = htons(PORT);  
  31.     server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  32.   
  33.     if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)  
  34.     {  
  35.         perror("bind");  
  36.         return -1;  
  37.     }  
  38.   
  39.     if(listen(server_sockfd,5) == -1)  
  40.     {  
  41.         perror("listen");  
  42.         return -1;  
  43.     }  
  44.   
  45.     struct sockaddr_in client_addr;  
  46.     socklen_t length = sizeof(client_addr);  
  47.   
  48.     sockConn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);  
  49.     if(sockConn<0)  
  50.     {  
  51.         perror("connect");  
  52.         return -1;  
  53.     }  
  54.     else  
  55.     {  
  56.         printf("connect successful!\n");  
  57.         return 1;  
  58.     }  
  59.       
  60.     close(server_sockfd);  
  61. }  
  62.   
  63.   
  64. void SocketMatTransmissionServer::socketDisconnect(void)  
  65. {  
  66.     close(sockConn);  
  67. }  
  68.   
  69. int SocketMatTransmissionServer::receive(cv::Mat& image)  
  70. {  
  71.     int returnflag = 0;  
  72.     cv::Mat img(IMG_HEIGHT, IMG_WIDTH, CV_8UC3, cv::Scalar(0));  
  73.     needRecv = sizeof(recvBuf);  
  74.     count = 0;  
  75.     memset(&data,0,sizeof(data));  
  76.   
  77.     for (int i = 0; i < PACKAGE_NUM; i++)  
  78.     {  
  79.         int pos = 0;  
  80.         int len0 = 0;  
  81.   
  82.         while (pos < needRecv)  
  83.         {  
  84.             len0 = recv(sockConn, (char*)(&data) + pos, needRecv - pos, 0);  
  85.             if (len0 < 0)  
  86.             {  
  87.                 printf("Server Recieve Data Failed!\n");  
  88.                 break;  
  89.             }  
  90.             pos += len0;  
  91.         }  
  92.   
  93.         count = count + data.flag;  
  94.   
  95.         int num1 = IMG_HEIGHT / PACKAGE_NUM * i;  
  96.         for (int j = 0; j < IMG_HEIGHT / PACKAGE_NUM; j++)  
  97.         {  
  98.             int num2 = j * IMG_WIDTH * 3;  
  99.             uchar* ucdata = img.ptr<uchar>(j + num1);  
  100.             for (int k = 0; k < IMG_WIDTH * 3; k++)  
  101.             {  
  102.                 ucdata[k] = data.buf[num2 + k];  
  103.             }  
  104.         }  
  105.   
  106.         if (data.flag == 2)  
  107.         {  
  108.             if (count == PACKAGE_NUM + 1)  
  109.             {  
  110.                 image = img;  
  111.                 returnflag = 1;  
  112.                 count = 0;  
  113.             }  
  114.             else  
  115.             {  
  116.                 count = 0;  
  117.                 i = 0;  
  118.             }  
  119.         }  
  120.     }  
  121.     if(returnflag == 1)  
  122.         return 1;  
  123.     else  
  124.         return -1;  
  125. }  


示例代码:

图像的采集与发送:

SocketClientMat.cpp

  1. #include "SocketMatTransmissionClient.h"  
  2.   
  3. int main()  
  4. {  
  5.     SocketMatTransmissionClient socketMat;  
  6.     if (socketMat.socketConnect("127.0.0.1", 6666) < 0)  
  7.     {  
  8.         return 0;  
  9.     }  
  10.       
  11.     cv::VideoCapture capture(0);  
  12.     cv::Mat image;  
  13.   
  14.     while (1)  
  15.     {  
  16.         if (!capture.isOpened())  
  17.             return 0;  
  18.   
  19.         capture >> image;  
  20.   
  21.         if (image.empty())  
  22.             return 0;  
  23.   
  24.         socketMat.transmit(image);  
  25.     }  
  26.   
  27.     socketMat.socketDisconnect();  
  28.     return 0;  
  29. }  

接收与显示:

SocketServerMat.cpp

  1. #include "SocketMatTransmissionServer.h"  
  2.   
  3. int main()  
  4. {  
  5.     SocketMatTransmissionServer socketMat;  
  6.     if (socketMat.socketConnect(6666) < 0)  
  7.     {  
  8.         return 0;  
  9.     }  
  10.   
  11.     cv::Mat image;  
  12.     while (1)  
  13.     {  
  14.         if(socketMat.receive(image) > 0)  
  15.         {  
  16.             cv::imshow("",image);  
  17.             cv::waitKey(30);  
  18.         }  
  19.     }  
  20.   
  21.     socketMat.socketDisconnect();  
  22.     return 0;  
  23. }  

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用OpenCVSocket进行视频传输,您可以按照以下步骤进行操作: 1. 服务端(发送端): - 使用OpenCV读取视频文件或捕获摄像头的实时视频。 - 将每一帧编码为图像数据(如JPEG或PNG)。 - 使用Socket将编码后的图像数据发送到客户端。 2. 客户端(接收端): - 创建Socket连接到服务端。 - 接收服务端发送的图像数据。 - 解码图像数据并显示(使用OpenCV)。 下面是一个简单的示例代码,演示了如何在Python中使用OpenCVSocket进行视频传输: 服务端代码: ```python import cv2 import socket import pickle # 创建Socket连接 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8000)) server_socket.listen(1) print("Waiting for client connection...") # 接受客户端连接 client_socket, address = server_socket.accept() print("Client connected:", address) # 打开视频文件或启动摄像头 cap = cv2.VideoCapture('path_to_video_file') # 或者使用摄像头:cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break # 编码图像数据 data = pickle.dumps(frame) # 发送图像数据到客户端 client_socket.sendall(data) # 关闭连接和摄像头 client_socket.close() cap.release() ``` 客户端代码: ```python import cv2 import socket import pickle import struct # 创建Socket连接 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 8000)) data = b'' # 存储接收到的图像数据 payload_size = struct.calcsize("L") # 图像数据的大小 while True: # 接收图像数据 while len(data) < payload_size: data += client_socket.recv(4096) packed_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("L", packed_size)[0] while len(data) < msg_size: data += client_socket.recv(4096) frame_data = data[:msg_size] data = data[msg_size:] # 解码图像数据 frame = pickle.loads(frame_data) # 显示图像 cv2.imshow('Video', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # 关闭连接 client_socket.close() cv2.destroyAllWindows() ``` 请注意,此示例仅介绍了基本的图像传输功能,并没有处理图像传输中的丢包和延迟等问题。在实际应用中,还需要考虑网络稳定性和性能优化等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值