如何将原始 RGB 帧缓冲区文件转换为可视格式?

Posted

技术标签:

【中文标题】如何将原始 RGB 帧缓冲区文件转换为可视格式?【英文标题】:How to convert a raw RGB frame buffer file to a viewable format? 【发布时间】:2012-09-17 09:09:10 【问题描述】:

我知道以前有人问过这个问题。原始线程在这里how to convert 16-bit RGB Frame Buffer to a viewable format? 但我没有得到我想要的输出。

目前我正在处理帧缓冲区。确切的情况是我正在访问安卓手机的帧缓冲区(/dev/graphics/fb0)(通过“adb”外壳)。我使用“dd”来获取帧缓冲区。

cd /dev/graphics

dd if=fb0 of=/sdcard/fb0.raw bs=1 count=width*height*3 //this width and height are based on mobile screen specification. And 3 is for RGB888

我使用了这个代码 -

#include <stdio.h>
#include <stdlib.h>
#include <bmpfile.h>

int main(int argc, char **argv)

bmpfile_t *bmp;
int i, j;
char* infilename;
FILE* infile;
char* outfile;
int width;
int height;
int depth;
unsigned char red, green, blue; // 8-bits each
unsigned short pixel; // 16-bits per pixel
//rgb_pixel_t bpixel = 128, 64, 0, 0;
//make && ./raw565tobmp fb.rgb565 720 480 32 fb.bmp && gnome-open fb.bmp

if (argc < 6) 
printf("Usage: %s infile width height depth outfile.\n", argv[0]);
exit(EXIT_FAILURE);


infilename = argv[1];
outfile = argv[5];

infile = fopen(infilename, "rb");
if (NULL == infile) 
perror("Couldn't read infile");
exit(EXIT_FAILURE);


width = atoi(argv[2]);
height = atoi(argv[3]);
depth = atoi(argv[4]);

// should be depth/8 at 16-bit depth, but 32-bit depth works better
short buffer[height*width*(depth/16)];
printf("depth: %d", depth);
if (fread(&buffer, 1, height*width*(depth/16), infile) != height*width*(depth/16)) 
 fputs("infile dimensions don't match the size you supplied\n", stderr);

printf("depth: %d", depth);

if ((bmp = bmp_create(width, height, depth)) == NULL) 
printf("Invalid depth value: '%d'. Try 1, 4, 8, 16, 24, or 32.\n", depth);
exit(EXIT_FAILURE);


for (i = 0; i < width; ++i)  // 720
 for (j = 0; j < height; ++j )  // 480
  pixel = buffer[width*j+i];

  red = (unsigned short)((pixel & 0xFF0000) >> 16);  // 8
  green = (unsigned short)((pixel & 0x00FF00) >> 8); // 8
  blue = (unsigned short)(pixel & 0x0000FF);         // 8

  rgb_pixel_t bpixel = blue, green, red, 0;
  bmp_set_pixel(bmp, i, j, bpixel);
  


bmp_save(bmp, outfile);
bmp_destroy(bmp);

return 0;

这个程序的输入 - ./a.out fb0.raw 480 854 24 /data/new.bmp

argv[1]=输入文件

argv[2]=宽度

argv[3]=高度

argv[4]=深度

argv[5]=输出文件

原来这里给出代码how to convert 16-bit RGB Frame Buffer to a viewable format?

现在打开 bmp 文件后,我发现所有东西都是 黑色。为什么会这样?

以及如何显示帧缓冲区?

【问题讨论】:

【参考方案1】:

为了不重新发明***,我尝试重用现有工具:

    获取帧缓冲区:

    adb pull /dev/graphics/fb0 androidFB
    

    找出我们的帧缓冲文件中使用的格式。为此,我使用实用程序 avconv(但您也可以使用 ffmpeg),并与自制脚本相关联:

    #!/bin/bash
    
    #Change FB_RESOLUTION value by the android device's resolution
    FB_RESOLUTION=240x320
    OUTPUT_DIR=fbresult
    
    #format come from: avconv -pix_fmts| cut -f 2 -d " "
    format=(yuv420p yuyv422 rgb24 bgr24 yuv422p yuv444p yuv410p yuv411p gray monow monob pal8 yuvj420p yuvj422p yuvj444p xvmcmc xvmcidct uyvy422 uyyvyy411 bgr8 bgr4 bgr4_byte rgb8 rgb4 rgb4_byte nv12 nv21 argb rgba abgr bgra gray16be gray16le yuv440p yuvj440p yuva420p vdpau_h264 vdpau_mpeg1 vdpau_mpeg2 vdpau_wmv3 vdpau_vc1 rgb48be rgb48le rgb565be rgb565le rgb555be rgb555le bgr565be bgr565le bgr555be bgr555le vaapi_moco vaapi_idct vaapi_vld yuv420p16le yuv420p16be yuv422p16le yuv422p16be yuv444p16le yuv444p16be vdpau_mpeg4 dxva2_vld rgb444le rgb444be bgr444le bgr444be y400a bgr48be bgr48le yuv420p9be yuv420p9le yuv420p10be yuv420p10le yuv422p10be yuv422p10le yuv444p9be yuv444p9le yuv444p10be yuv444p10le yuv422p9be yuv422p9le vda_vld gbrp gbrp9be gbrp9le gbrp10be gbrp10le gbrp16be gbrp16le)
    
    
    mkdir $OUTPUT_DIR
    
    for item in $format[*]
    do
        #Loop through operation   
        avconv -vframes 1 -f rawvideo -pix_fmt $item -s $FB_RESOLUTION -i androidFB $OUTPUT_DIR/$item.png
    done
    

    浏览 OUTPUT_DIR 目录以查找具有正确外观的图像。文件名是要使用的格式:XXXX.png 要使用的格式是 XXXX

    您现在可以使用以下命令转换 PNG 格式的帧缓冲区(不要忘记将分辨率 FB_RESOLUTION 替换为正确的值并格式化 XXXX)

    avconv -vframes 1 -f rawvideo -pix_fmt XXXX -s FB_RESOLUTION -i androidFB androidFB.png
    

