“高对比度”曲线的快速公式

时间:2009-09-25 23:35:19

标签: optimization math formula

我的内部循环包含一个计算,分析显示有问题。

想法是采用灰度像素x(0 <= x <= 1),并“增加其对比度”。我的要求相当宽松,只有以下内容:

  • for x&lt; .5,0 <= f(x)&lt; X
  • for x&gt; .5,x&lt; f(x)&lt; = 1
  • f(0)= 0
  • f(x)= 1-f(1-x),即它应该是“对称的”
  • 优选地,功能应该是平滑的。

因此图表必须如下所示:

Graph

我有两个实现(它们的结果不同但两者都符合):

float cosContrastize(float i) {
    return .5 - cos(x * pi) / 2;
}

float mulContrastize(float i) {
    if (i < .5) return i * i * 2;
    i = 1 - i;
    return 1 - i * i * 2;
}

所以我要求对这些实现之一进行微优化,或者为自己的原始,更快的公式请求。

也许你们中的一个人甚至可以把这些位弄乱;)

3 个答案:

答案 0 :(得分:13)

考虑以下 sigmoid 形函数(正确转换为所需范围):

screenshot


我使用MATLAB生成了上图。如果对此感兴趣的是代码:

x = -3:.01:3;
plot(   x, 2*(x>=0)-1, ...
        x, erf(x), ...
        x, tanh(x), ...
        x, 2*normcdf(x)-1, ...
        x, 2*(1 ./ (1 + exp(-x)))-1, ...
        x, 2*((x-min(x))./range(x))-1  )
legend({'hard' 'erf' 'tanh' 'normcdf' 'logit' 'linear'})

答案 1 :(得分:5)

琐事你可能只是门槛,但我想这太愚蠢了:

return i < 0.5 ? 0.0 : 1.0;

由于你提到'增加对比度',我假设输入值是亮度值。如果是这样,并且它们是离散的(可能是8位值),您可以使用查找表来快速完成此操作。

你的'mulContrastize'看起来相当快。一个优化是使用整数数学。让我们再次说明,您的输入值实际上可以作为[0..255]中的8位无符号值传递。 (再一次,可能是一个很好的假设吗?)你可以做一些大致相似的事情......

int mulContrastize(int i) {
  if (i < 128) return (i * i) >> 7; 
  // The shift is really: * 2 / 256
  i = 255 - i;
  return 255 - ((i * i) >> 7);

答案 2 :(得分:4)

分段插值可以快速灵活。它只需要几个决策,然后进行乘法和加法,并且可以近似任何曲线。它还避免了查找表可以引入的过程(或者两个查找中的额外成本,然后是插值以平滑这个),尽管lut可能对你的情况完全正常。

alt text

只需几段,就可以获得非常好的匹配。这里将有颜色渐变的路线,这将比绝对颜色的路线更难检测。

正如Eamon Nerbonne在评论中指出的那样,可以通过“根据二阶导数选择分割点来最大化细节”来优化分割,也就是说,斜率变化最大的地方。很明显,在我发布的示例中,在五个分段案例中间有三个段并没有添加更多细节。