美文网首页OpenCv计算机图像理论opencv及vslam嵌入式软件学习小组
linux opencv传递网络摄像头数据--Apple的学习笔

linux opencv传递网络摄像头数据--Apple的学习笔

作者: applecai | 来源:发表于2018-05-16 22:35 被阅读17次

    一,遇到问题

    1.段溢出?

    根本原因:vector申请后没有释放,导致段溢出。
    调试方法:通过gdb调试core文件找到原因。
    解决方案:添加clear及swap函数来释放内存。

    2.client没有显示出图片?

    根本原因:都没有收到一张完整的图片就开始imshow导致。
    调试方法:添加imwrite把数据保存来看效果。
    解决方法:添加waitkey延时

    3.client通过imwrite只能保存几张相对完好的图片?imshow显示为黑色

    根本原因:imwrite的数据不完整。
    调试方法:1. 通过添加握手来分别传输长度+jpg数据。
    2. 通过打印log来看size的值是否和预期传输一致。
    解决方法:client接收大数据时候,需要while多次来接收,否则一个size的只总是小于预期接收,它只要收到数据,则不会阻塞,代码会继续往下走。

    二,直接学到的经验

    1. c++ vector的使用,申请控件,清空内存,与char转换。
    2. imwrite和imdecode等函数的应用。(jpg等压缩参数值)
    3. send和revc函数的使用及返回值的作用。
    4. socket通信的基本流程。
    5. socket大数据传输处理方式。socket的阻塞体验。
    6. core的gdb调试方法。
    7. cmake添加g++编译的方法。
    8. 各个c++函数对应的头文件。
    9. int转字符串的方法。
    10. stringstream的数据流使用。
      11.通过编译报错来直接找到原因。

    三,直接了解的相关经验

    1. socket粘包处理方法。
    2. 显示帧率与sleep时间的计算。
    3. jpg图像的格式。

    四,客户端和服务器交互说明

    服务器向读取摄像头数据向客户端先发长度,获取客户端ACK后再像客户端发送压缩为JPG的数据。


    交互图.png

    五,linux 客户端代码

    #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;
    
    /* tansfer int to string */
    string int2string(int value)
    {
        stringstream ss;
        ss<<value;
        return ss.str();
    }
    
    int main(int argc, char** argv)
    {
        int    sockfd, n;
        char    recvline[4096], sendline[4096];
        struct sockaddr_in    servaddr;
        
        #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(8080);
        if( inet_pton(AF_INET, "192.168.7.4", &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 65535
        char buffer[ BUF_SIZE ];
        vector<char> vec;
        Mat img_decode; 
        string filename="";   
        int size = 0;
        int mylen = 0;
        int j= 0;
        char cokstart[ 1 ]={0x33};
        memset( buffer, 0, 4 );
        while(1)
        {
            size = recv(sockfd,buffer,4,0);
        
            mylen = ((buffer[2]<<8)&(0xFF00))|((buffer[3])&(0xFF));
            if (mylen>0){
                /*received length then send ack signal cokstart.*/  
                send(sockfd, cokstart, 1, 0);      
            }
            /* receive one frame of jpg data */
            while(mylen) 
            {
                size=recv(sockfd,buffer,mylen,0);
                //printf("size is %d\n",size);
                //printf("mylen is %x\n",mylen);
                /* put char values to vector */
                for(int i = 0 ; i < mylen ; 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);     
            }
            
            /* reflash display window in every 33ms */
            cvWaitKey(33);
            
            /* save to file -- this function is optional */
            j++;
            filename = "pic"+int2string(j)+".jpg";
            imwrite(filename,img_decode);   
            
            /* send ack signal cok to tell that I'm ready to handler next frame */
            char cok[ 1 ]={0x55};
            send(sockfd, cok, 1, 0);
        }
    }
    

    六,服务器代码

    #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;
    
    /* tansfer int to string */
    string int2string(int value)
    {
        stringstream ss;
        ss<<value;
        return ss.str();
    }
    
    int main(int argc, char** argv)
    {
        int    listenfd, connfd;
        struct sockaddr_in     servaddr;
        char    buff[4096];
        int     n;
        int sendbytes;
    
        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(8080);
    
        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);
        }
        
        char cok[1]={0x55};
        char cokstart[1]={0};
        char j=0;
        int sizelen=0;
        int sizejpg=0;
        
        for (;;)
        {
            /* read one frame */
            cap.read(frame);
            /* check if we succeeded */
            if (frame.empty()) {
                cerr << "ERROR! blank frame grabbed\n";
                break;
            }
            /* stop display after get key press */
            if(waitKey(5)>=0)
                break;
    
            /* get trigger from client's command */
            if (cok[0]==0x55){
                cok[0]=0;
                //printf("read one frame!\n");
                /* encode frame to JPG data */
                imencode(".jpg",frame,inImage);  
                /* get length of jpg */
                int datalen=inImage.size();
                /* prepare char to save jpg data */
                unsigned char *msgImage=new unsigned char[datalen]; 
                
                unsigned char msgLen[4];
                msgLen[0]=datalen >> 24;
                msgLen[1]=datalen >> 16;
                msgLen[2]=datalen >> 8;
                msgLen[3]=datalen;
                //printf("datalen=%x\n",datalen);
                /* send lenght to client first */
                sizelen=send(connfd,msgLen,4,0);
                //printf("sizelen:%x",sizejpg);
    
                /* put vector data to char */
                for(int i=0;i<datalen;i++)  
                {  
                        msgImage[i]=inImage[i];  
                } 
                /* get lenght response ack from client */
                recv(connfd,cokstart,1,0);
                if(cokstart[0] == 0x33)
                {
                    vector<char>vec;
                    Mat img_decode;
                    string filename="";
                    /* decode than save display to save to file. This is optional function */
                    cokstart[0]=0x0;
                    /* put data to vector */
                    for(int i=0;i<datalen;i++)
                    {
                        vec.push_back(msgImage[i]);
                    }
                    /* decode JPG data */
                    img_decode =imdecode(vec,CV_LOAD_IMAGE_COLOR);
                    j++;
                    /* display JPG data */
                    imshow("serpic",img_decode);
                    /* save JPG data to files */
                    filename="sevpic"+int2string(j)+".jpg";
                    imwrite(filename,img_decode);
    
                    /* send data to client */
                    sizejpg=send(connfd,msgImage,datalen,0);
                    printf("sizejpg:%x",sizejpg);
                    usleep(10000);
                    /* get response ack from client then can send the next frame*/
                    recv(connfd,cok,1,0);
                }
        
            }
    
        }
        /* if get key press than break display and stop the socket connection */
        close(listenfd);
        return 0;
    }
    

    相关文章

      网友评论

        本文标题:linux opencv传递网络摄像头数据--Apple的学习笔

        本文链接:https://www.haomeiwen.com/subject/ukomdftx.html