` 本帖最后由 donatello1996 于 2021-1-11 00:52 编辑
既然是要做图像分类识别,那么从摄像头获取图像那也是必须的,电脑端的QT上位机通过TCP或者UDP两种协议从开发板处获得连续帧图像,这里有三种方式可以实现,第一种就是直接在开发板上生成每一帧的图片,QT上位机直接通过FTP方式读取图片,这个直接用传统的FTP协议即可实现,不需要做任何传输处理,图片可编程性最低,因为图片文件是在板子上面的,只能在板子上面做图片编程,而且QT上位机读取图片也会出现冲突的情况;第二种方式也是直接在开发板上生成每一帧的图片,通过TCP或者UDP协议将图片切割传输,每一帧传输1024个字节,再在QT上位机上组合生成图片,这种方法同样图片可编程性很低,不过还是可以可以直接读取图片信息的,因为这种方式会在QT上位机上生成图片文件,就可以进行对图片的编程了;最后一种方式是直接通过TCP或UDP协议传输图片的点阵数据部分,也就是不以文件形式传输,相当于传输一个二维数组,这种方式可编程性最高,但是TCP方式会出现延迟或图片撕裂现象,最好是用UDP实现,UDP方式传输图片缓存这个会在我之后的帖子中写出来。
首先是板子的代码,这里我的设计是板子做TCP客户端以及UDP发送端,并封装好了 TCP_Client_Found()和UDP_Found()函数,这两个函数的作用就是初始化socket接口以及sockfd套接字文件符(socklen_t型),对于TCP通信,只需要传出sockfd参数即可,将socket_found变量以指针方式传出,因为不是TCP服务器端,因此不需要bind() accept()等操作,只需要socket()和connect()操作:
- int TCP_Client_Found(socklen_t* socket_found,char* ip,int port)
- {
- struct sockaddr_in servaddr;
- if( (*socket_found = socket(AF_INET,SOCK_STREAM,0)) == -1)
- {
- printf(" create socket error: %s (errno :%d)
- ",strerror(errno),errno);
- return -1;
- }
- memset(&servaddr,0,sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(port);
- servaddr.sin_addr.s_addr=inet_addr(ip);
- if(connect(*socket_found , (struct sockaddr*)&servaddr,sizeof(servaddr)) <0)
- {
- printf(" connect socket error: %s(errno :%d)
- ",strerror(errno),errno);
- return -2;
- }
- return 0;
- }
复制代码
对于UDP通信的话传出参数就多了一个sockaddr_in地址信息,因为UDP通信的靶向信息是存放在addr结构体里面的,同样是使用指针方式进行传出:
- int UDP_Found(socklen_t* socket_found,struct sockaddr_in *addr,char* ip,int port)
- {
- *socket_found = socket(AF_INET, SOCK_DGRAM, 0);
- if(*socket_found == (~0))
- {
- printf("Create Socket Failed!
- ");
- return -1;
- }
- addr->sin_family = AF_INET;
- addr->sin_addr.s_addr = inet_addr(ip);
- addr->sin_port = htons(port);
- memset(addr->sin_zero, 0, 8);
- }
复制代码
传输文件的方式借用了网上代码,大致就是用FILE指针读取文件,将文件切片读取并传输,除去最后一片外,所有切片均是相同大小,文件信息存放在Package结构体中:
- int TCP_Send_Picture(socklen_t socket_send,char* filename)
- {
- struct Package
- {
- int length;
- char data[TCP_FRAME_LEN];
- int fin;
- }picture;
- socklen_t addr_len = sizeof(struct sockaddr_in);
- FILE *fp;
- fp = fopen(filename, "rb+");
- printf("fp = %d
- ",fp);
- fseek(fp, 0, SEEK_END);
- int fend = ftell(fp);
- fseek(fp, 0, 0);
- int sendbytes;
- printf("fend = %d
- ",fend);
- while(fend > 0)
- {
- memset(picture.data, 0, sizeof(picture.data));
- fread(picture.data, TCP_FRAME_LEN, 1, fp);
- if(fend >= TCP_FRAME_LEN)
- {
- picture.length = TCP_FRAME_LEN;
- picture.fin = 0;
- }
- else
- {
- picture.length = fend;
- picture.fin = 1;
- }
- printf("sendbytes = %d
- ",sendbytes);
- sendbytes = send(socket_send, (char *)&picture, sizeof(struct Package), 0);
- if(sendbytes == -1)
- {
- printf("Send Picture Failed!d
- ");
- return -1;
- }
- else
- {
- fend -= TCP_FRAME_LEN;
- }
- }
- }
复制代码
UDP方式基本相同,比TCP方式少了accept()握手操作:
- int UDP_Send_Picture(socklen_t socket_send,struct sockaddr_in addr,char* filename)
- {
- struct Package
- {
- int length;
- char data[UDP_FRAME_LEN];
- int fin;
- }picture;
- socklen_t addr_len = sizeof(struct sockaddr_in);
- FILE *fp;
- fp = fopen(filename, "rb+");
- printf("fp = %d
- ",fp);
- fseek(fp, 0, SEEK_END);
- int fend = ftell(fp);
- fseek(fp, 0, 0);
- int sendbytes;
- printf("fend = %d
- ",fend);
- while(fend > 0)
- {
- memset(picture.data, 0, sizeof(picture.data));
- fread(picture.data, UDP_FRAME_LEN, 1, fp);
- if(fend >= UDP_FRAME_LEN)
- {
- picture.length = UDP_FRAME_LEN;
- picture.fin = 0;
- }
- else
- {
- picture.length = fend;
- picture.fin = 1;
- }
- //printf("sendbytes = %d
- ",sendbytes);
- sendbytes = sendto(socket_send, (char *)&picture, sizeof(struct Package), 0, (struct sockaddr*)&addr,addr_len);
- if(sendbytes == -1)
- {
- printf("Send Picture Failed!d
- ");
- return -1;
- }
- else
- {
- fend -= UDP_FRAME_LEN;
- }
- }
- }
复制代码
操作函数(分开两个main):
TCP方式:
- int main(int argc, char**argv)
- {
- int recvbytes;
- socklen_t socklen_tcp;
- TCP_Client_Found(&socklen_tcp,IP_ADDRESS,TCP_PORT);
- V4L2_Init(CAMERA_DEV);
- while(1)
- {
- V4l2_Grab();
- Yuyv_2_RGB888(buffers,frame_buffer);
- Encode_Jpeg(frame_buffer,640,480,"1.jpg");
- TCP_Send_Picture(socklen_tcp,(char*)"/home/workspace1/1.jpg");
- sleep(1);
- // char recvbuffer[256];
- // recvbytes = recv(socklen_tcp , recvbuffer , sizeof(recvbuffer) , 0);
- // printf("Server: %s
- ",recvbuffer);
- // printf("Please input img to send: ");
- }
- close(socklen_tcp);
- return 0;
- }
复制代码
UDP方式:
- int main(int argc, char* argv[])
- {
- int recvbytes;
- struct sockaddr_in sockaddr_udp;
- socklen_t socklen_udp,addr_len = sizeof(struct sockaddr_in);
- UDP_Found(&socklen_udp,&sockaddr_udp,IP_ADDRESS,UDP_PORT);
- V4L2_Init(CAMERA_DEV);
- while(1)
- {
- V4l2_Grab();
- Yuyv_2_RGB888(buffers,frame_buffer);
- Encode_Jpeg(frame_buffer,640,480,"1.jpg");
- UDP_Send_Picture(socklen_udp,sockaddr_udp,(char*)"/home/workspace1/1.jpg");
- char recvbuffer[256];
- recvbytes = recvfrom(socklen_udp , recvbuffer , sizeof(recvbuffer) , 0,
- (struct sockaddr*)&sockaddr_udp , &addr_len);
- printf("Server: %s
- ",recvbuffer);
- printf("Please input img to send: ");
- }
- close(socklen_udp);
- }
复制代码
电脑QT上位机设计:
这是TCP和UDP两种不同传输方式的实际效果:
可以看出来UDP方式要比TCP更为顺畅,但是即使是UDP方式显示效果依然很差,这里有两个原因,第一是摄像头太低档,帧生成时间长,即使是在开发板本机输出也快不到哪里去,第二是网络传输文件的速率还可以再改进。
`
|