简单的方法来显示在C / Linux的一个连续更新图像(Easy way to display a

2019-07-05 12:53发布

我是一个科学家,谁是下数值计算相当舒适,但我需要一些帮助,显示结果。 我希望能够以显示一个窗口,它是由实时数据计算的不断更新位图。 我想能够相当快速地更新图像(例如快于1帧/秒,优选为100 fps)的。 例如:

char image_buffer[width*height*3];//rgb data
initializewindow();

for (t=0;t<t_end;t++)
{
   getdata(data);//get some realtime data
   docalcs(image_buffer, data);//process the data into an image
   drawimage(image_buffer);//draw the image
}

什么是做在Linux(Ubuntu的)最简单的方法? 我应该怎么使用initializewindow()和drawImage方法()?

Answer 1:

如果你想要做的是显示的数据(即不需要一个GUI),你可能想看看SDL :这是直着从你的像素数据创建一个表面 ,然后在屏幕上显示出来 。

灵感来自Artelius的回答 ,我也砍死了一个示例程序:

#include <SDL/SDL.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>

#define WIDTH 256
#define HEIGHT 256

static _Bool init_app(const char * name, SDL_Surface * icon, uint32_t flags)
{
    atexit(SDL_Quit);
    if(SDL_Init(flags) < 0)
        return 0;

    SDL_WM_SetCaption(name, name);
    SDL_WM_SetIcon(icon, NULL);

    return 1;
}

static uint8_t * init_data(uint8_t * data)
{
    for(size_t i = WIDTH * HEIGHT * 3; i--; )
        data[i] = (i % 3 == 0) ? (i / 3) % WIDTH :
            (i % 3 == 1) ? (i / 3) / WIDTH : 0;

    return data;
}

static _Bool process(uint8_t * data)
{
    for(SDL_Event event; SDL_PollEvent(&event);)
        if(event.type == SDL_QUIT) return 0;

    for(size_t i = 0; i < WIDTH * HEIGHT * 3; i += 1 + rand() % 3)
        data[i] -= rand() % 8;

    return 1;
}

static void render(SDL_Surface * sf)
{
    SDL_Surface * screen = SDL_GetVideoSurface();
    if(SDL_BlitSurface(sf, NULL, screen, NULL) == 0)
        SDL_UpdateRect(screen, 0, 0, 0, 0);
}

static int filter(const SDL_Event * event)
{ return event->type == SDL_QUIT; }

#define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff })

int main(int argc, char * argv[])
{
    (void)argc, (void)argv;
    static uint8_t buffer[WIDTH * HEIGHT * 3];

    _Bool ok =
        init_app("SDL example", NULL, SDL_INIT_VIDEO) &&
        SDL_SetVideoMode(WIDTH, HEIGHT, 24, SDL_HWSURFACE);

    assert(ok);

    SDL_Surface * data_sf = SDL_CreateRGBSurfaceFrom(
        init_data(buffer), WIDTH, HEIGHT, 24, WIDTH * 3,
        mask32(0), mask32(1), mask32(2), 0);

    SDL_SetEventFilter(filter);

    for(; process(buffer); SDL_Delay(10))
        render(data_sf);

    return 0;
}


Answer 2:

我建议SDL太。 然而,有一点了解你需要收集如果你想要写快的程序,这不是最容易做的事情。

我建议这个奥赖利文章为出发点。

不过,我会从计算的角度归结最重要的要点。

双缓冲

SDL什么所谓的“双缓冲”通常被称为页面翻转

这基本上意味着显卡上,有两个内存块称为 ,每一个大到足以容纳数据的屏幕的价值。 一个是可见的显示器上,另一种是通过程序访问。 当你调用SDL_Flip()显卡切换自己的角色(即可见一个变成节目访问,反之亦然)。

另一种选择是,而不是交换的网页的角色 ,而不是将数据从程序访问的页面复制到监测页面(使用SDL_UpdateRect()

翻页速度快,但有一个缺点:页面翻转后,你的程序所呈现的包含从2帧以前的像素的缓冲区。 如果你需要每一帧重新计算每个像素,这是好的。

但是,如果你只需要在屏幕上每一帧修改短小的区域,并在屏幕的其他部分并不需要改变,那么UpdateRect可以有更好的方式(参见: SDL_UpdateRects()

当然,这取决于它是什么你的计算,以及如何你形象化它。 分析您的图像生成代码 - 也许你可以重新调整它得到的东西更有效出来的吗?

请注意,如果您的图形硬件不支持页面翻转,SDL将正常使用另一种方法适合你。

软件/硬件/ OpenGL的

这是你面对的另一个问题。 基本上,软件表面居住在RAM,硬件的表面生活在显存和OpenGL表面由OpenGL的魔力管理。

根据您的硬件,操作系统和SDL版本,编程修改硬件表面的像素可以包括存储复制很多(VRAM到RAM中,然后回来了!)。 你不希望这种事情发生每一帧。 在这种情况下,软件的表面更好地工作。 但是,你不能利用双缓冲,也没有硬件加速的blit。

的blit是从一个表面到另一个的像素的块的副本。 如果你想画了一大堆的图标相同的表面上这非常适用。 事实并非如此有用的,如果你产生的温度图。

OpenGL的让你做更多的事情与你的图形硬件(一开始3D加速)。 现代图形卡都具有大量的处理能力,但它是一种很难,除非你正在做一个三维仿真使用。 编写代码的图形处理器是可行的,但对于普通C.很大的不同

演示

下面是我做了一个快速演示SDL的程序。 它不应该是一个很好的例子,并可能有一些可移植性问题。 (我会尝试编辑一个更好的方案到这个帖子的时候我得到的时间。)

#include "SDL.h"
#include <assert.h>
#include <math.h>

/* This macro simplifies accessing a given pixel component on a surface. */
#define pel(surf, x, y, rgb) ((unsigned char *)(surf->pixels))[y*(surf->pitch)+x*3+rgb]


int main(int argc, char *argv[])
{
    int x, y, t;

    /* Event information is placed in here */
    SDL_Event event;

    /* This will be used as our "handle" to the screen surface */
    SDL_Surface *scr;

    SDL_Init(SDL_INIT_VIDEO);

    /* Get a 640x480, 24-bit software screen surface */
    scr = SDL_SetVideoMode(640, 480, 24, SDL_SWSURFACE);
    assert(scr);

    /* Ensures we have exclusive access to the pixels */
    SDL_LockSurface(scr);

    for(y = 0; y < scr->h; y++)
        for(x = 0; x < scr->w; x++)
        {
            /* This is what generates the pattern based on the xy co-ord */
            t = ((x*x + y*y) & 511) - 256;
            if (t < 0)
                t = -(t + 1);

            /* Now we write to the surface */
            pel(scr, x, y, 0) = 255 - t; //red
            pel(scr, x, y, 1) = t; //green
            pel(scr, x, y, 2) = t; //blue
        }
    SDL_UnlockSurface(scr);

    /* Copies the `scr' surface to the _actual_ screen */
    SDL_UpdateRect(scr, 0, 0, 0, 0);


    /* Now we wait for an event to arrive */
    while(SDL_WaitEvent(&event))
    {
        /* Any of these event types will end the program */
        if (event.type == SDL_QUIT
         || event.type == SDL_KEYDOWN
         || event.type == SDL_KEYUP)
            break;
    }
    SDL_Quit();
    return EXIT_SUCCESS;
}


Answer 3:

GUI的东西是有规律,改造轮,而且也没有理由不使用框架。

我建议您使用QT4或wxWidgets的。 如果你正在使用Ubuntu,GTK +就足够了,因为它会谈到GNOME和可能更愿意给您(QT和wxWidgets的都需要C ++)。

看一看GTK + , QT和wxWidgets的 。

这里的所有3教程:

  • 世界您好 ,wxWidgets的
  • GTK + 2.0教程 ,GTK +
  • 教程 ,QT4


Answer 4:

除了杰德史密斯的答案,也有低级别的框架,如OpenGL的,它通常用于游戏编程。 既然你要使用高帧速率,我会考虑类似的东西。 GTK等的主要目的不是用于快速更新显示。



Answer 5:

在通过MIT-SHM扩展我的经验的Xlib比SDL表面显著快,不知道我使用SDL在最优化的方式虽然。



文章来源: Easy way to display a continuously updating image in C/Linux