将 YUV422 转换为 RGB24

发布于 2024-11-28 12:38:11 字数 5700 浏览 1 评论 0原文

我尝试编写一个YUV422到RGB24转换器,但是转换后数据的结果似乎很奇怪。 结果是带有一些浅绿色点的紫罗兰色灰度图片...... 有人有想法吗?

inline void convert_yuv442_2_rgb24(const unsigned char* source, unsigned char* destination, unsigned long width, unsigned long height)
{
    unsigned char data[3];
    for(unsigned long i = 0, c = 0; i < width * height * 2; i += 2, c += 3)
    {
        // 16Bit YUV422 -> 24Bit YUV
        data[0] =  source[i+0];
        data[1] = (source[i+1] & 0xF0) >> 4;
        data[2] = (source[i+1] & 0X0F);

// YUV-> RGB24
//destination[c + 0] = (float) (1.164f*(data[0] - 16) + 1.596f*(data[2] - 128));
//destination[c + 1] = (float) (1.164f*(data[0] - 16) - 0.813f*(data[2] - 128) - 0.391f*(data[1] - 128));
//destination[c + 2] = (float) (1.164f*(data[0] - 16)                          + 2.018f*(data[1] - 128));

        destination[c + 0] = (float) data[0] + (float) data[2] / 0.877F;
        destination[c + 2] = (float) data[0] + (float) data[1] / 0.493f;
        destination[c + 1] = (float) 1.7f * (float) data[0] - 0.509f * destination[c + 0] - 0.194f*(float)destination[c + 2];

    }
}

我按照给定的提示尝试了另一个人,但没有成功。 转换器代码来自这里: http://paulbourke.net/dataformats/yuv/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <libv4l1.h>
#include <libv4l2.h>
#include <linux/videodev.h>

int init_webcam( int *fd, struct video_window *web_win, long *length);

struct RGB
{
    unsigned char r, g, b;
};

RGB convert(int y, int u, int v)
{
    RGB rgb;
    u -= 128;
    v -= 128;

    rgb.r = y + 1.370705 * v;
    rgb.g = y - 0.698001 * v - 0.337633 * u;
    rgb.b = y + 1.732446 * u;


    if (rgb.r < 0) rgb.r = 0;
    if (rgb.g < 0) rgb.g = 0;
    if (rgb.b < 0) rgb.b = 0;
    if (rgb.r > 255) rgb.r = 255;
    if (rgb.g > 255) rgb.g = 255;
    if (rgb.b > 255) rgb.b = 255;

    return rgb;
}

void YUV422_2_RGB24(unsigned char* yuv, RGB* p1, RGB* p2)
{
//    int u = yuv[0];
//    int y1 = yuv[1];
//    int v = yuv[2];
//    int y2 = yuv[3];

    int y1 = yuv[0];
    int u = yuv[1];
    int y2 = yuv[2];
    int v = yuv[3];

    *p1 = convert(y1, u, v);
    *p2 = convert(y2, u, v);
}


int main()
{
    struct video_window web_win;
    int fd;
    long length;

    if( !init_webcam( &fd, &web_win, &length))
        return 1;


    // Bild aufnehmen
    unsigned char* picture = new unsigned char[web_win.width * web_win.height * 2];
    unsigned char* image = new unsigned char[web_win.width * web_win.height * 3];

    if( v4l1_read(fd, picture, web_win.width * web_win.height * 2) == -1)
    {
        printf( "Error while reading webcam\n");
        return 0;
    }

    // Bild speichern
    FILE *imagefile;

    if((imagefile = fopen( "bild.ppm", "w+b")) == NULL)
    {
            printf("Couldn't open file for writing\n");
            return 0;
    }

    RGB p1, p2;
    for(unsigned long i = 0, c = 0; i < web_win.width * web_win.height * 2;  i += 4, c += 6)
    {
        YUV422_2_RGB24(&picture[i], &p1, &p2);
        image[c + 0] = p1.r;
        image[c + 1] = p1.g;
        image[c + 2] = p1.b;

        image[c + 3] = p2.r;
        image[c + 4] = p2.g;
        image[c + 5] = p2.b;
    }

    fprintf( imagefile, "P6\n%d %d\n255\n", web_win.width, web_win.height);

    for(unsigned long i = 0; i < web_win.width * web_win.height; ++ i)
    {
            fwrite((unsigned char*) &image[i * 3], 1, 3, imagefile);  
    }

    fclose(imagefile); 

    delete[] picture;
    delete[] image;



    v4l1_close( fd);
    return 0;
}

