我正在尝试使用 c++ python 将图像转换为 CbCrA,但是当从 raspberry pi 和 ubuntu 笔记本电脑运行时,相同的函数会输出两个不同的输出。我知道有些变量在手臂上有不同的大小,但我无法指出是什么搞砸了。
static PyObject *
method_rgb_to_atem(PyObject *self, PyObject *args)
{
Py_buffer input_buffer;
Py_ssize_t data_length;
unsigned int width, height, premultiply;
PyObject *res;
/* Parse arguments */
if (!PyArg_ParseTuple(args, "y*IIp", &input_buffer, &width, &height, &premultiply)) {
return NULL;
}
data_length = input_buffer.len;
unsigned char *buffer;
buffer = input_buffer.buf;
char *outbuffer = (char *) malloc(data_length);
if (outbuffer == NULL) {
return PyErr_NoMemory();
}
char *writepointer = outbuffer;
int pixel_size = 8;
for (int i = 0; i < data_length; i += pixel_size) {
// Convert RGBA 8888 to 10-bit BT.709 Y'CbCrA
float r1 = (float)buffer[0] / 255;
float g1 = (float)buffer[1] / 255;
float b1 = (float)buffer[2] / 255;
float r2 = (float)buffer[4] / 255;
float g2 = (float)buffer[5] / 255;
float b2 = (float)buffer[6] / 255;
if (premultiply) {
// PNG files have straight alpha, for BMD switchers premultipled alpha is easier
float a1 = (float)buffer[3] / 255;
float a2 = (float)buffer[7] / 255;
r1 = r1 * a1;
g1 = g1 * a1;
b1 = b1 * a1;
r2 = r2 * a2;
g2 = g2 * a2;
b2 = b2 * a2;
}
float y1 = (0.2126 * r1) + (0.7152 * g1) + (0.0722 * b1);
float y2 = (0.2126 * r2) + (0.7152 * g2) + (0.0722 * b2);
float cb = (b2 - y2) / 1.8556;
float cr = (r2 - y2) / 1.5748;
unsigned short a10a = ((buffer[3] << 2) * 219 / 255) + (15 << 2) + 1;
unsigned short a10b = ((buffer[7] << 2) * 219 / 255) + (15 << 2) + 1;
unsigned short y10a = clamp((unsigned short)(y1 * 876) + 64, 64, 940);
unsigned short y10b = clamp((unsigned short)(y2 * 876) + 64, 64, 940);
unsigned short cb10 = clamp((unsigned short)(cb * 896) + 512, 44, 960);
unsigned short cr10 = clamp((unsigned short)(cr * 896) + 512, 44, 960);
writepointer[0] = (unsigned char) (a10a >> 4);
writepointer[1] = (unsigned char) (((a10a & 0x0f) << 4) | (cb10 >> 6));
writepointer[2] = (unsigned char) (((cb10 & 0x3f) << 2) | (y10a >> 8));
writepointer[3] = (unsigned char) (y10a & 0xff);
writepointer[4] = (unsigned char) (a10b >> 4);
writepointer[5] = (unsigned char) (((a10b & 0x0f) << 4) | (cr10 >> 6));
writepointer[6] = (unsigned char) (((cr10 & 0x3f) << 2) | (y10b >> 8));
writepointer[7] = (unsigned char) (y10b & 0xff);
writepointer += pixel_size;
buffer += pixel_size;
}
res = Py_BuildValue("y#", outbuffer, data_length);
free(outbuffer);
return res;
}
在 Ubuntu (22.04) 上 对于这个输入
b'\xff\x00\x00\xff\xff\x00\x00\xff'
输出是
b':\x96h\xfa:\x9f\x00\xfa'
或(hexdump)
00000000: 3A 96 68 FA 3A 9F 00 FA :.h.:...
在 Raspberry pi arm32bit 和 64bi (raspberry pi os) 对于相同的输入 我得到输出
b':\x98\x00\xfa:\x9f\x00\xfa'
或(hexdump)
00000000: 3A 98 00 FA 3A 9F 00 FA :...:...
在
float cb = -0.114572;
unsigned short cb10 = std::clamp((unsigned short)(cb * 896) + 512, 44, 960);
std::clamp
的参数被推导为 int
。 cb * 896
转换为 unsigned short
计算为 65434
(而不是 -102
的正确值),添加 512
得到 65946
然后被夹紧到 960
而不是 410 的预期值。我我猜你打算改为这样做:
unsigned short cb10 = std::clamp((unsigned short)(cb * 896 + 512), 44, 960);
然后你会得到一个参数类型不匹配的错误,你要么需要将所有参数转换为
unsigned short
或者只明确指定模板类型:
unsigned short cb10 = std::clamp<unsigned short>(cb * 896 + 512, 44, 960);
我不确定您的代码是如何工作的(而且我无法重现它的工作方式),
std::clamp<unsigned short>((unsigned short)(cb * 896 + 512), 44, 960)
确实有效,因为将 65946
转换为 unsigned short
确实会让您回到 410
但是 std::clamp
应该推断int
在你的代码中。
@AlanBirtles,感谢您指出我能够编写一个使用 float 而不是 short 的自定义钳位函数,这使得转换正确发生。
unsigned short
clamp(float v, unsigned short min, unsigned short max)
{
const short t = v < min ? min : v;
return t > max ? max : t;
}