如果给出黑色像素的坐标,我可以通过数学公式y = mx + c插值计算出蓝色像素的坐标值。但是新的RGB像素值怎么办?考虑到黑色像素RGB值在图中如此给出,那么如何得到蓝色像素加权平均RGB值呢?
非常感谢任何帮助。提前致谢。
如果给出黑色像素的坐标,我可以通过数学公式y = mx + c插值计算出蓝色像素的坐标值。但是新的RGB像素值怎么办?考虑到黑色像素RGB值在图中如此给出,那么如何得到蓝色像素加权平均RGB值呢?
非常感谢任何帮助。提前致谢。
与RGB和插值相关的特征是,中性被定义为R = G = B的点。三线性插值器沿着该中性轴具有最大误差,并且通常具有沿颜色空间中中性路径的错误的特征(呈扇形)。
那么如何在三维空间中进行插值呢?我假设你是在颜色空间的一组规则点上进行插值。在这种情况下,可以确定包含任何单个点的立方体。如果你要在一组散点内进行插值,则最简单的解决方案通常是构建这些点的三角剖分,然后在任何给定的四面体内进行简单(线性)插值。高阶插值在这里是有问题的,因为它们可能会在某些情况下导致颜色问题。例如,人们不希望看到梯度沿着反向变化。这可能会发生,因为在相对高曲率的区域中,基于样条的插值器存在严重的振铃问题。如果涉及到色域映射,那么这样的转换肯定会成为一个问题。即使不需要进行色域映射,仍然需要处理色域问题。Q1 = [66, 51, 77]
Q2 = [55, 66, 77]
这些是我们要插值的值,基本上是我们映射的输出,但我们还需要知道这些点在输入RGB空间中的位置。因此,请假设基于它们来自的立方体的坐标,这些坐标为:
P1 = [0, 0, 0]
P2 = [1, 0, 0]
这是一个三维单位立方体,我已经写好了,所以其他点会位于
P3 = [0, 1, 0]
P4 = [1, 1, 0]
P5 = [0, 0, 1]
P6 = [1, 0, 1]
P7 = [0, 1, 1]
P8 = [1, 1, 1]
当然,任何一般的立方体也可以使用,没有理由它必须是一个真正的立方体。任何三维直角四边形棱柱在这里也适用。你总是可以将事物转化为单位立方体。
现在,假设我们希望在立方体的这条边上,在由Q1和Q2定义的域中,在P1和P2之间进行插值?选择沿着该边的某个点。你可以看到只有R在这些点之间沿着该边变化,因此我们只关心我们插值点处的R值。从沿着该边从0到1的红色通道的r值的百分比来考虑它。插值仅仅是两个端点的加权平均值,即线性组合。因此,对于沿着从0到1的红色通道的边缘具有红色值r的点,我们的插值将是
Q(r) = Q1*(1-r) + Q2*r
Q(1/2,0,0) = (Q1 + Q2)/2
从逻辑上讲,中点值将是两个端点的平均值。您需要独立为每个输出通道执行插值操作。
Q(1/2,0,0) = ([66, 51, 77] + [55, 66, 77])/2 = [60.5, 58.5, 77]
这个能恢复端点吗?当然可以。当r = 0或r = 1时,你可以看到它恰好返回相应的Q1或Q2。
同样,你可以沿着每个红色边缘进行插值,得到三线性插值器的四个结果。然后,你需要进行两次插值,可能是沿着我们上面得到的四个结果的绿色边缘。最后,你需要进行一次插值,沿着蓝色边缘得到三线性插值器。同样,选择插值轴的顺序并不重要。结果在数学上是相同的。
如果你停留在双线性插值上,那么就有三个这样的线性插值。是的,双线性插值或三线性插值也可以作为矩形(或立方体)的所有4(或8)个角落的加权组合来完成。这可以留待未来。
你需要独立地进行值的插值计算,对于R、G和B分别执行一次计算。例如,在(200,50,10)和(0,0,0)之间进行一半插值得到(100,25,5)。
/*
resize an image using bilinear interpolation
*/
void bilerp(unsigned char *dest, int dwidth, int dheight, unsigned char *src, int swidth, int sheight)
{
float a, b;
float red, green, blue, alpha;
float dx, dy;
float rx, ry;
int x, y;
int index0, index1, index2, index3;
dx = ((float) swidth)/dwidth;
dy = ((float) sheight)/dheight;
for(y=0, ry = 0;y<dheight-1;y++, ry += dy)
{
b = ry - (int) ry;
for(x=0, rx = 0;x<dwidth-1;x++, rx += dx)
{
a = rx - (int) rx;
index0 = (int)ry * swidth + (int) rx;
index1 = index0 + 1;
index2 = index0 + swidth;
index3 = index0 + swidth + 1;
red = src[index0*4] * (1.0f-a)*(1.0f-b);
green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
red += src[index1*4] * (a)*(1.0f-b);
green += src[index1*4+1] * (a)*(1.0f-b);
blue += src[index1*4+2] * (a)*(1.0f-b);
alpha += src[index1*4+3] * (a)*(1.0f-b);
red += src[index2*4] * (1.0f-a)*(b);
green += src[index2*4+1] * (1.0f-a)*(b);
blue += src[index2*4+2] * (1.0f-a)*(b);
alpha += src[index2*4+3] * (1.0f-a)*(b);
red += src[index3*4] * (a)*(b);
green += src[index3*4+1] * (a)*(b);
blue += src[index3*4+2] * (a)*(b);
alpha += src[index3*4+3] * (a)*(b);
red = red < 0 ? 0 : red > 255 ? 255 : red;
green = green < 0 ? 0 : green > 255 ? 255 : green;
blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
dest[(y*dwidth+x)*4] = (unsigned char) red;
dest[(y*dwidth+x)*4+1] = (unsigned char) green;
dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
}
index0 = (int)ry * swidth + (int) rx;
index1 = index0;
index2 = index0 + swidth;
index3 = index0 + swidth;
red = src[index0*4] * (1.0f-a)*(1.0f-b);
green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
red += src[index1*4] * (a)*(1.0f-b);
green += src[index1*4+1] * (a)*(1.0f-b);
blue += src[index1*4+2] * (a)*(1.0f-b);
alpha += src[index1*4+3] * (a)*(1.0f-b);
red += src[index2*4] * (1.0f-a)*(b);
green += src[index2*4+1] * (1.0f-a)*(b);
blue += src[index2*4+2] * (1.0f-a)*(b);
alpha += src[index2*4+3] * (1.0f-a)*(b);
red += src[index3*4] * (a)*(b);
green += src[index3*4+1] * (a)*(b);
blue += src[index3*4+2] * (a)*(b);
alpha += src[index3*4+3] * (a)*(b);
red = red < 0 ? 0 : red > 255 ? 255 : red;
green = green < 0 ? 0 : green > 255 ? 255 : green;
blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
dest[(y*dwidth+x)*4] = (unsigned char) red;
dest[(y*dwidth+x)*4+1] = (unsigned char) green;
dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
}
index0 = (int)ry * swidth + (int) rx;
index1 = index0;
index2 = index0 + swidth;
index3 = index0 + swidth;
for(x=0, rx = 0;x<dwidth-1;x++, rx += dx)
{
a = rx - (int) rx;
index0 = (int)ry * swidth + (int) rx;
index1 = index0 + 1;
index2 = index0;
index3 = index0;
red = src[index0*4] * (1.0f-a)*(1.0f-b);
green = src[index0*4+1] * (1.0f-a)*(1.0f-b);
blue = src[index0*4+2] * (1.0f-a)*(1.0f-b);
alpha = src[index0*4+3] * (1.0f-a)*(1.0f-b);
red += src[index1*4] * (a)*(1.0f-b);
green += src[index1*4+1] * (a)*(1.0f-b);
blue += src[index1*4+2] * (a)*(1.0f-b);
alpha += src[index1*4+3] * (a)*(1.0f-b);
red += src[index2*4] * (1.0f-a)*(b);
green += src[index2*4+1] * (1.0f-a)*(b);
blue += src[index2*4+2] * (1.0f-a)*(b);
alpha += src[index2*4+3] * (1.0f-a)*(b);
red += src[index3*4] * (a)*(b);
green += src[index3*4+1] * (a)*(b);
blue += src[index3*4+2] * (a)*(b);
alpha += src[index3*4+3] * (a)*(b);
red = red < 0 ? 0 : red > 255 ? 255 : red;
green = green < 0 ? 0 : green > 255 ? 255 : green;
blue = blue < 0 ? 0 : blue > 255 ? 255 : blue;
alpha = alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
dest[(y*dwidth+x)*4] = (unsigned char) red;
dest[(y*dwidth+x)*4+1] = (unsigned char) green;
dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
}
dest[(y*dwidth+x)*4] = src[((sheight-1)*swidth+swidth-1)*4];
dest[(y*dwidth+x)*4+1] = src[((sheight-1)*swidth+swidth-1)*4+1];
dest[(y*dwidth+x)*4+2] = src[((sheight-1)*swidth+swidth-1)*4+2];
dest[(y*dwidth+x)*4+3] = src[((sheight-1)*swidth+swidth-1)*4+3];
}
代码在此维护
https://github.com/MalcolmMcLean/babyxrc/blob/master/src/resize.c