c++ 函数在 arm 设备和 x64 机器上运行时输出不同

问题描述 投票:0回答:2

我正在尝试使用 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                           :...:...
c++ raspberry-pi arm byte sizeof
2个回答
2
投票

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
在你的代码中。


0
投票

@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;
}
© www.soinside.com 2019 - 2024. All rights reserved.