首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在OpenCL中实现快速RGB => YUV转换

在OpenCL中实现快速RGB => YUV转换
EN

Stack Overflow用户
提问于 2011-02-13 01:36:35
回答 3查看 10.3K关注 0票数 5

我知道下面的公式可以用来将RGB图像转换为YUV图像。在下面的公式中,R、G、B、Y、U、V都是8位无符号整数,中间值是16位无符号整数。

代码语言:javascript
复制
Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16  
U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128  
V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128

但当这个公式在OpenCL中使用时,情况就不同了。

代码语言:javascript
复制
 1. 8-bit memory write access is an optional extension, which means some OpenCL implementations may not support it.
 2. even the above extension is supported, it's deadly slow compared with 32-bit write access.

为了获得更好的性能,每4个像素将被同时处理,所以输入是12个8位整数,输出是3个32位无符号整数(第一个代表4个Y样本,第二个代表4个U样本,最后一个代表4个V样本)。

我的问题是如何直接从12个8位整数中获得这3个32位整数?有没有公式来得到这3个32位整数,或者我只需要用旧的公式得到12个8位整数结果(4Y,4U,4V),然后用逐位运算构造这3个32位整数?

EN

回答 3

Stack Overflow用户

发布于 2013-07-31 04:36:22

尽管这个问题是在两年前提出的,但我认为一些工作代码在这里会有所帮助。就直接访问8位值时最初对性能不佳的担忧而言,最好尽可能执行32位直接访问。

不久前,我开发并使用了以下OpenCL内核,将ARGB (典型的windows位图像素布局)转换为y平面(全尺寸),u/v半平面(四分之一大小)内存布局作为libx264编码的输入。

代码语言:javascript
复制
__kernel void ARGB2YUV ( 
                            __global  unsigned int * sourceImage,
                            __global unsigned int * destImage,
            unsigned int srcHeight,
            unsigned int srcWidth,
            unsigned int yuvStride // must be srcWidth/4 since we pack 4 pixels into 1 Y-unit (with 4 y-pixels)
            )
{
    int i,j;
    unsigned int RGBs [ 4 ];
    unsigned int posSrc, RGB, Value4 = 0, Value, yuvStrideHalf, srcHeightHalf, yPlaneOffset, posOffset;
    unsigned char red, green, blue;

    unsigned int posX = get_global_id(0);
    unsigned int posY = get_global_id(1);

    if ( posX < yuvStride ) {
        // Y plane - pack 4 y's within each work item
        if ( posY >= srcHeight )
            return;

        posSrc = (posY * srcWidth) + (posX * 4);

        RGBs [ 0 ] = sourceImage [ posSrc ];
        RGBs [ 1 ] = sourceImage [ posSrc + 1 ];
        RGBs [ 2 ] = sourceImage [ posSrc + 2 ];
        RGBs [ 3 ] = sourceImage [ posSrc + 3 ];

        for ( i=0; i<4; i++ ) {
            RGB = RGBs [ i ];

            blue = RGB & 0xff; green = (RGB >> 8) & 0xff; red = (RGB >> 16) & 0xff;

            Value = ( ( 66 * red + 129 * green + 25 * blue ) >> 8 ) + 16;
            Value4 |= (Value << (i * 8));
        }

        destImage [ (posY * yuvStride) + posX ] = Value4;
        return;
    }

    posX -= yuvStride;
    yuvStrideHalf = yuvStride >> 1;

    // U plane - pack 4 u's within each work item
    if ( posX >= yuvStrideHalf )
        return;

    srcHeightHalf = srcHeight >> 1; 
    if ( posY < srcHeightHalf ) {
        posSrc = ((posY * 2) * srcWidth) + (posX * 8);

        RGBs [ 0 ] = sourceImage [ posSrc ];
        RGBs [ 1 ] = sourceImage [ posSrc + 2 ];
        RGBs [ 2 ] = sourceImage [ posSrc + 4 ];
        RGBs [ 3 ] = sourceImage [ posSrc + 6 ];

        for ( i=0; i<4; i++ ) {
            RGB = RGBs [ i ];

            blue = RGB & 0xff; green = (RGB >> 8) & 0xff; red = (RGB >> 16) & 0xff;
            Value = ( ( -38 * red + -74 * green + 112 * blue ) >> 8 ) + 128;
            Value4 |= (Value << (i * 8));
        }
        yPlaneOffset = yuvStride * srcHeight;
        posOffset = (posY * yuvStrideHalf) + posX;
        destImage [ yPlaneOffset + posOffset ] = Value4;
        return;
    }

    posY -= srcHeightHalf;
    if ( posY >= srcHeightHalf )
        return;

    // V plane - pack 4 v's within each work item
    posSrc = ((posY * 2) * srcWidth) + (posX * 8);

    RGBs [ 0 ] = sourceImage [ posSrc ];
    RGBs [ 1 ] = sourceImage [ posSrc + 2 ];
    RGBs [ 2 ] = sourceImage [ posSrc + 4 ];
    RGBs [ 3 ] = sourceImage [ posSrc + 6 ];

    for ( i=0; i<4; i++ ) {
        RGB = RGBs [ i ];

        blue = RGB & 0xff; green = (RGB >> 8) & 0xff; red = (RGB >> 16) & 0xff;

        Value = ( ( 112 * red + -94 * green + -18 * blue ) >> 8 ) + 128;
        Value4 |= (Value << (i * 8));
    }

    yPlaneOffset = yuvStride * srcHeight;
    posOffset = (posY * yuvStrideHalf) + posX;

    destImage [ yPlaneOffset + (yPlaneOffset >> 2) + posOffset ] = Value4;
    return;
}

