c++ fast screenshots in linux for use with opencv

后端 未结 4 1470
面向向阳花
面向向阳花 2021-01-30 08:02

I\'m trying to find a fast way to take screenshots (as in 30 fps or over) for use with opencv in c++

All the information I\'ve found online either involved windows.h or

4条回答
  •  北恋
    北恋 (楼主)
    2021-01-30 08:12

    Based on @abc's answer I came up with the following, using MIT's shared memory extension for X.

    @abc's example runs at 120-180 fps and uses ~40% of a Titan X (Maxwell). The following runs at 15000 fps and uses 80% of a Titan X. (Assuming you don't sync. If you do sync, then the framerate drops to @abc's framerate!)

    Comment out the break; statement inside the inner loop too run it nonstop.

    Version using @abc's class:

    // g++ screena.cpp -o screena -lX11 -lXext -Ofast -mfpmath=both -march=native -m64 -funroll-loops -mavx2 `pkg-config opencv --cflags --libs` && ./screena
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    #include   // This includes most headers!
    
    #include 
    #define FPS(start) (CLOCKS_PER_SEC / (clock()-start))
    
    
    struct ScreenShot{
        ScreenShot(uint x, uint y, uint width, uint height):
                   x(x), y(y), width(width), height(height){
    
            display = XOpenDisplay(nullptr);
            root = DefaultRootWindow(display);
    
            XGetWindowAttributes(display, root, &window_attributes);
            screen = window_attributes.screen;
            ximg = XShmCreateImage(display, DefaultVisualOfScreen(screen), DefaultDepthOfScreen(screen), ZPixmap, NULL, &shminfo, width, height);
    
            shminfo.shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT|0777);
            shminfo.shmaddr = ximg->data = (char*)shmat(shminfo.shmid, 0, 0);
            shminfo.readOnly = False;
            if(shminfo.shmid < 0)
                puts("Fatal shminfo error!");;
            Status s1 = XShmAttach(display, &shminfo);
            printf("XShmAttach() %s\n", s1 ? "success!" : "failure!");
    
            init = true;
        }
    
        void operator() (cv::Mat& cv_img){
            if(init)
                init = false;
    
            XShmGetImage(display, root, ximg, 0, 0, 0x00ffffff);
            cv_img = cv::Mat(height, width, CV_8UC4, ximg->data);
        }
    
        ~ScreenShot(){
            if(!init)
                XDestroyImage(ximg);
    
            XShmDetach(display, &shminfo);
            shmdt(shminfo.shmaddr);
            XCloseDisplay(display);
        }
    
        Display* display;
        Window root;
        XWindowAttributes window_attributes;
        Screen* screen;
        XImage* ximg;
        XShmSegmentInfo shminfo;
    
        int x, y, width, height;
    
        bool init;
    };
    
    
    int main(){
        ScreenShot screen(0, 0, 1920, 1080);
        cv::Mat img;
    
        for(uint i;; ++i){
            double start = clock();
    
            screen(img);
    
            if(!(i & 0b111111))
                printf("fps %4.f  spf %.4f\n", FPS(start), 1 / FPS(start));
                break;
    
        }
    
        cv::imshow("img", img);
        cv::waitKey(0);
    }
    

    "Naked" version:

    // g++ xshm2.c -o xshm2 -lX11 -lXext `$cv`-Ofast -mfpmath=both -march=native -m64 -funroll-loops -mavx2 && ./xshm2
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    #include   // This includes most headers!
    
    #include 
    #define FPS(start) (CLOCKS_PER_SEC / (clock()-start))
    
    // Using one monitor DOESN'T improve performance! Querying a smaller subset of the screen DOES
    const uint WIDTH  = 1920>>0;
    const uint HEIGHT = 1080>>0;
    
    // -------------------------------------------------------
    int main(){
        Display* display = XOpenDisplay(NULL);
        Window root = DefaultRootWindow(display);  // Macro to return the root window! It's a simple uint32
        XWindowAttributes window_attributes;
        XGetWindowAttributes(display, root, &window_attributes);
        Screen* screen = window_attributes.screen;
        XShmSegmentInfo shminfo;
        XImage* ximg = XShmCreateImage(display, DefaultVisualOfScreen(screen), DefaultDepthOfScreen(screen), ZPixmap, NULL, &shminfo, WIDTH, HEIGHT);
    
        shminfo.shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT|0777);
        shminfo.shmaddr = ximg->data = (char*)shmat(shminfo.shmid, 0, 0);
        shminfo.readOnly = False;
        if(shminfo.shmid < 0)
            puts("Fatal shminfo error!");;
        Status s1 = XShmAttach(display, &shminfo);
        printf("XShmAttach() %s\n", s1 ? "success!" : "failure!");
    
        cv::Mat img;
    
        for(int i; ; i++){
            double start = clock();
    
            XShmGetImage(display, root, ximg, 0, 0, 0x00ffffff);
            img = cv::Mat(HEIGHT, WIDTH, CV_8UC4, ximg->data);
    
            if(!(i & 0b111111))
                printf("fps %4.f  spf %.4f\n", FPS(start), 1 / FPS(start));
            break;
        }
    
        cv::imshow("img", img);
        cv::waitKey(0);
    
        XShmDetach(display, &shminfo);
        XDestroyImage(ximg);
        shmdt(shminfo.shmaddr);
        XCloseDisplay(display);
        puts("Exit success!");
    }
    

提交回复
热议问题