这个项程序是用c++写的,运行过程,服务端读取摄像头数据,并建立socker server, 作为视频服务器,本机再运行client.pp读取服务端的视步图像,server.cpp, 与client.cpp,可以同时在两台机使用。
先看看效果图。
1. 每一步,装好摄像头硬件,
2. 建立两个文件,
server.cpp 是服务端程序
client.cpp 是客户端程序
3. 编写服务端代码( server.cpp)
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
int sendbytes;
int connectstatus =0;
while(1)
{
if( connectstatus== 0)
{
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8001);
int opt = 1;
/* set port reuse */
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const void *)&opt,sizeof(opt)))
{
perror("setsockopt");
return -1;
}
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
if( listen(listenfd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
}
/* ---main task process--- */
Mat frame;
VideoCapture cap;
vector<unsigned char> inImage;
/* open camera */
cap.open(0);
if (!cap.isOpened())
{
cerr << "ERROR! Unable to open camera\n";
return -1;
}
printf("open camera success\n");
printf("======waiting for client's apple request======\n");
if((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
{
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
exit(0);
}
{
printf("accept socket success!!\n");
}
char cok[1]={0x55};
char cokstart[1]={0};
char j = 0;
int sizelen=0;
int sizejpg=0;
for (;;)
{
if(waitKey(5)>=0)
break;
if (cok[0]==0x55)
{
cap.read(frame);
if (frame.empty())
{
cerr << "ERROR! blank frame grabbed\n";
break;
}
cok[0]=0;
imencode(".jpg",frame,inImage);
int datalen=inImage.size()+1;
unsigned char *msgImage=new unsigned char[datalen];
memset(msgImage, 0 ,datalen);
unsigned char msgLen[4];
msgLen[0]=datalen >> 24;
msgLen[1]=datalen >> 16;
msgLen[2]=datalen >> 8;
msgLen[3]=datalen;
sizelen=send(connfd,msgLen,4,0);
for(int i=0;i<datalen;i++)
{
msgImage[i]=inImage[i];
}
recv(connfd,cokstart,1,0);
if(cokstart[0] == 0x33)
{
vector<char>vec;
Mat img_decode;
cokstart[0]=0x0;
for(int i=0;i<datalen;i++)
{
vec.push_back(msgImage[i]);
}
img_decode =imdecode(vec,CV_LOAD_IMAGE_COLOR);
printf("send image data length:%d\n",datalen);
sizejpg=send(connfd, msgImage, datalen, 0);
}
// usleep(10);
recv(connfd, cok, 1, 0);
}
}
close(listenfd);
}
return 0;
}
4. 编写客户端代码(client.cpp)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include<vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <unistd.h>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
int sockfd, n;
char recvline[4096], sendline[4096];
struct sockaddr_in servaddr;
int ntry =0;
#if 0
if( argc != 2)
{
printf("usage: ./client <ipaddress>\n");
exit(0);
}
#endif
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8008);
if( inet_pton(AF_INET, "10.8.0.88", &servaddr.sin_addr) <= 0)
{
printf("inet_pton error for %s\n",argv[1]);
exit(0);
}
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
#define BUF_SIZE 254280
char buffer[ BUF_SIZE ];
Mat img_decode;
//string filename="";
int size = 0;
int mylen = 0;
int j= 0;
char cokstart[ 1 ]={0x33};
int nTry =0;
while(1)
{
memset( buffer, 0, BUF_SIZE );
vector<char> vec;
size = recv(sockfd,buffer,4,0);
unsigned char a0 = buffer[0];
int b0 = (int)a0;
int mylen0 = b0* (int)0x1000000;
unsigned char a1 = buffer[1];
int b1 = (int)a1;
int mylen1 = a1* (int)0x10000;
unsigned char a2 = buffer[2];
int b2 = (int)a2;
int mylen2 = a2* (int)0x100;
unsigned char a3 = buffer[3];
int b3 = (int)a3;
int mylen3 = b3;
mylen = mylen0 + mylen1 + mylen2 + mylen3;
printf("receive data length: %d\n",mylen);
if (mylen>0)
{
/*received length then send ack signal cokstart.*/
send(sockfd, cokstart, 1, 0);
}
/* receive one frame of jpg data */
if(mylen>100)
{
while(mylen)
{
memset( buffer, 0, BUF_SIZE );
size=recv(sockfd,buffer,mylen,0);
for(int i = 0 ; i < size ; i++)
{
vec.push_back(buffer[i]);
}
mylen = mylen-size;
}
/* decode jpg data */
img_decode = imdecode(vec, CV_LOAD_IMAGE_COLOR);
/* release vector then ready to receive next frame */
vec.clear();
//cout << "vector capacity:"<<vec.capacity()<<endl;
vector<char>(vec).swap(vec);
//cout << "vector capacity afterswap:"<<vec.capacity()<<endl;
/* display the jpg in windows */
namedWindow("pic",WINDOW_AUTOSIZE);
if( !img_decode.empty())
{
imshow("pic",img_decode);
/* save to file -- this function is optional */
//j++;
//filename = "pic"+int2string(j)+".jpg";
//imwrite(filename,img_decode);
}
/* reflash display window in every 33ms */
cvWaitKey(33);
/* send ack signal cok to tell that I'm ready to handler next frame */
char cok[ 1 ]={0x55};
send(sockfd, cok, 1, 0);
usleep(1000);
}
nTry++;
}
exit(0);
}
5. 编译服务端后台程序
g++ server.cpp -o ser1 `pkg-config opencv --cflags` `pkg-config opencv --libs`
6. 编译客户端程序
g++ client.cpp -o cli1 `pkg-config opencv --cflags` `pkg-config opencv --libs`
7. 运行服务器程序
./ser1
8. 运行客户端程序
./cli1
测试效果一切正常,
小结:通过这个程序,可以了解 报像头的图像转换为字符串,并通过socket发送数据,客服端则接收数据后重新转换为图像,不过,这个过程,可能会有延时,大约一秒左右。
并且刷率很低。
源代码下载路径: