【视频传输】二、Opencv结合socket进行视频传输(TCP协议)
来源:互联网 发布:分班软件fenban 编辑:程序博客网 时间:2024/06/06 00:25
博文由来:笔者突发奇想,做采集4个USB摄像头画面小实验时,却遇到了在电脑上最多只能同时开启3个这样头痛的问题(个人分析认为是电脑的问题),故出此下策,在客户端挂1个,服务器挂3个摄像头,利用socket进行视频传输,本篇文章是利用的是TCP协议。笔者拙见,欢迎提出批评。
说明:在此之前笔者也从未接触过socket编程,也不懂TCP/IP、UDP等基本知识。为了避免让读者感到繁琐,我将运用小学及初中学习的总分总、承上启下的写作技巧进行讲解,力图做到详略有致,言简意赅,通俗易懂。如确实还有问题,可以直接回复博客或图文并茂的将问题邮件给笔者(cuit_hjs@163.com),笔者知识有限,但尽量答复。
实验平台:VS2010 + opencv2.4.10(其他版本搭配也是一样的做法)
准备工作:
1、一台电脑,能跑vs和opencv,用来运行服务器(server)和客户端(client)代码;
2、一个摄像头(笔记本摄像头、USB摄像头等,网络摄像头我还没接触过,暂不考虑)。
在同一台电脑上实验,即运行服务器程序,又跑客户端程序,也就是说通过socket编程来实现数据的自发自收,这一步通过了接下来跑服务器和客户端分开的实验就简单了。两台PC之间的视频传输见下一节:【二】Opencv结合socket进行视频传输(TCP协议)
那我们先在就开始吧,不用等下一曲了。
实验1、简单的数据传输,分三步。
①建立一个名为server的vs空项目,再新建demo.cpp源文件,将下面的代码拷贝到demo.cpp中,编译好后关闭vs。
#include "stdafx.h"#include <stdio.h>#include <winsock2.h>#pragma comment(lib,"ws2_32.lib")int main(void){//初始化WSAWORD sockVersion = MAKEWORD(2,2);WSADATA wsaData;if(WSAStartup(sockVersion, &wsaData)!=0){return 0;}//创建套接字SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(slisten == INVALID_SOCKET){printf("socket error !");return 0;}//绑定IP和端口sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(8888);sin.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){printf("bind error !");}//开始监听if(listen(slisten, 5) == SOCKET_ERROR){printf("listen error !");return 0;}//循环接收数据SOCKET sClient;sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);char revData[255]; while (true){printf("等待连接...\n");sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);if(sClient == INVALID_SOCKET){printf("accept error !");continue;}printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));//接收数据int ret = recv(sClient, revData, 255, 0);if(ret > 0){revData[ret] = 0x00;printf(revData);}//发送数据char * sendData = "你好,TCP客户端!\n";send(sClient, sendData, strlen(sendData), 0);closesocket(sClient);}closesocket(slisten);WSACleanup();return 0;}
②建立一个名为client的vs空项目,再新建demo.cpp源文件,将下面的代码拷贝到demo.cpp中,编译好后关闭vs。
#include "stdafx.h"#include <WINSOCK2.H>#include <STDIO.H>#pragma comment(lib,"ws2_32.lib")int main(int argc, char* argv[]){WORD sockVersion = MAKEWORD(2,2);WSADATA data; if(WSAStartup(sockVersion, &data) != 0){return 0;}SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(sclient == INVALID_SOCKET){printf("invalid socket !");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(8888);serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("connect error !");closesocket(sclient);return 0;}char * sendData = "你好,TCP服务端,我是客户端!\n";send(sclient, sendData, strlen(sendData), 0);char recData[255];int ret = recv(sclient, recData, 255, 0);if(ret > 0){recData[ret] = 0x00;printf(recData);}closesocket(sclient);WSACleanup();return 0;}
③同时打开server和client这两个解决方案。先运行server;再运行client,你会发现二者建立起了通信,并相互之间成功将数据进行了传输。
到此我们已经学会了怎么使用socket进行发送接收数据了,这里有两个函数send()和recv()。注意:127.0.0.1这个IP地址是回送地址(自发自收),每台电脑的回环地址都是这个IP,是固定的。很多时候我们组装电脑时给电脑插网卡,就可以在cmd窗口里面ping此IP,若不通则说明网卡没插好。
实验2、简单的图片传输,分三步。
接下来我们就在实验1的基础上添加入opencv代码,读取图片,为尽量简单,我们将图像灰度化。设置好opencv的include和lib路径及依赖项后,就可以开始动手敲代码了。
①先看client端,思路是将读出的图像数据放到一个数组里面,再用send()发送出去,代码如下:
#include "stdafx.h"#include <WINSOCK2.H>#include <iostream>#include <stdio.h>#include <cv.h>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#pragma comment(lib,"ws2_32.lib")int main(int argc, char* argv[]){WORD sockVersion = MAKEWORD(2,2);WSADATA data; if(WSAStartup(sockVersion, &data) != 0){return 0;}SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(sclient == INVALID_SOCKET){printf("invalid socket !\n");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(8888);serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("connect error !\n");closesocket(sclient);return 0;}//读取图像并发送IplImage *image_src = cvLoadImage("wall.jpg");//载入图片IplImage *image_dst = cvCreateImage(cvSize(640, 480), 8, 1);//放置灰度图像int i, j;char sendData[1000000] = "";cvNamedWindow("client", 1);cvCvtColor(image_src, image_dst, CV_RGB2GRAY);for(i = 0; i < image_dst->height; i++){for (j = 0; j < image_dst->width; j++){sendData[image_dst->width * i + j] = ((char *)(image_dst->imageData + i * image_dst->widthStep))[j];}}cvShowImage("client", image_dst);cvWaitKey(0);//任意键发送send(sclient, sendData, 1000000, 0);//发送cvDestroyWindow("client");closesocket(sclient);WSACleanup();return 0;}
②server端,思路是将recv()接收到的数据放到一个数组里面,再还原为图像数据,代码如下:
#include "stdafx.h"#include <stdio.h>#include <winsock2.h>#include <cv.h>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#pragma comment(lib,"ws2_32.lib")int main(int argc, char* argv[]){//初始化WSAWORD sockVersion = MAKEWORD(2,2);WSADATA wsaData;if(WSAStartup(sockVersion, &wsaData)!=0){return 0;}//创建套接字SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(slisten == INVALID_SOCKET){printf("socket error !");return 0;}//绑定IP和端口sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(8888);//端口8888sin.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){printf("bind error !");}//开始监听if(listen(slisten, 5) == SOCKET_ERROR){printf("listen error !");return 0;}//循环接收数据SOCKET sClient;sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);printf("等待连接...\n");do{sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);}while(sClient == INVALID_SOCKET);printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));char revData[1000000] = ""; IplImage *image_src = cvCreateImage(cvSize(640, 480), 8, 1);//接收灰度图像int i, j;int ret;cvNamedWindow("server", 1);while(true){//接收数据ret = recv(sClient, revData, 1000000, 0);if(ret > 0){revData[ret] = 0x00;for(i = 0; i < image_src->height; i++){for (j = 0; j < image_src->width; j++){((char *)(image_src->imageData + i * image_src->widthStep))[j] = revData[image_src->width * i + j];}}ret = 0;}cvShowImage("server", image_src);cvWaitKey(1);}cvDestroyWindow("server");closesocket(slisten);WSACleanup();return 0;}
③ 先运行server,再运行client。在client端,按任意键即可发送数据,而server端马上会收到数据并还原为图像显示出来。
经过上述的实验及讲解,可以对使用socket的编程有一定的了解。如果能够启发读者想去探索,并开发些好玩的东西出来,那自然是一件幸事,但这里就不深入了。
本次实验所需要的所有文件都已打包上传,此处下载:http://download.csdn.net/detail/hujingshuang/8400083
特别注意:
1、本博客例程仅做学习交流用,切勿用于商业用途。
2、欢迎交流,转载请注明出处:http://blog.csdn.net/hujingshuang/article/details/43191461
- 【视频传输】二、Opencv结合socket进行视频传输(TCP协议)
- OpenCV结合socket进行实时视频传输(TCP协议)
- 【视频传输】一、Opencv结合socket进行视频传输(TCP协议)
- tcp+opencv 视频传输
- 基于socket(TCP)和opencv的实时视频传输
- tcp+opencv 视频传输+raspberry
- 基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)
- 基于TCP协议的视频传输
- 【视频传输】(一)传输协议
- tcp视频传输-服务端
- tcp视频传输-客户端
- 网络视频传输协议
- 基于opencv的视频传输
- Linux中用socket 传输视频
- 实时视频传输协议RTP
- 传输控制协议TCP(二)
- 网络编程:基于TCP的socket网络传输视频(C++, python)
- 基于Socket和OpenCV的实时视频传输(On Windows)
- struts学习笔记1
- struts 的传值问题
- django ckeditor.js找不到解决方法
- iOS runtime总结
- 关于限制Android横竖屏问题
- 【视频传输】二、Opencv结合socket进行视频传输(TCP协议)
- LeetCode N阶乘的尾数为0的个数
- UVa #10954 Add All (例题8-11)
- java连接网页
- qcom平台分析通话失败原因
- 给新建的Cocos2d-x 3.x 的Win32工程添加CocoStudio库
- 在Maven中新增自定的jar包
- JQuery滚动图片
- 程序员的八种级别,你在哪一级?