int init_webcam( int *fd, struct video_window *web_win, long *length)
{
    struct video_capability web_cap;
    struct video_picture web_pict;

    if((*fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)/*Open webcam device*/
    {
        printf( "Unable to open webcam devide\n");
        return 0;
    }

    if( v4l1_ioctl( *fd, VIDIOCGPICT, &web_pict) == -1)/*This function call isn't necessary but otherwise you won't get a proper picture*/
    {
        printf( "Unable to get picture information\n");
        return 0;
    }

    if (ioctl (*fd, VIDIOCGPICT, &web_pict) != -1)
    {       // successfully retrieved the default image properties

            // the following values are for requesting 8bit grayscale
            //web_pict.depth = 16;
            web_pict.palette = VIDEO_PALETTE_YUV422;
            if (ioctl (*fd, VIDIOCSPICT, &web_pict) == -1)
            {
                printf("failed to set the image properties\n");
                //return 0;
            }
    }

    if( ioctl( *fd, VIDIOCGCAP, &web_cap) == -1)/*Get video capabilities*/
    {
        printf( "Unable to get capabilities\n");
        return 0;
    }

    if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Get video information*/
    {
        printf( "Unable to get video information\n");
        return 0;
    }
    web_win->width = web_cap.maxwidth;/*Try to write max solution*/
    web_win->height = web_cap.maxheight;
    if( v4l1_ioctl( *fd, VIDIOCSWIN, web_win) == -1)/*Write new(?!) video information*/
    {
        printf( "Unable to write video information\n");
        return -1;
    }
    if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Read new(?!) video information*/
    {
        printf( "Unable to get video information\n");
        return 0;
    }

    *length = web_win->width * web_win->height * (web_pict.depth/8);

    printf("bits per pixel: %d\n", web_pict.depth);
    printf("palette:        %d\n", web_pict.palette);

    return 1;
}

I tried to write an YUV422 to RGB24 converter, but the result of the converted data seems to be strange.
The result is a violet touched greyscale Picture with some light green dots...
Does anyone has an idea?

inline void convert_yuv442_2_rgb24(const unsigned char* source, unsigned char* destination, unsigned long width, unsigned long height)
{
    unsigned char data[3];
    for(unsigned long i = 0, c = 0; i < width * height * 2; i += 2, c += 3)
    {
        // 16Bit YUV422 -> 24Bit YUV
        data[0] =  source[i+0];
        data[1] = (source[i+1] & 0xF0) >> 4;
        data[2] = (source[i+1] & 0X0F);

// YUV-> RGB24
//destination[c + 0] = (float) (1.164f*(data[0] - 16) + 1.596f*(data[2] - 128));
//destination[c + 1] = (float) (1.164f*(data[0] - 16) - 0.813f*(data[2] - 128) - 0.391f*(data[1] - 128));
//destination[c + 2] = (float) (1.164f*(data[0] - 16)                          + 2.018f*(data[1] - 128));

        destination[c + 0] = (float) data[0] + (float) data[2] / 0.877F;
        destination[c + 2] = (float) data[0] + (float) data[1] / 0.493f;
        destination[c + 1] = (float) 1.7f * (float) data[0] - 0.509f * destination[c + 0] - 0.194f*(float)destination[c + 2];

    }
}

I tried successless anotherone with the given hints.
The converter code comes from here: http://paulbourke.net/dataformats/yuv/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <libv4l1.h>
#include <libv4l2.h>
#include <linux/videodev.h>

int init_webcam( int *fd, struct video_window *web_win, long *length);

struct RGB
{
    unsigned char r, g, b;
};

RGB convert(int y, int u, int v)
{
    RGB rgb;
    u -= 128;
    v -= 128;

    rgb.r = y + 1.370705 * v;
    rgb.g = y - 0.698001 * v - 0.337633 * u;
    rgb.b = y + 1.732446 * u;


    if (rgb.r < 0) rgb.r = 0;
    if (rgb.g < 0) rgb.g = 0;
    if (rgb.b < 0) rgb.b = 0;
    if (rgb.r > 255) rgb.r = 255;
    if (rgb.g > 255) rgb.g = 255;
    if (rgb.b > 255) rgb.b = 255;

    return rgb;
}

void YUV422_2_RGB24(unsigned char* yuv, RGB* p1, RGB* p2)
{
//    int u = yuv[0];
//    int y1 = yuv[1];
//    int v = yuv[2];
//    int y2 = yuv[3];

    int y1 = yuv[0];
    int u = yuv[1];
    int y2 = yuv[2];
    int v = yuv[3];

    *p1 = convert(y1, u, v);
    *p2 = convert(y2, u, v);
}


int main()
{
    struct video_window web_win;
    int fd;
    long length;

    if( !init_webcam( &fd, &web_win, &length))
        return 1;


    // Bild aufnehmen
    unsigned char* picture = new unsigned char[web_win.width * web_win.height * 2];
    unsigned char* image = new unsigned char[web_win.width * web_win.height * 3];

    if( v4l1_read(fd, picture, web_win.width * web_win.height * 2) == -1)
    {
        printf( "Error while reading webcam\n");
        return 0;
    }

    // Bild speichern
    FILE *imagefile;

    if((imagefile = fopen( "bild.ppm", "w+b")) == NULL)
    {
            printf("Couldn't open file for writing\n");
            return 0;
    }

    RGB p1, p2;
    for(unsigned long i = 0, c = 0; i < web_win.width * web_win.height * 2;  i += 4, c += 6)
    {
        YUV422_2_RGB24(&picture[i], &p1, &p2);
        image[c + 0] = p1.r;
        image[c + 1] = p1.g;
        image[c + 2] = p1.b;

        image[c + 3] = p2.r;
        image[c + 4] = p2.g;
        image[c + 5] = p2.b;
    }

    fprintf( imagefile, "P6\n%d %d\n255\n", web_win.width, web_win.height);

    for(unsigned long i = 0; i < web_win.width * web_win.height; ++ i)
    {
            fwrite((unsigned char*) &image[i * 3], 1, 3, imagefile);  
    }

    fclose(imagefile); 

    delete[] picture;
    delete[] image;



    v4l1_close( fd);
    return 0;
}

int init_webcam( int *fd, struct video_window *web_win, long *length)
{
    struct video_capability web_cap;
    struct video_picture web_pict;

    if((*fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)/*Open webcam device*/
    {
        printf( "Unable to open webcam devide\n");
        return 0;
    }

    if( v4l1_ioctl( *fd, VIDIOCGPICT, &web_pict) == -1)/*This function call isn't necessary but otherwise you won't get a proper picture*/
    {
        printf( "Unable to get picture information\n");
        return 0;
    }

    if (ioctl (*fd, VIDIOCGPICT, &web_pict) != -1)
    {       // successfully retrieved the default image properties

            // the following values are for requesting 8bit grayscale
            //web_pict.depth = 16;
            web_pict.palette = VIDEO_PALETTE_YUV422;
            if (ioctl (*fd, VIDIOCSPICT, &web_pict) == -1)
            {
                printf("failed to set the image properties\n");
                //return 0;
            }
    }

    if( ioctl( *fd, VIDIOCGCAP, &web_cap) == -1)/*Get video capabilities*/
    {
        printf( "Unable to get capabilities\n");
        return 0;
    }

    if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Get video information*/
    {
        printf( "Unable to get video information\n");
        return 0;
    }
    web_win->width = web_cap.maxwidth;/*Try to write max solution*/
    web_win->height = web_cap.maxheight;
    if( v4l1_ioctl( *fd, VIDIOCSWIN, web_win) == -1)/*Write new(?!) video information*/
    {
        printf( "Unable to write video information\n");
        return -1;
    }
    if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Read new(?!) video information*/
    {
        printf( "Unable to get video information\n");
        return 0;
    }

    *length = web_win->width * web_win->height * (web_pict.depth/8);

    printf("bits per pixel: %d\n", web_pict.depth);
    printf("palette:        %d\n", web_pict.palette);

    return 1;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

音盲 2024-12-05 12:38:11

YUV 422 将 2 个像素编码为 4 个字节。您的代码正在将 3 个字节解码为 1 个像素,因此完全关闭。请参阅维基百科的描述: http://en.wikipedia.org/wiki/YUV#Y .27UV422

YUV 422 encodes 2 pixels into 4 bytes. Your code is decoding 3 bytes into 1 pixel, so it's completely off. See the description at Wikipedia: http://en.wikipedia.org/wiki/YUV#Y.27UV422

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文