我有一个RGB颜色空间LUT(33x33x33x3),我在三线性插值后将其转换为YUV(或UYV,以简化使用)(所以我基本上有一个256x256x256x3 LUT)。然后我在 UYVY 中有一个视频流,我从中一一获取帧并使用 LUT 进行颜色校正。问题是我得到了奇怪的颜色。
我的 LUT 文件的值是浮点数。
我的RGB LUT转UYV LUT功能:
// input is a 256x256x256x3 RGB interpolated LUT containing values from 0-255
__global__ void cudargblut2yuv(uint8_t *input, uint8_t *output) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int idy = blockIdx.y * blockDim.y + threadIdx.y;
int idz = blockIdx.z * blockDim.z + threadIdx.z;
if (idx < 256 && idy < 256 && idz < 256) {
int index = idx * 256 * 256 * 3 + idy * 256 * 3 + idz * 3;
float red = input[index];
float green = input[index + 1];
float blue = input[index + 2];
float y = 16 + 0.256 * red + 0.504 * green + 0.0979 * blue;
float u = 128 + 0.439 * red - 0.368 * green - 0.0714 * blue;
float v = 128 - 0.148 * red - 0.291 * green + 0.439 * blue;
// clamping 0-255
if(y > 255) y = 255;
else if(y < 0) y = 0;
if(u < 0) u = 0;
else if(u > 255) u = 255;
if(v < 0) v = 0;
else if(v > 255) v = 255;
output[index] = u;
output[index + 1] = y;
output[index + 2] = v;
}
}
我的函数将 LUT 应用于像素:
__global__
void applyLUTKernel(const uint8_t* input, uint8_t* output, int frameSize, const uint8_t* lut) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
frameSize >>= 1;
for(int i = index; i < frameSize; i += stride) {
// UYV values from UYVY frame
uint8_t U = input[(i << 2)];
uint8_t Y1 = input[(i << 2) + 1];
uint8_t V = input[(i << 2) + 2];
uint8_t Y2 = input[(i << 2) + 3];
uint8_t pixel1U = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V];
uint8_t pixel1Y = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V + 1];
uint8_t pixel1V = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V + 2];
uint8_t pixel2U = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V];
uint8_t pixel2Y = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V + 1];
uint8_t pixel2V = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V + 2];
// getting corresponding LUT[U1][Y1][V1] values to put back into the frame
output[(i << 2)] = (pixel1U + pixel2U) >> 1;
output[(i << 2) + 1] = pixel1Y;
output[(i << 2) + 2] = (pixel1V + pixel2V) >> 1;
output[(i << 2) + 3] = pixel2Y;
// normal frame
// output[(i << 2)] = U;
// output[(i << 2) + 1] = Y1;
// output[(i << 2) + 2] = V;
// output[(i << 2) + 3] = Y2;
}
}
有人可以纠正我可能错的地方吗?
我怀疑我可能错误地将 LUT 转换为 UYV,或者我错误地将结果 LUT 值替换回帧。我觉得我的插值是准确的,因为在我将 UYVY LUT 转换为 RGB 然后应用 LUT 之前,它按照我的预期完美工作。
我取 U1 和 U2 值的平均值,因为从逻辑上讲,相邻像素的值不应有巨大差异,因此取平均值是有意义的。
我的镜框是什么样的:
您遇到的一个问题是您使用无符号字节类型对可能溢出的像素值进行算术运算。在加法过程中,当您将值放回输出流时,总和的中间结果将以 256 为模进行计算!对代码进行以下细微更改应该可以改善情况并防止由于溢出而丢失重要数据。
int32_t pixel1U = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V];
uint8_t pixel1Y = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V + 1];
int32_t pixel1V = lut[256 * 256 * 3 * U + 256 * 3 * Y1 + 3 * V + 2];
int32_t pixel2U = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V];
uint8_t pixel2Y = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V + 1];
int32_t pixel2V = lut[256 * 256 * 3 * U + 256 * 3 * Y2 + 3 * V + 2];
// getting corresponding LUT[U1][Y1][V1] values to put back into the frame
output[(i << 2)] = (pixel1U + pixel2U) >> 1;
output[(i << 2) + 1] = pixel1Y;
output[(i << 2) + 2] = (pixel1V + pixel2V) >> 1;
output[(i << 2) + 3] = pixel2Y;
请注意,如果贡献值 1U + 2U、1V + 2V 之和超过 256,U 和 V 分量将被损坏(这种情况似乎主要发生在绿色草地上)。
如果将算术循环内的工作变量提升为 32 位整数,您可能会发现代码运行得更快。如果您计算一次索引,代码会更清晰。
同样的风格观察也适用于使用“i<<2" as an index throughout - you might as well multiply both the stride and framesize by 4.