我正在开发一个名为 filter 的 cs50 程序(不太舒服,第 4 周),它必须将图像从正常图像转换为棕褐色图像。除非必须将颜色转换为白色,否则它工作正常。当尝试传输白色时,它只是将其转换为蓝色和绿色。就像这样:
原版
棕褐色
正如您所看到的,除了白色或接近白色的颜色之外,它可以很好地转换所有内容。 这是我的代码(仅限棕褐色部分):
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int j = 0; j < width; j++)
{
for (int i = 0; i < height; i++)
{
int sepiared = image[i][j].rgbtRed *.393 + image[i][j].rgbtGreen *.769 + image[i][j].rgbtBlue *.189;
int sepiagreen = image[i][j].rgbtRed *.349 + image[i][j].rgbtGreen *.686 + image[i][j].rgbtBlue *.168;
int sepiablue = image[i][j].rgbtRed *.272 + image[i][j].rgbtGreen *.534 + image[i][j].rgbtBlue *.131;
image[i][j].rgbtRed = sepiared;
image[i][j].rgbtGreen = sepiagreen;
image[i][j].rgbtBlue = sepiablue;
}
}
return;
}
请帮助我理解为什么会发生这种情况。 Clang 不打印任何错误消息。
您真诚的, 迷失在代码中:)
最佳答案
首先,顺便说一句,当您有 CS50 问题时,请在提问前先在 StackOverflow 中搜索关键字。答案大概就在那里。如果您搜索 sepia RGBTRIPLE cs50
,您会得到相当多的结果。
进行大量像素处理后,您将磨练一些有用的调试直觉。其中:
- 如果您看到对角线偏移,则图像的每行字节数可能大于宽度乘以像素大小。 (特别是在 YCbCr 图像中或图像缓冲区与 128 位 vector 大小对齐的平台上。)
- 2x 或 0.5x 图像显示可能意味着您没有注意到 Retina 显示屏上的比例值。
- 某些色彩空间错误会立即让您发现 BGR 与 RGB 字节排序问题。根本没有蓝色 channel 还是全蓝色?可能将 ARGB 与 BGRA 混合。
但更重要的是:
- 如果您在明亮或颜色饱和的区域看到奇怪的现象,则您的像素分量值可能过饱和(超过最大值,并丢弃高位)。
每次 (1) 将一个颜色分量乘以大于 1 的数字或 (2) 将多个颜色分量相加时,您需要考虑如果超过最大值会发生什么。如果您的中级数学将两个值相加然后除以 2,请确保您的编译操作将使用足够大的变量大小来容纳额外的位。
因此,在此处的内部循环中,当对白色像素进行操作时,几乎每个颜色分量都会超过 255(即红色和绿色会超过,但不会超过蓝色,因为棕褐色的蓝色含量较低):
int sepiared = image[i][j].rgbtRed *.393 + image[i][j].rgbtGreen *.769 + image[i][j].rgbtBlue *.189;
int sepiagreen = image[i][j].rgbtRed *.349 + image[i][j].rgbtGreen *.686 + image[i][j].rgbtBlue *.168;
int sepiablue = image[i][j].rgbtRed *.272 + image[i][j].rgbtGreen *.534 + image[i][j].rgbtBlue *.131;
结果值为 {255, 255, 255} x {.393+.769+.189, .349+.686+.168, .272+.534+.131} 或 {344.5, 306.8 ,238.9}。
但是,由于 RGBTRIPLE 结构的 BYTE 组件中的这些值没有足够的位,因此您的值将不正确。因此,您可以这样做:
int sepiared = (int) image[i][j].rgbtRed *.393 + image[i][j].rgbtGreen *.769 + image[i][j].rgbtBlue *.189;
int sepiagreen = (int) image[i][j].rgbtRed *.349 + image[i][j].rgbtGreen *.686 + image[i][j].rgbtBlue *.168;
int sepiablue = (int) image[i][j].rgbtRed *.272 + image[i][j].rgbtGreen *.534 + image[i][j].rgbtBlue *.131;
sepiared = min(sepiared, 255);
sepiagreen = min(sepiagreen, 255);
sepiablue = min(sepiablue, 255);
请注意,我做了两项更改:
- 将每个表达式中的第一个值转换为 (int);否则计算将以字节为单位进行,并且您将丢失高位。
- 对每个像素组件强制使用最大值 255。
在考虑其他答案时,请添加我的第一个修复。如果您已经放弃了高位,则检查最大值 255 将无济于事!
关于Cs50 棕褐色将图像从正常转换为棕褐色的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63416505/