无符号字符型的负数

3

我正在从头开始实现二维相关代码,我拥有一个类型为 unsigned char 的简单 3x3 图像矩阵:

 unsigned char Image = [184   0   35
                        48   107  193
                        29   166  32]

我的相关核心
             Kernel = [-1 0 1]  

现在,当我进行相关性计算时,第一行的结果在数学上为-149,但打印出来的结果是107(二进制补码)。
unsigned char res = -1.F *(Kernel[i-1]) + (Kernel[i+1]); 

这是一个错误吗?我如何将结果保存为-149但仍保持类型为unsigned char? 我知道我的问题可能不太恰当,因为unsigned char的范围是0到255,但我想确保我没有错过什么。 我也知道负数被转换为二进制补码。
顺便说一下,这不是任何作业,我只是从图像处理角度研究C / C++。

1
-149 无法用 char 表示。char 的范围限制为 -128..+127。请使用 int 替代 unsigned char - Jabberwocky
我不理解你的问题。如果您需要一个负值,那么显然不能将其存储在无符号类型中。而应该使用有符号类型(例如 int,因为 char 大小也不够)。 - interjay
1
@MichaelWalz:这并不一定是正确的。char 可以有更大的范围。另一方面,它可以是无符号的,因此根本没有负值。 - too honest for this site
1
也许你最好提供一个 [mcve]。 - too honest for this site
2
在进行图像处理时,通常希望使用更高范围(和精度)的类型执行算术运算,然后饱和结果。您可能还想查找饱和算术。 - MikeMB
显示剩余13条评论
3个回答

3
如何将结果保存为-149,但类型仍为unsigned char?
不要这样做。使用有符号整数类型。
如果增加的内存使用不是问题,请使用int。 否则,请使用short。

内存效率也是我的关注点。也许我应该将结果图像类型更改为“short int”。 - Tanya
@Tanya,我强烈建议这样做。 - R Sahu
@R Sahu 好的。但是在大多数教程中,图像被表示为“unsigned char”。所以我正在尝试按照那种方式编码。 - Tanya
@Tanya,这很有道理。也许在计算逻辑中缺少某些内容。图像矩阵元素的值何时会为负数?在图像中对应什么? - R Sahu
@ R Sahu 图像矩阵中的元素何时为负? 在我的问题中已经解释了。它与相关的结果相对应,对应于图像中的像素/强度值,我正在尝试将其保存为“unsigned char”。我认为,如果我想保存为“unsigned char”,我应该将负值舍入为零。我不确定标准编码是否这样做,因此我提出了这个问题。 - Tanya
@Tanya,在现实世界中,像素强度不能为负数。因此,我对你的计算逻辑提出了疑问。如果计算结果可以为负数,在现实世界中代表什么意义? - R Sahu

1
当在范围[0 max]的图像上计算梯度[-X 0 X]时,结果会落在范围[-Xmax, Xmax]内。根据您的需求和限制,有不同的处理方法:
  1. 如果您没有内存问题,可以增加编码(byte -> short,short -> int)。
  2. 如果您只关心梯度强度而不是其符号,则首先应用绝对值以获得新的结果范围[0,X*max],然后再应用第三个解决方案。
  3. 您可以拉伸结果以适应所需范围,这意味着您需要应用直方图拉伸(线性函数):[-Xmax, Xmax] -> [0 max]。不幸的是,这种解决方案会损失很多精度。对于您的示例,此解决方案会损失一半的精度(从[-255,255]到[0,255]),除非您先应用第二点。

0
现在,当我执行相关性时,第一行的结果在数学上是-149,但打印出来的结果是107(二进制补码)。这不是一个错误吗?
unsigned char res = -1.F *(Kernel[i-1]) + (Kernel[i+1]); 

在无符号变量(如res)中保存负值不会改变res的类型。它永远是unsigned char。负值通过重复加/(或减去)UCHAR_MAX + 1(256)进行转换,直到它在unsigned char范围内或在此情况下为107
要保存负值并使负值保留在res中,请使用满足范围要求的有符号类型:
Type          Range of Type 
signed char   at least [-127 to 127]      Varies by platform
signed short  at least [-32767 to 32767]  Varies by platform
int8_t        exactly  [-128 to 127]
int16_t       exactly  [-32768 to 32767]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接