11

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

在此处输入图像描述

我想做的是修改我的代码,以便波形的明显动态范围基本上是“压缩的”。要生成看起来更像这样的波形:

在此处输入图像描述

我目前用来渲染每个数据点高度的方程式如下:-

 // 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。

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

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

在此处输入图像描述

当 $v 的值是 0 或 255 时,方程的输出应该正好是输入(0 或 255)。但是,当输入是介于两者之间的值时,它应该遵循上面曲线的结果输出。(以上只是一个粗略的图来说明。)

编辑:

基于 Alnitiks 'pow' 函数解决方案,我现在正在生成如下所示的波形:-

在此处输入图像描述

使用 $v 变量的替换方程如下:-

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

我已经尝试提高 0.4 的值,但结果仍然不符合预期。

编辑2:

这里要求是我的 $data 变量的原始数据转储:

原始数据

这被传递到方程中以在用于绘制波形之前返回 $v(您可以在上面发布的原始代码中看到我对变量 $v 所做的事情。$height 很简单,我设置了图像的高像素数渲染。

此数据是逗号分隔的值列表。我希望这有帮助。看来您断言平均值为 128 是正确的。到目前为止,我一直无法理解您对此的更正。恐怕这有点超出我目前的理解。

4

3 回答 3

3

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

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

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

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

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

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


自然动态值是由数学正弦和余弦函数生成的,在 PHP 这个sin文档(以及那里链接的其他文档)中。

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

$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);

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

于 2012-01-03T15:10:28.903 回答
3

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

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

由于您的值在 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曲线(红色):

伽玛曲线与罪

的值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);

虽然我看到PHP 开发人员没有在 PHP 库中包含sign函数。

于 2012-01-03T15:19:59.067 回答
0

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

于 2019-11-11T07:17:32.407 回答