我正在C中制作一个图像大小调整程序,目前我遇到了双线性插值功能(这是我正在使用的众多功能之一)。这个问题只出现在16位位图中,如果我使用的是24位版本,它会完美地调整它们的大小。
这是我的双线性插值代码。 n_w和n_h是图像的新宽度和高度:
#define getelm(x) (((pix+index)->x)*(1-xdiff)*(1-ydiff))+(((pix+index+1)->x)*(xdiff)*(1-ydiff))+(((pix+index+o_w)->x)*(1-xdiff)*(ydiff))+((pix+index+o_w+1)->x)*xdiff*ydiff
int pad = (2*n_w) & 3;
if (pad)
pad = 4-pad;
uint16_t *buffer;
if (buf)
buffer = malloc(2*n_w);
for (i = 0; i < n_h; i++) {
for (j = 0; j < n_w; j++) {
x = (int)(j*xrat);
y = (int)(i*yrat);
xdiff = (xrat*j)-x;
ydiff = (yrat*i)-y;
index = y*o_w+x;
uint16_t container = 0;
container |= (int)(round(getelm(b))) << 11;
container |= (int)(round(getelm(g))) << 5;
container |= (int)round(getelm(r));
if (buf)
*(buffer+j) = container;
else
fwrite(&container, 1, 2, dest);
}
if (buf)
fwrite(buffer, 1, 2*n_w, dest);
fwrite(&pad, 1, pad, dest);
}
这个代码的24位版本(唯一的区别是没有使用容器,而是3个8位整数保存RGB值)可以很好地工作。
然而,这段代码给出了奇怪的结果。请看下面的图片:
当我调整大小时,它会给我回复:
我不明白为什么会发生这种情况,特别是当它适用于24位位图时,还有一些其他调整大小算法(例如最近邻)以与此相同的方式使用16位。
编辑: 我不认为这是一个溢出问题,因为在运行时添加以下代码不会产生输出:
if (MAX((int)(getelm(b)), 31) > 31)
printf("blue overflow: %.10f\n", (getelm(b)));
if (MAX((int)(getelm(g)), 63) > 63)
printf("green overflow: %.10f\n", (getelm(g)));
if (MAX((int)(getelm(r)), 31) > 31)
printf("red overflow: %.10f\n", (getelm(r)));
编辑2: 我不认为这也是一个下溢问题,这没有任何作用:
if ((getelm(b)) < 0 || (getelm(g)) < 0 || (getelm(r)) < 0)
printf("Underflow\n");
答案 0 :(得分:2)
假设pix
中的数据具有类型
struct
{
uint16_t r : 5;
uint16_t g : 6;
uint16_t b : 5;
};
计算container
时出现错误。使用round
并不总能防止溢出。下一个代码将:
uint16_t container = 0;
container |= ((int)(round(getelm(b))) & 31) << 11; // optionally
container |= ((int)(round(getelm(g))) & 63) << 5;
container |= ((int)round(getelm(r)) & 31);
或保留最多丢失的信息:
uint16_t container = 0;
container |= min((int)(round(getelm(b))) , 31) << 11;
container |= min(((int)(round(getelm(g))) , 63) << 5;
container |= min(((int)round(getelm(r)) , 31);
修改强>
由于pix->r
,pix->g
和pix->b
来自8位值,因此相同的推理适用于它们,并且需要检查它们的范围。
由于白色区域变为紫色,这意味着绿色由于溢出而被抑制,或者它首先被读取为零。在这种情况下,检查读取颜色可以帮助。 类似地,黑色变成绿色表示表示小值的位移位,颜色以某种方式反转。
要找到错误,我建议将代码拆分为小函数并断言每个函数的输入。