基于Socket、Opencv、树莓派---实时拍摄并传输图片
程序员文章站
2022-04-24 11:06:43
...
- 1.器件
1 | 上位机—笔记本 |
2 | 下位机–树莓派zero w/树莓派3B+ |
3 | 树莓派V2相机–800w像素 |
-
2.基于SOCKET的通讯
Server----作为服务器接收图片
Client----作为客户端采集图片并通过socket的网口连接传输 -
3.树莓派Linux,笔记本Windows/Linux
Server端代码-----(Linux)
1.main.cpp
#include<several_mat.h>
int main()
{
getpicture img;
if(img.socketConnect(8888)<0) //建立socket通讯,端口为8888
{
cout<<"connect error!";
return -1;
}
Mat image;
if(img.acceptfile(image)>0) //等待客户端的信号输入,接收图片
{
cout<<"accept is OK!";
}
img.socketDisconnect();
return 0;
}
2.several_mat.h
#ifndef SEVERAL_IMGS_H
#define SEVERAL_IMGS_H
#endif // SEVERAL_IMGS_H
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
using namespace std;
using namespace cv;
#define MAXLINE 1024*1024 //最大传输单张图片的大小
#define img_width 1920 //图片的分辨率
#define img_height 1080
#define img_num 30 //传输图片的张数
#define packet_num 8 //把一张图片划分成n部分传输
struct recvBuf //接收的数据
{
char buf[MAXLINE];
int flag; //来判断一张图片接收完成
};
class getpicture
{
public:
getpicture(void);
~getpicture(void);
int socketConnect(int PORT); //socket通讯
int acceptfile(Mat& image); //接收图片,每一个像素的接收
void socketDisconnect(void);//关闭服务器
private:
struct recvBuf data;
int needRecv;
int count;
int sockConn;
};
3.several_mat.cpp
#include<several_mat.h>
getpicture::getpicture(void)
{
}
getpicture::~getpicture(void)
{
}
int getpicture::socketConnect(int PORT)
{
int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);//创建套接字,初始化信息
struct sockaddr_in server_sockaddr; //指向sockaddr地址的指针,该结构含有IP和PORT
server_sockaddr.sin_family = AF_INET; //ipv4
server_sockaddr.sin_port = htons(PORT); //端口
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //ip地址
if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)//bind函数将socket关联一个本地地址
{
perror("bind");
return -1;
}
if(listen(server_sockfd,5) == -1)//listen来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
{
perror("listen");
return -1;
}
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
sockConn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length); //socket()、bind()、listen()之后,就会监听指定的socket地址了。
//TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。
//TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。
if(sockConn<0) //之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
{
perror("connect");
return -1;
}
else
{
printf("connect successful!\n");
}
// int nRecvBuf = 1024 * 1024 * 20;
// setsockopt(sockConn, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int));
}
void getpicture::socketDisconnect(void)
{
close(sockConn);
}
int getpicture::acceptfile(Mat& image)
{
int returnflag = 0;
cv::Mat img(img_height, img_width, CV_8UC3, cv::Scalar(0));
needRecv = sizeof(recvBuf); //struct recvBuf int needRecv
count = 0;
memset(&data,0,sizeof(data));
for (int p=0;p<img_num;p++)
{
for (int i = 0; i < packet_num; i++) //一张图片划分为n个区域来传递,一个像素一个像素的传递
{
int pos = 0;
int len0 = 0;
while (pos < needRecv) //接收缓冲区中的数据可能大于buf,所以需要调用几次recv函数把接收缓冲区中的数据完全copy
{
len0 = recv(sockConn, (char*)(&data) + pos, needRecv - pos, 0);//3.needRecv>2buf 分多次传 每次传pos的数据量
if (len0 < 0)//3
{
printf("Server Recieve Data Failed!\n");
break;
}
pos += len0;//
}
count = count + data.flag;//1+1+1+1+1+1+1+.....2
int num1 = img_height / packet_num * i; //划分为每一行像素
for (int j = 0; j < img_height / packet_num; j++)
{
int num2 = j * img_width * 3;
uchar* ucdata = img.ptr<uchar>(j + num1);
for (int k = 0; k < img_width * 3; k++)
{
ucdata[k] = data.buf[num2 + k]; //划分为每个像素
}
}
if (data.flag == 2) //一张图片的最后一块区域 data.flag=2
{
if (count == packet_num + 1)//表示一张图片是传输完整的
{
image = img;
string str="/home/yqz/图片/"+to_string(p+1)+".jpg";
imwrite(str,img);
returnflag++;
count = 0;// one picture over,begin next
}
else
{
count = 0; //if (count != PACKAGE_NUM + 1) restart transmit
i = 0;
}
}
}
}
if(returnflag == img_num)
return 1;
else
return -1;
}
Server端代码-----(Windows)
1.main.cpp
#include"several_mat.h"
int main()
{
getpicture img;
if (img.socketConnect(8888) < 0)
{
cout << "connect error!";
return -1;
}
Mat image;
if (img.acceptfile(image) > 0)
{
cout << "accept is OK!";
}
img.socketDisconnect();
system("pause");
return 0;
}
2.several_mat.h
#ifndef SEVERAL_IMGS_H
#define SEVERAL_IMGS_H
#endif // SEVERAL_IMGS_H
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib ")
using namespace std;
using namespace cv;
#define MAXLINE 1024*1024
#define img_width 1920
#define img_height 1080
#define img_num 20
#define packet_num 8
struct recvBuf
{
char buf[MAXLINE];
int flag;
};
class getpicture
{
public:
getpicture(void);
~getpicture(void);
int socketConnect(int PORT);
int acceptfile(Mat& image);
void socketDisconnect(void);
private:
struct recvBuf data;
int needRecv;
int count;
SOCKET sockConn;
};
3.several_mat.cpp
#include"several_mat.h"
getpicture::getpicture(void)
{
}
getpicture::~getpicture(void)
{
}
int getpicture::socketConnect(int PORT)
{
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)//初始化供进程调用的Winsock相关的dll
{
cout << "WSAStartup error" << endl; //WSACleanup()释放Ws2_32.dl的l函数
return 0;
}
SOCKET server_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//socket函数将创建指定传输服务的socket
if (server_sockfd == INVALID_SOCKET)
{
int er = WSAGetLastError();
return 0;
}
u_long mode = 0;
ioctlsocket(server_sockfd, FIONBIO, &mode);
sockaddr_in server_sockaddr; //指定一个未绑定的socket
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.2");
//server_sockaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (::bind(server_sockfd, (const SOCKADDR*)&server_sockaddr, sizeof(SOCKADDR)) == SOCKET_ERROR)//bind函数将socket关联一个本地地址
{
perror("bind");
return -1;
}
if (listen(server_sockfd, 5) == SOCKET_ERROR)
{
perror("listen");
return -1;
}
printf("Listening To Client...\n");
sockaddr_in client_addr;
int length = sizeof(client_addr);
sockConn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
if (sockConn < 0)
{
perror("connect");
return -1;
}
else
{
printf("connect successful!\n");
}
/*int nRecvBuf = 1024 * 1024 * 20;
setsockopt(sockConn, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int));*/
}
void getpicture::socketDisconnect(void)
{
closesocket(sockConn);
WSACleanup();
}
int getpicture::acceptfile(Mat& image)
{
int returnflag = 0;
cv::Mat img(img_height, img_width, CV_8UC3, cv::Scalar(0));
needRecv = sizeof(recvBuf); //struct recvBuf int needRecv
count = 0;
memset(&data, 0, sizeof(data));
for (int p = 0; p < img_num; p++)
{
for (int i = 0; i < packet_num; i++)
{
int pos = 0;
int len0 = 0;
while (pos < needRecv)
{
len0 = recv(sockConn, (char*)(&data) + pos, needRecv - pos, 0);//3needRecv>2buf fen duoci chuan meicichuan pos
if (len0 < 0)//3
{
printf("Server Recieve Data Failed!\n");
break;
}
pos += len0;//
}
count = count + data.flag;//1+1+1+1+1+1+1+.....2
int num1 = img_height / packet_num * i;
for (int j = 0; j < img_height / packet_num; j++)
{
int num2 = j * img_width * 3;
uchar* ucdata = img.ptr<uchar>(j + num1);
for (int k = 0; k < img_width * 3; k++)
{
ucdata[k] = data.buf[num2 + k];
}
}
if (data.flag == 2) //final area data.flag=2
{
if (count == packet_num + 1)
{
image = img;
string str = "d:\\" + to_string(p + 1) + ".jpg";
imwrite(str, img);
returnflag++;
count = 0;// one picture over,begin next
}
else
{
count = 0; //if (count != PACKAGE_NUM + 1) restart transmit
i = 0;
}
}
}
}
if (returnflag == img_num)
return 1;
else
return -1;
}
Client-----(树莓派采集图片)
1.边拍变传
/////////////////////////////////////////////////////////////////////////////////main.cpp
#include <severalimg.h>
int main()
{
severalimg img;
if(img.connectsocket("192.168.1.2",8888)<0)
{
cout<<"connect error!";
return -1;
}
if(img.getandtransmit()>0)
{
cout<<"transmit is right!";
}
img.socketDisconnect();
return 0;
}
/////////////////////////////////////////////////////////////////////////////severalimg.h
#ifndef SEVERALIMG_H
#define SEVERALIMG_H
#endif // SEVERALIMG_H
#include<iostream>
#include<opencv2/opencv.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
using namespace std;
using namespace cv;
#define img_width 1920
#define img_height 1080
#define img_exposure -20
#define img_fps 30
#define MAXLINE 1024*1024
#define delay 1000 //1s=1000ms
#define img_num 20
#define packet_num 8
struct sentbuf
{
char buf[MAXLINE];
int flag;
};
class severalimg
{
public:
severalimg(void);
~severalimg(void);
int connectsocket(const char* IP,int PORT);
// int transmit(vector<Mat>img);
// vector<Mat> getimg();
int getandtransmit();
void socketDisconnect();
private:
struct sentbuf data;
int sockClient;
};
///////////////////////////////////////////////////////////////////////////severalimg.cpp
#include<severalimg.h>
severalimg::severalimg(void)
{
}
severalimg::~severalimg(void)
{
}
int severalimg::getandtransmit()
{
VideoCapture capture(0);
Mat img;
int imgimg_num;
capture.set(CV_CAP_PROP_FRAME_WIDTH,img_width);
capture.set(CV_CAP_PROP_FRAME_HEIGHT,img_height);
capture.set(CV_CAP_PROP_FPS,img_fps);
capture.set(CV_CAP_PROP_EXPOSURE, img_exposure);
if(!capture.isOpened())
{
cout<<"The camera can not open!"<<endl;
//return -1;
}
while(1)
{
for(int i=0;i<img_num;i++)
{
Mat image;
capture>>image;
img=image;
String img_name="/home/pi/imgimg/"+to_string(i+1)+".jpg";
imwrite(img_name,image);
for(int k = 0; k < packet_num; k++)//##划分每块区域
{
int num1 = img_height / packet_num * k;//720/8 *(0-7) 每块区域的第一个元素
for (int i = 0; i < img_height/ packet_num; i++) //##划分每块区域的每一行
{
int num2 = i * img_width * 3;
uchar* ucdata = img.ptr<uchar>(i + num1);//第一行第一个元素,第二行第一个元素
for (int j = 0; j < img_width * 3; j++)//##划分每块区域每一行的每一个元素
{
data.buf[num2 + j] = ucdata[j];//每一行的元素每个元素相对应
}
}
if(k == packet_num - 1)
{ //最后一块区域data.flag为2,反之为1
data.flag = 2;
}
else
{
data.flag = 1;
} //发送8次数据
if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
{
printf("send image error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
}
waitKey(delay);
imgimg_num++;
}
capture.release();
break;
}
if(imgimg_num==img_num)
return 1;
else
return -1;
}
int severalimg::connectsocket(const char* IP, int PORT)//dingyi socket
{
struct sockaddr_in servaddr;
if ((sockClient = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, IP, &servaddr.sin_addr) <= 0)
{
printf("inet_pton error for %s\n", IP);
return -1;
}
if (connect(sockClient, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
else
{
//int nsendbuf=1024*1024;
//setsockopt(sockClient,SOL_SOCKET,SO_SNDBUF,(const char*)&nsendbuf,sizeof(int));
printf("connect successful!\n");
return 1;
}
}
//int severalimg::transmit(vector<Mat>picture)
//{
// if(picture.empty())
// {
// cout<<"empty picture";
// return -1;
// }
// Mat img1;
// for(int l=0;l<img_num;l++)
// {
// img1=picture[l];
// for(int k = 0; k < packet_num; k++)//##划分每块区域
// {
// int num1 = img_height / packet_num * k;//720/8 *(0-7) 每块区域的第一个元素
// for (int i = 0; i < img_height/ packet_num; i++) //##划分每块区域的每一行
// {
// int num2 = i * img_width * 3;
// uchar* ucdata = img1.ptr<uchar>(i + num1);//第一行第一个元素,第二行第一个元素
// for (int j = 0; j < img_width * 3; j++)//##划分每块区域每一行的每一个元素
// {
// data.buf[num2 + j] = ucdata[j];//每一行的元素每个元素相对应
// }
// }
// if(k == packet_num - 1)
// { //最后一块区域data.flag为2,反之为1
// data.flag = 2;
// }
// else
// {
// data.flag = 1;
// } //发送8次数据
// if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
// {
// printf("send image error: %s(errno: %d)\n", strerror(errno), errno);
// return -1;
// }
// }
// }
//}
void severalimg::socketDisconnect()
{
close(sockClient);
}