V4L2采集图像并在LCD上显示的图像格式问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了V4L2采集图像并在LCD上显示的图像格式问题相关的知识,希望对你有一定的参考价值。

我使用Linux内核的开发板,用V4L2编写的图像采集程序,图像格式是mjpeg。但是我的LCD是16位的RGB,要把图像显示在LCD上,需要进行格式转换。貌似是需要先转换为RGB24,再转换为RGB16;谁做过类似的转换的,麻烦帮帮忙,给点代码。谢谢了
都是什么回答哦!!

参考技术A 摄像头采集的视频数据是JPEG格式,需要通过libjpeg库进行解压,解压后得到的事RGB 24位的,在转换成RGB16位即可。 具体转换是将RGB24位的前8位右移3位,中间8位右移2位,最后8位右移3位,就得到RGB16位数据了。。。具体代码:
unsigned short RGB888toRGB565(unsigned char red, unsigned char green, unsigned char blue)

unsigned short B = (blue >> 3) & 0x001F;
unsigned short G = ((green >> 2) << 5) & 0x07E0;
unsigned short R = ((red >> 3) << 11) & 0xF800;
return (unsigned short) (R | G | B);
参考技术B 图3图像采集卡在采集数据时的工作时序
其中,VSYNV为场同步输出脉冲,HREF为也用于SRAM和FLASH的片选和读写控制,同时还负责LCD的显示控制。
2
软件设计

如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?

【中文标题】如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?【英文标题】:How to draw image in Linux at same time on LCD and HDMI on Raspberry Pi with QT? 【发布时间】:2016-06-21 12:54:06 【问题描述】:

有谁知道如何在 Linux、Raspberry Pi、Qt 中同时使用双帧缓冲区绘制图像。 我的意思是我想在 LCD 显示器上运行我的应用程序并同时将图像绘制到 HDMI时间。

【问题讨论】:

我认为这种事情的首选格式是提出问题,然后自己回答。您可能需要多解释一下,以便将来的读者清楚。 这不是问题!请将所有答案放入答案中,然后将问题编辑为问题。回答你自己的问题完全没问题! 为什么要添加额外的代码,而不是仅仅在其环境中使用QT_QPA_PLATFORM=linuxfbQT_QPA_GENERIC_PLUGINS=evdevtouch,evdevmouse,evdevkeyboardQT_QPA_EVDEV_KEYBOARD_PARAMETERS=grab=1 运行您的程序 - 这不是使用跨平台库的全部意义,例如Qt? 因为您不能在 QT 中同时使用双帧缓冲区。尝试使用 /dev/fb1 执行您的程序并将图像设置为 /dev/fb0 - 这就是该代码存在的原因。玩得开心 【参考方案1】:

我写了这段代码,但是在网上看到很多关于如何在Linux fraimbuffer上显示图像的问题。我会把它留在这里,也许有人需要帮助。该代码在 Raspberry Pi 2 型号 B、B+ 和 Linux Kernel 4.4.y 上进行了测试。使用 Qt 5.6

文件:fbdi.pro

QT += core
QT += gui
QT += widgets
CONFIG += c++11
TARGET = fbdi
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += fbdi.cpp

文件:fbdi.cpp

#include <QDebug>
#include <QImage>
#include <QRgb>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <unistd.h>

#define FB_ERROR_OPEN_FBD 0x0001  // Could not open the framebuffer device
#define FB_ERROR_READ_FSI 0x0002  // Read fixed display information failed
#define FB_ERROR_READ_VSI 0x0004  // Read variable display information failed
#define FB_ERROR_MAPS_MEM 0x0008  // Mapping memory failed
#define FB_ERROR_LOAD_IMG 0x0016  // Load image file failed
#define FB_ERROR_TRAN_IMG 0x0032  // Transformation image file

struct fb_fix_screeninfo;
struct fb_var_screeninfo;

typedef fb_fix_screeninfo finfo;
typedef fb_var_screeninfo vinfo;

struct linuxfb_t 
    int     device;     // file handler
    uint8_t *data;      // data ptr
    finfo   fix_info;   // fixed display information
    vinfo   var_info;   // variable display information
    int     err_code;   // error code
    char    *err_mesg;  // error mesage
    long    screensize; // calculated screen size
