<树莓派>——基于Socket、Opencv、树莓派---实时拍摄并传输图片

  • 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;
}

2.severalimg.h



/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=0;
    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(img_num==imgimg_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);
}

3.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(img_num==imgimg_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);
}

参考博客:
https://blog.csdn.net/pengz0807/article/details/52204475

  • 2
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值