我用过
图形图像
框架(
)最近读取Adobe acv文件并生成着色器纹理的LUT。在成功地使用这个工具在我的图像中渲染自定义色调后,我很好奇使用了什么样的样条插值算法来实现这一点。在示例代码中,我可以发现有一些二阶导数计算。但我不明白这些数学参数是从哪里来的。能否为进一步的插值研究提供一些理论参考?谢谢
[编辑]
如下文所述,我将样条计算代码粘贴在
GPUImageToneCurveFilter。m
. 它是
目标-C
版本
从ACV文件中获取控制点并将其从(0,1)转换为(0,255)后,将点发送到splineCurve函数进行插值,如下所示:
NSMutableArray *splinePoints = [self splineCurve:convertedPoints];
- (NSMutableArray *)splineCurve:(NSArray *)points
{
NSMutableArray *sdA = [self secondDerivative:points];
// [points count] is equal to [sdA count]
NSInteger n = [sdA count];
if (n < 1)
{
return nil;
}
double sd[n];
// From NSMutableArray to sd[n];
for (int i=0; i<n; i++)
{
sd[i] = [[sdA objectAtIndex:i] doubleValue];
}
NSMutableArray *output = [NSMutableArray arrayWithCapacity:(n+1)];
for(int i=0; i<n-1 ; i++)
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
CGPoint cur = [[points objectAtIndex:i] CGPointValue];
CGPoint next = [[points objectAtIndex:(i+1)] CGPointValue];
#else
NSPoint cur = [[points objectAtIndex:i] pointValue];
NSPoint next = [[points objectAtIndex:(i+1)] pointValue];
#endif
for(int x=cur.x;x<(int)next.x;x++)
{
double t = (double)(x-cur.x)/(next.x-cur.x);
double a = 1-t;
double b = t;
double h = next.x-cur.x;
double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
if (y > 255.0)
{
y = 255.0;
}
else if (y < 0.0)
{
y = 0.0;
}
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
[output addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
#else
[output addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
#endif
}
}
// The above always misses the last point because the last point is the last next, so we approach but don't equal it.
[output addObject:[points lastObject]];
return output;
}
- (NSMutableArray *)secondDerivative:(NSArray *)points
{
const NSInteger n = [points count];
if ((n <= 0) || (n == 1))
{
return nil;
}
double matrix[n][3];
double result[n];
matrix[0][1]=1;
// What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.)
matrix[0][0]=0;
matrix[0][2]=0;
for(int i=1;i<n-1;i++)
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
CGPoint P1 = [[points objectAtIndex:(i-1)] CGPointValue];
CGPoint P2 = [[points objectAtIndex:i] CGPointValue];
CGPoint P3 = [[points objectAtIndex:(i+1)] CGPointValue];
#else
NSPoint P1 = [[points objectAtIndex:(i-1)] pointValue];
NSPoint P2 = [[points objectAtIndex:i] pointValue];
NSPoint P3 = [[points objectAtIndex:(i+1)] pointValue];
#endif
matrix[i][0]=(double)(P2.x-P1.x)/6;
matrix[i][1]=(double)(P3.x-P1.x)/3;
matrix[i][2]=(double)(P3.x-P2.x)/6;
result[i]=(double)(P3.y-P2.y)/(P3.x-P2.x) - (double)(P2.y-P1.y)/(P2.x-P1.x);
}
// What about result[0] and result[n-1]? Assuming 0 for now (Brad L.)
result[0] = 0;
result[n-1] = 0;
matrix[n-1][1]=1;
// What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.)
matrix[n-1][0]=0;
matrix[n-1][2]=0;
// solving pass1 (up->down)
for(int i=1;i<n;i++)
{
double k = matrix[i][0]/matrix[i-1][1];
matrix[i][1] -= k*matrix[i-1][2];
matrix[i][0] = 0;
result[i] -= k*result[i-1];
}
// solving pass2 (down->up)
for(NSInteger i=n-2;i>=0;i--)
{
double k = matrix[i][2]/matrix[i+1][1];
matrix[i][1] -= k*matrix[i+1][0];
matrix[i][2] = 0;
result[i] -= k*result[i+1];
}
double y2[n];
for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
NSMutableArray *output = [NSMutableArray arrayWithCapacity:n];
for (int i=0;i<n;i++)
{
[output addObject:[NSNumber numberWithDouble:y2[i]]];
}
return output;
}
希望这些解释能帮助找出Brad L.用什么样的算法来插值曲线,从而得到Photoshop那样的结果。