;

///
/// \brief  fb_error     Set error code and message
/// \param  fb           Pointer to struct linuxfb_t
/// \param  code         Error number
/// \param  message      Error message
/// \return bool         Always false
///
bool fb_error(linuxfb_t *fb, int code, QString message)

    fb->err_code = code;
    fb->err_mesg = message.toLocal8Bit().data();
    return false;


///
/// \brief fb_fatal     Output message if an error accurred
/// \param fb           Pointer to struct linuxfb_t
/// \return int         Error code
///
int fb_fatal(linuxfb_t *fb)

    qDebug("Error %d: %s", fb->err_code, fb->err_mesg);
    return fb->err_code;



///
/// \brief fb_draw      Draw specified image on linux framebuffer
/// \param fb           Pointer to struct linuxfb_t
/// \param device       Path to linux framebuffer device (eg. /dev/fb0)
/// \param filename     Path to image file which support by Qt
/// \return bool        True if the function success, overwise false
///
bool fb_draw(linuxfb_t *fb, const char *device, const char *filename)

    fb->device = open(device, O_RDWR);

    if( fb->device < 0 ) 
        return fb_error(fb, FB_ERROR_OPEN_FBD, QString("Unable to open specified device"));
    

    if( ioctl(fb->device, FBIOGET_VSCREENINFO, &fb->var_info) ) 
        return fb_error(fb, FB_ERROR_READ_VSI, QString("Unable to read variable screen information"));
    

    if( ioctl(fb->device, FBIOGET_FSCREENINFO, &fb->fix_info) ) 
        return fb_error(fb, FB_ERROR_READ_FSI, QString("Unable to get fixed screen information"));
    

    fb->screensize = fb->var_info.xres * fb->var_info.yres * (fb->var_info.bits_per_pixel/8);
    fb->data = (uint8_t *) mmap(0, fb->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb->device, (off_t) 0);

    if( (intptr_t) fb->data == -1 ) 
        return fb_error(fb, FB_ERROR_MAPS_MEM, QString("Failed to map framebuffer device to memory"));
    

    QImage img_orig;
    if( !img_orig.load(filename) ) 
        munmap(fb->data, fb->screensize);
        close(fb->device);
        return fb_error(fb, FB_ERROR_LOAD_IMG, "Could not open the file you specified");
    

    QImage img_trans;
    img_trans = img_orig.scaled(fb->var_info.xres, fb->var_info.yres);
    if( img_trans.isNull() ) 
        munmap(fb->data, fb->screensize);
        close(fb->device);
        return fb_error(fb, FB_ERROR_TRAN_IMG, "Could not transform image");
    

    for( uint32_t x=0; x < fb->var_info.xres; x++ ) 
        for( uint32_t y=0; y < fb->var_info.yres; y++ ) 
            long location = (x+fb->var_info.xoffset) * (fb->var_info.bits_per_pixel/8) +
                            (y+fb->var_info.yoffset) * fb->fix_info.line_length;

            QRgb color = img_trans.pixel(x,y);
            uint32_t pixel = (qRed(color)<<fb->var_info.red.offset)     |
                             (qGreen(color)<<fb->var_info.green.offset) |
                             (qBlue(color)<<fb->var_info.blue.offset)   ;

            *((uint32_t*)(fb->data+location)) = pixel;
        
    

    munmap(fb->data, fb->screensize);
    close(fb->device);

    return true;


///
/// \brief  main Application entry point
/// \return result
///
int main()

    // Create linuxfb variable
    linuxfb_t fb;

    // Output some image
    if( !fb_draw(&fb, "/dev/fb0", "/tmp/test.png") ) 

        // Failed
        return fb_fatal(&fb);
    

    // success
    return 0;

【讨论】:

以上是关于V4L2采集图像并在LCD上显示的图像格式问题的主要内容,如果未能解决你的问题,请参考以下文章

如何将摄像头采集的YUV图像数据保存成图片

在LCD显示摄像头图像

Linux应用开发第七章摄像头V4L2编程应用开发

使用 v4l2 捕获相机图像非常慢

实战小项目之嵌入式linux图像采集与传输

控制相机采集图像并做处理