在PHP中渲染波形 - 如何生成更加压缩的渲染?

时间:2012-01-03 15:03:38

标签: php math libpng

我通过使用跛脚编码器对其进行下采样,然后从结果数据点绘制波形,在PHP中渲染波形。我目前正在获得这样的图像:

enter image description here

我想要做的是修改我的代码,使波形的表观动态范围基本上“压缩”。要产生看起来更像这样的波形:

enter image description here

我目前用于渲染每个数据点高度的公式如下: -

 // draw this data point
          // relative value based on height of image being generated
          // data values can range between 0 and 255
           $v = (int) ( $data / 255 * $height );


          // don't print flat values on the canvas if not necessary
          if (!($v / $height == 0.5 && !$draw_flat))
            // draw the line on the image using the $v value and centering it vertically on the canvas
            imageline(
              $img,
              // x1
              (int) ($data_point / DETAIL),
              // y1: height of the image minus $v as a percentage of the height for the wave amplitude
              $height * $wav - $v,
              // x2
              (int) ($data_point / DETAIL),
              // y2: same as y1, but from the bottom of the image
              $height * $wav - ($height - $v),
              imagecolorallocate($img, $r, $g, $b)
            );      

实际幅度由此代码的第一行定义: -

  $v = (int) ( $data / 255 * $height );

不幸的是,我的数学技能充其量只是很差。我需要做的是基本上对$ v的值应用'曲线',这样当输入到方程中的数字较低时,结果输出较高,并且当输入数字增加时,等式减小放大直到最后输入达到255时,输出也应该是255.此外曲线应该是这样的,输入为0时输出也为0.

如果不清楚我会道歉但我发现这个问题很难用我有限的数学经验表达出来。

也许视觉表现有助于描述我的意图: -

enter image description here

当$ v的值为0或255时,等式的输出应该完全是输入(0或255)。但是,当输入是中间值时,它应该遵循上面曲线的结果输出。 (以上只是粗略说明。)

编辑:

基于Alniti的'pow'功能解决方案,我现在生成的波形如下: -

enter image description here

使用$ v变量的替换公式如下: -

 $v = pow($data / 255.0, 0.4) * $height;

我试过提高0.4值,但结果仍然不符合预期。

编辑2:

这里要求的是我的$ data变量的原始datadump:

Raw Data

在用于绘制波形之前,这会被传递到公式中以返回$ v(你可以看到我在上面发布的原始代码中对变量$ v做了什么。$ height很简单我拥有的像素数高将图像设置为渲染。

此数据是逗号分隔的值列表。我希望这有帮助。看来你的断言平均值是128是正确的。到目前为止,我一直无法理解你的纠正。我担心这稍微超出了我目前的理解。

3 个答案:

答案 0 :(得分:3)

没有数学技能(可能有助于快速显示):

您有256个可能的值。创建一个数组,其中包含每个值的“动态”值:

$dynamic = array(
   0 => 0,
   1 => 2,
   ...
);

完成后,您可以轻松获得动态值:

$v = (int) ($dynamic[(int) $data / 255] * $height);

你可能会失去一些精确度,但它可能很有用。


自然动态值由数学sine和余弦函数生成,在PHP中sin­Docs(以及其他链接的那些)。

您可以使用循环和该函数预先填充数组并重新使用数组,以便预先计算出值:

$sine = function($v)
{
    return sin($v * 0.5 * M_PI);
};

$dynamic = array();
$base = 255;
for ($i = 0; $i <= $base; $i++)
{
    $dynamic[$i] = $i/$base;
}

$dynamic = array_map($sine, $dynamic);

我在这里使用变量函数,因此您可以编写多个函数并轻松测试哪一个符合您的需求。

答案 1 :(得分:3)

你需要类似于伽马校正的东西。

对于输入值x,范围为0.0 - > 1.0,当y = pow(x, n)应在0.2 - 0.7(ish)范围内时,取n。只需选择一个能产生所需曲线的数字。

由于您的值在0 - >范围内; 255你将需要除以255.0,应用pow函数,然后再乘以255,例如

$y = 255 * pow($x / 255.0, 0.4);

pow公式满足0和1映射到自身的条件,较小的值比较大的值“放大”。

这是一张显示n = 1 / 1.6,1 / 2,1 / 2.4和1 / 2.8的伽玛曲线与sin曲线(红色)的曲线图:

Gamma Curves vs Sin

n的值越低,对低端应用的“压缩”越多,因此浅蓝色线是n = 1 / 2.8的那个。

注意sin曲线在0到0.5范围内几乎是线性的,因此几乎不提供低端压缩。

如果我怀疑你的值实际上以128为中心,那么你需要稍微修改一下公式:

$v = ($x - 128.0) / 128.0;
$y = 128 + 127 * sign($v) * pow(abs($v), 0.4);

虽然我看到the PHP developers have not在PHP库中包含了sign函数。

答案 2 :(得分:0)

简单的下采样将无法为您提供正确的渲染,因为它只会使原始信号只有低频,而所有频率都会影响幅度。因此,您需要从原始波形构建峰值数据(在特定范围的值的最大值和最小值)以使其可视化。您不应该对数据应用任何非线性函数,因为波形表示是线性的(不同于伽玛压缩的图像)。