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
因此,在比较无符号字节时,您希望将像素提升为 int
与 Byte.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;
}
}
我试图从另一个字节中减去一个字节,同时确保不会发生溢出,但得到了意想不到的结果。
我的情况是我有一个字节的黑白图像,我想从中减去背景。因此我需要处理字节并防止发生溢出。当从另一个图像中减去背景图像时,我可能对字节的符号有一些困难。 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
因此,在比较无符号字节时,您希望将像素提升为 int
与 Byte.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;
}
}