此代码仅执行全局32位内存访问,而在每个工作项中进行8位处理。

哦..。以及调用内核的正确代码

代码语言:javascript
复制
unsigned int width = 1024;
unsigned int height = 768;

unsigned int frameSize = width * height;
const unsigned int argbSize = frameSize * 4; // ARGB pixels

const unsigned int yuvSize = frameSize + (frameSize >> 1); // Y,U,V planes

const unsigned int yuvStride = width >> 2; // since we pack 4 RGBs into "one" YYYY

// Allocates ARGB buffer
ocl_rgb_buffer = clCreateBuffer ( context, CL_MEM_READ_WRITE, argbSize, 0, &error );
// ... error handling ...

ocl_yuv_buffer = clCreateBuffer ( context, CL_MEM_READ_WRITE, yuvSize, 0, &error );
// ... error handling ...

error = clSetKernelArg  ( kernel, 0, sizeof(cl_mem), &ocl_rgb_buffer );
error |= clSetKernelArg ( kernel, 1, sizeof(cl_mem), &ocl_yuv_buffer );

error |= clSetKernelArg ( kernel, 2, sizeof(unsigned int), &height);
error |= clSetKernelArg ( kernel, 3, sizeof(unsigned int), &width);

error |= clSetKernelArg ( kernel, 4, sizeof(unsigned int), &yuvStride);
// ... error handling ...

const size_t local_ws[] = { 16, 16 };
const size_t global_ws[] = { yuvStride + (yuvStride >> 1), height };

error = clEnqueueNDRangeKernel ( queue, kernel, 2, NULL, global_ws, local_ws, 0, NULL, NULL );
// ... error handling ...

注意:看一下工作项计算。需要添加一些额外的代码(例如,使用mod来添加足够的备用项),以确保工作项大小适合本地工作大小。

票数 10
EN

Stack Overflow用户

发布于 2011-02-15 06:09:34

是像这样吗?除非您的平台可以使用int3,否则请使用int4。此外,您可以将5个像素放入一个int16中,这样就浪费了1/16而不是1/4的内存带宽。

代码语言:javascript
复制
__kernel void rgb2yuv( __global int3* input, __global int3* output){


rgb = input[get_global_id(0)];
R = rgb.x;
G = rgb.y;
B = rgb.z;    

yuv.x = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16; 
yuv.y = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128; 
yuv.z = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128;

output[get_global_id(0)] = yuv;
}
票数 2
EN

Stack Overflow用户

发布于 2011-02-28 09:01:52

除了opencl specification数据类型之外,int3也不存在。

第123页:

支持的n值为2、4、8和16...

在内核变量中,rgbRGByuv至少应该为__private int4

OpenCL 1.1添加了对typen where n = 3的支持。但是,我强烈建议您不要使用它。不同的供应商实现有不同的bug,并且它不会为您节省任何东西。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4979504

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档