欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于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);
}