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

Posted

技术标签:

【中文标题】在 PHP 中渲染波形 - 如何生成更压缩的渲染?【英文标题】:Rendering waveform in PHP - How to produce a more compressed render? 【发布时间】:2012-02-01 14:35:04 【问题描述】:

我在 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 变量的原始数据转储:

Raw Data

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

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

【问题讨论】:

+1:我不确定这是否完全符合主题,但我不在乎……这很有趣! 你真的需要找到该曲线的方程并应用一个乘法因子;这一切都归结为当你去掉有趣的因素时。如果您不关心小数值(这似乎很可能),您可以完全跳过它,只需手动创建已知值的查找 - 正如 hakre 所建议的那样。 确实如此。我确实想知道这是否应该发布在数学网站上。但我敢肯定,我从你们那里得到的回答会比数学家更多地用我的“自己的”语言来表达。 :-) +1 这也是一个写得很好的问题。 所需曲线是伽玛校正曲线-y = pow(x, 1 / gamma) 【参考方案1】:

没有数学技能(可能对快速展示有用):

您有 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);

我这里使用了一个变量函数,所以你可以写多个,并且可以很容易地测试哪一个符合你的需要。

【讨论】:

感谢 hakre,预定义的数组肯定是最简单的解决方案,我不知道为什么我自己没有想到它。如果一切都失败了,这就是我将采取的方法。尽管如此,我宁愿有一个简单的方程式来完成这项工作(最终可以在需要时进行修改),因此我目前正在探索您的正弦/余弦建议。再次感谢。 对于正弦,看起来 x 从 i/255 * 0.5 * PI 开始,而 i 从 0-255 开始。可能会给你你的曲线。将添加一个示例。 很棒的答案,非常感谢。你的例子正是我需要的。顺便说一句,我几乎使用 Alnitak 建议的 pow 函数到达那里。我确信他的方法也行得通,但花时间提供一个例子,你应该得到答案。非常感谢大家。 :-) 没问题,我仍然不确定答案中的这种等式是否正在创造您正在寻找的动力。您也可以通过编辑答案添加自己的;) 恕我直言,sin 曲线没有提供足够的低端增强 - 对于低 x 而言,这不足为奇,sin(x) ~= x【参考方案2】:

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

对于 0.0 -> 1.0 范围内的输入值 x,当 n 应在 0.2 - 0.7 (ish) 范围内时,取 y = pow(x, 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 曲线(红色):

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 函数。

【讨论】:

感谢 Alnitak,我目前正在研究 hakre 和您自己的建议。 (分别为正弦/余弦和 pow 函数。)非常感谢您的回答,希望我能尽快将其标记为已回答。 :-) 这是非常棒的信息 Alnitak。谢谢你。它确实看起来像是一个更好的整体解决方案。但是由于某种原因,我无法让它正确渲染图像。我对您的回答的实施一定有问题。我会继续努力并报告。 @gordyr 你的一些值是负数还是基于 128 的零值? 不,它们都应该在 0 到 255 之间。我已经设法使用 pow 方法来渲染波形,正如您建议的那样,将上面的 $v 行替换为:$v = (255 * pow($data / 255.0, 0.4)) * $height;然而,这似乎大大放大了低值。我将通过更新显示使用 pow 函数生成的波形图像来编辑我的问题。 @gordyr 是平均值 128,但是?我已经更新了我的答案以显示如何解决这个问题。如果放大仍然太大,将 0.4 值向上调整一点。【参考方案3】:

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

【讨论】:

以上是关于在 PHP 中渲染波形 - 如何生成更压缩的渲染?的主要内容,如果未能解决你的问题,请参考以下文章

如何从HTML5网络视频生成音频波形?

如何从 HTML5 网络视频生成音频波形?

如何在reactjs中渲染压缩/压缩图像

在 iOS 上渲染非常高频的声音

如何在 UIScrollView 中的图像上呈现非缩放覆盖

想渲染或生成一个目录下的所有php文件到静态html