【讨论】:

【参考方案2】:

我一直在尝试捕获 Android 2.3.4 手机屏幕图像并且遇到了同样的问题。首先我尝试了一些工具,但我把一切都复杂化了。

Joe 给了我关于填充的线索,所以我只是尝试读取文件中的原始帧缓冲区,然后用 GIMP 加载它(此时我对为此制作软件不感兴趣,也许以后再说)。

在使用 GIMP 原始导入参数时,我发现 240x320 屏幕的填充宽度实际上是 256x320,右侧有透明填充。此外,它不是 RGB,而是“RGB Alpha”原始类型。

由于我正在编写的是手册,因此以下内容与 GIMP 一起足以在旧的 Android 版本上运行:

adb shell "cat /dev/graphics/fb0 > /mnt/sdcard/documents/devimages/$1.data" adb pull /mnt/sdcard/documents/devimages/$1.data 亚行外壳“rm /mnt/sdcard/documents/devimages/$1.data”

我希望这对某人有帮助:-)

【讨论】:

【参考方案3】:

为了获得很多便利和功能,您可以使用适用于 android 的 OpenCV 端口。那么这将是最简单的事情之一。我认为这不是什么大问题,因为您在项目中使用的是 natice 代码。

如果我没记错的话,该函数名为imwrite(),位于 HighGui.hpp 中

您可以在此处找到 OpenCV 的 android 端口:http://opencv.org/downloads.html

相关的“黑度”问题:我在处理 pgm 图像时遇到了这个问题。 PGM 标头必须指定图像的“最大”深度。例如。 255,8位。假设您有 8 位数据,但使用 16 位的最大分辨率,65565 个值。图片将是“黑色”,因为所有值都太低了。我希望你明白我的意思。

【讨论】:

上述输入不是我唯一尝试过的。我尝试了不同的深度、宽度和高度值,但不幸的是最终结果是黑屏。 你能发布一张图片的二进制样本吗?【参考方案4】:
  rgb_pixel_t bpixel = blue, green, red, 0;

可能将 alpha 值设置为 0,而 alpha 是一个透明度值。试试 255 看看你是否得到任何结果。如果你的像素方程错了,你至少应该得到一些东西。

图像的另一个“陷阱”是有时数据不存储为 RGBRGBRGB...,而是像 Microsoft/IBM DIB 中的 BGRBGRBGR。这是一个简单的检查,因为你会得到图像,但就像你在 LSD 上一样。

height*width*(depth/16)

也应该看看。我还建议将它放入一个变量中,以便您更容易维护。

另外,关于 RAW DIB 需要注意的一件事:有时它们每行都有一组填充。在 MS/IBM DIB 中,要求每条扫描线必须以 4 字节增量存储。因此,如果您的输出大量转向一个方向,则可能是这样。在某些情况下,图像是倒置存储的

【讨论】:

我尝试使用 255 而不是 0 但没有用。我得到的是黑色的。

以上是关于如何将原始 RGB 帧缓冲区文件转换为可视格式?的主要内容,如果未能解决你的问题,请参考以下文章

在 Librealsense SDK 中将 OpenCV Mat 转换为 Realsense 的帧类型

如何将 rgb 图像数组从 sws_scale 转换为 DIB(在内存位图中)

截取嵌入式 Linux 帧缓冲区的屏幕截图

如何从 Linux 帧缓冲区获取 RGB 像素值?

如何将从 .arff 文件加载的 arff 对象转换为数据帧格式?

如何使用 GLUT 在按键上的纹理/帧缓冲区之间切换?