简单的方法来显示在C / Linux中不断更新的图像

我是一个对C进行数值计算相当舒服的科学家,但是我需要一些帮助来显示结果。 我希望能够在一个窗口中显示一个连续更新的位图,这是从实时数据计算出来的。 我希望能够相当快地更新图像(例如,快于1帧/秒,最好是100帧/秒)。 例如:

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()?

Solutions Collecting From Web of "简单的方法来显示在C / Linux中不断更新的图像"

如果您只想显示数据(即不需要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; } 

我也推荐SDL。 然而,如果你想编写快速的程序,你需要收集一些理解,这不是最简单的事情。

我会建议这个O'Reilly文章作为一个起点。

但是从计算的角度来看,我将归纳出最重要的一点。

双缓冲

SDL所称的“双缓冲”通常称为翻页

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

另一种方法是,不是交换页面的角色 ,而是将数据从程序可访问的页面复制到监控页面(使用SDL_UpdateRect() )。

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

但是,如果您只需要在每一帧中修改屏幕上的较小区域,并且屏幕的其余部分不需要更改,则UpdateRect可以是更好的方法(另请参阅: SDL_UpdateRects() )。

这当然取决于你在计算什么,以及如何将其视觉化。 分析你的图像生成代码 – 也许你可以重组它来获得更有效率的东西呢?

请注意,如果您的图形硬件不支持页面翻转,SDL将优雅地使用其他方法。

软件/硬件/ OpenGL的

这是你面对的另一个问题。 基本上,软件表面存在于RAM中,硬件表面存在于视频RAM中,OpenGL表面由OpenGL魔术来管理。

根据您的硬件,操作系统和SDL版本,以编程方式修改硬件表面的像素可能涉及大量内存复制(VRAM到RAM,然后返回!)。 你不希望每一帧都发生这种情况。 在这种情况下,软件表面效果更好。 但是,那么你不能利用双缓冲,也不能利用硬件加速。

Blits是从一个表面到另一个表面的像素块复制。 如果要在表面上绘制大量相同的图标,这种方法效果很好。 如果您生成温度图,则不是很有用。

OpenGL可以让你用图形硬件做更多的事情(3D加速起步)。 现代图形卡具有很强的处理能力,但除非您正在进行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; } 

图形用户界面的东西是一个经常重新创建的轮子,没有理由不使用框架。

我建议使用QT4或wxWidgets。 如果你使用的是Ubuntu,那么GTK +就可以和GNOME交谈,而且可能对你更加舒服(QT和wxWidgets都需要C ++)。

看看GTK + , QT和wxWidgets 。

这里是所有3的教程:

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

除了Jed Smith的回答外,还有一些底层框架,比如OpenGL,这个框架经常用于游戏编程。 鉴于你想使用高帧率,我会考虑类似的东西。 GTK等不主要用于快速更新的显示器。

根据我的经验,通过MIT-SHM扩展的Xlib比SDL表面快得多,不确定我是否以最佳方式使用了SDL。