Subtraction/difference 在 Java 中的字节之间

Subtraction/difference between bytes in Java

我试图从另一个字节中减去一个字节,同时确保不会发生溢出,但得到了意想不到的结果。

我的情况是我有一个字节的黑白图像,我想从中减去背景。因此我需要处理字节并防止发生溢出。当从另一个图像中减去背景图像时,我可能对字节的符号有一些困难。 data2为背景数组,data1为另一张图片

在下面的代码中,我希望从 data1 数组中减去 data2 数组。但是,当我确定应该有高值时,我会得到低值。

    for (int i = 0; i < data1.length; i++) {
        if (data1[i] > data2[i]) {
            dest[i] = (byte) (data1[i] - data2[i]);
        } else {
            dest[i] = 0;
        }
    }

我想我应该确保 data2 字节不是负数并被添加到 data1。 所以我来到:

    for (int i = 0; i < data1.length; i++) {
        if (data1[i] > data2[i]) {

            dest[i] = (byte) ((int)data1[i] & 0xff - (int)data2[i] & 0xff - 128);

        } else {
            dest[i] = 0;
        }
    }

然而,这也没有给出正确的结果。

我目前对此的看法是:

(byte) ((int)data1[i] & 0xff - (int)data2[i] & 0xff - 128);

(int) cast: make sure bytes are cast to integer.
&0xff: make value unsigned.
- subtraction smaller value from bigger value.
- 128: subtract 128 to make signed again.
(byte): cast back to byte.

我希望我在这里做错了一些愚蠢的事情,或者我的问题出在其他地方,我无法弄清楚在哪里。

编辑

我似乎已经弄清楚了问题的一部分: 当字节被签名时,data1[i] > data2[i] 处理错误(在我的例子中)。相反:

        if ((data1[i] & 0xff) > (data2[i] & 0xff)) {

似乎产生了正确的结果,而不是之前的比较。

这里的重点是您的字节来自 API,它使用 8 位来编码像素的光线,因此它们的范围是 0; 0xFF。但是 Java 字节是 -128; 127,因此 0x7F 之后的任何位模式都将被解释为负数。例如,如果字节是无符号的,0xF0 中的位是 128,如果解释为带符号的字节,则 -16

System.out.println(0xFF > 0);  // true
System.out.println((byte) 0xFF > 0); // false

因此,在比较无符号字节时,您希望将像素提升为 intByte.toUnsignedInt(byteVal)(或 ((int) byteVal) & 0xFF on Java 7)。

永远记住 Java 字节是有符号的。如果 data1[i]127,并且 data2[i]-128,那么 data1[i] > data2[i],但是 data1[i] - data2[i] 不适合有符号的 byte ;结果是 255.

如果您字节视为无符号,那很好。这或多或少意味着在使用 & 0xFF 等之后将它们打印出来。那会很好用;它会给出正确的结果如果你正确地将它们视为未签名。

为确保您只从更大的字节中减去非负字节,您应该使用:

for (int i = 0; i < data1.length; i++) {
    if (data1[i] > data2[i] && data2[i]>=0 ) {
        dest[i] = (byte) (data1[i] - data2[i]);
    } else {
        dest[i] = 0;
    }
}

您的第二个代码不起作用,因为 & 运算符将值提升为 int 类型。
考虑 data1=127 (0x7F) 和 data2=-128 (0x80) 的情况。
data1 & 0xff 是 int 类型,值为 127 (0x0000007F)
data2 & 0xff 是 int 类型,值为 128 (0x00000080)
data1[i] & 0xff - data2[i] & 0xff 是 int 类型,值为 -1 (0xFFFFFFFF)
(byte)(data1[i] & 0xff - data2[i] & 0xff) 是字节类型,值为 -1 (0xFF)
所以你仍然有溢出

出于某种原因,比较字节的处理方式很奇怪。如果我在比较中将字节转换为无符号整数,则比较工作正常并且我的结果符合我的预期。

然后我可以减去字节,就像 Louis Wasserman 指出的那样,就好像它们是无符号的,这对我来说是新的。

    for (int i = 0; i < data1.length; i++) {
        if ((data1[i] & 0xff) > (data2[i] & 0xff)) {
            dest[i] = (byte)(data1[i] - data2[i]);
        } else {
            dest[i] = 0;
        }
    }