Плавающая точка CUDA дает разные результаты

Я конвертирую изображение из цветного в оттенки серого, используя CUDA 5/VC 2008.

Ядро CUDA:

__global__ static void rgba_to_grayscale( const uchar4* const rgbaImage, unsigned char * const greyImage,
                                     int numRows, int numCols) 
{
    int pos = blockIdx.x * blockDim.x + threadIdx.x;
    if (pos < numRows * numCols) {
        uchar4 zz = rgbaImage[pos];
        float out = 0.299f * zz.x + 0.587f * zz.y + 0.114f * zz.z;
        greyImage[pos] = (unsigned char) out;
    }

}

Функция С++:

inline unsigned char rgba_to_grayscale( uchar4 rgbaImage) 
{
    return (unsigned char) 0.299f * rgbaImage.x + 0.587f * rgbaImage.y + 0.114f * rgbaImage.z;
}

и они оба называются соответствующим образом. Однако они дают разные результаты.

Исходное изображение:

Это цветное изображение

CUDA-версия:

cuda результат

Серийная версия процессора:

Результат серийного кода

Кто-нибудь может объяснить, почему результаты разные?


person Dave Appleton    schedule 12.05.2013    source источник
comment
Каков коэффициент ускорения для этой функции?   -  person huseyin tugrul buyukisik    schedule 12.05.2013


Ответы (2)


С вашей функцией CUDA проблем нет. Версия процессора неверна. Вы приводите значение 0.299f * rgbaImage.x к unsigned char, что эквивалентно следующему коду:

inline unsigned char rgba_to_grayscale( uchar4 rgbaImage) 
{
    return ((unsigned char) 0.299f * rgbaImage.x) + 0.587f * rgbaImage.y + 0.114f * rgbaImage.z;
}

Вы должны преобразовать окончательный результат в unsigned char следующим образом:

inline unsigned char rgba_to_grayscale( uchar4 rgbaImage) 
{
    return (unsigned char) (0.299f * rgbaImage.x + 0.587f * rgbaImage.y + 0.114f * rgbaImage.z);
}
person sgarizvi    schedule 12.05.2013
comment
Ага - почти там. Но другая вещь, которую я смутно помнил, это то, что порядок RGBA отличается для кода C и CUDA. опубликует ниже. - person Dave Appleton; 13.05.2013

@ sga91 был почти там .... но также кажется, что порядок байтов другой.

inline unsigned char rgba_to_grayscale( uchar4 rgbaImage) 
{
    return (unsigned char) (0.299f * rgbaImage.z + 0.587f * rgbaImage.y + 0.114f * rgbaImage.y);
}

обратите внимание, что x и z переставлены....

Я помню, что читал об этом раньше, но я не могу найти ссылку сейчас...

person Dave Appleton    schedule 13.05.2013
comment
Я не думаю, что порядок байтов должен быть другим. Это зависит от последовательности каналов входного изображения. например, RGBA или BGRA и т. д. - person sgarizvi; 13.05.2013
comment
Похоже, что OpenGL использует BGRA, и я думаю, что этот вид мигрирует на CUDA, но я попытаюсь получить на него абсолютную ссылку. Но я согласен, что это выглядит безумно, потому что я использовал вспомогательные функции загрузки изображений CUDA в обоих случаях. - person Dave Appleton; 15.05.2013