2012-01-03 7 views
11

Estoy representando una forma de onda en PHP al reducir la resolución con el codificador cojo y luego dibujar la forma de onda de los puntos de datos resultantes. Actualmente estoy recibiendo imágenes como esta:Representación de forma de onda en PHP - ¿Cómo producir un renderizado más comprimido?

enter image description here

Lo que me gustaría hacer es modificar mi código para que el rango dinámico aparente de la forma de onda es esencialmente 'comprimido'. Para producir una forma de onda que se parece más a esto:

enter image description here

La ecuación Actualmente estoy usando para hacer que la altura de cada punto de datos es el siguiente: -

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

siendo la amplitud real definido por la primera línea de este código: -

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

Desafortunadamente, mi habilidad matemática es mala en el mejor de los casos. Lo que necesito hacer es aplicar esencialmente una 'curva' al valor de $ v para que cuando el número de entrada en la ecuación sea más bajo, el resultado resultante sea más alto y a medida que aumente el número de entrada la ecuación reduzca la amplificación hasta que finalmente la entrada llega a 255 la salida también debe ser 255. También la curva debe ser tal que con una entrada de 0 la salida también sea 0.

Pido disculpas si esto no está claro pero estoy encontrando esta pregunta muy difícil de articular con mi limitada experiencia en matemáticas.

Tal vez una representación visual podría ayudar a describir mi intención: -

enter image description here

Cuando el valor de $ v es 0 o 255 la salida de la ecuación debe ser exactamente la entrada (0 ó 255) . Sin embargo, cuando la entrada es un valor intermedio, debe seguir la salida resultante de la curva de arriba. (El anterior fue sólo un dibujo en bruto para ilustrar.)

EDIT:

basado en la solución función 'pow' Alnitiks ahora estoy generando formas de onda que se parece a esto: -

enter image description here

utilizando la ecuación de reemplazo para el $ variable v de la siguiente manera: -

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

he tratado subiendo el valor de 0,4, pero el resultado es st no como se esperaba

EDIT 2:

Como solicitó que aquí hay una DataDump prima de mi variable de datos $:

Raw Data

Esto se transfieren en la ecuación para volver $ v antes de ser utilizado para dibujar la forma de onda (Puede ver lo que le hago a la variable $ v en el código original que publiqué arriba. $ height es simple el número de píxeles altos He configurado la imagen para procesar.

Estos datos son una lista de valores separados por comas.Espero que esto ayude. Parece que tu afirmación de que el valor medio es 128 es correcto. Hasta ahora no he podido entender mi corrección por esto. Me temo que es un poco más allá de mi comprensión actual.

+1

+1: No estoy seguro de si esto es estrictamente sobre el tema, pero no me importa ... ¡es divertido! –

+0

Realmente necesitas encontrar la ecuación de esa curva y aplicar un factor de multiplicación; eso es todo lo que se reduce a cuando se deshace del factor diversión. Y podría omitirlo por completo y simplemente crear manualmente una búsqueda de valores conocidos, como sugiere Hakre, si no le importan los valores fraccionarios (lo que parece probable). –

+1

De hecho. Me pregunto si esto debería haber sido publicado en el sitio de matemáticas. Pero estoy seguro de que las respuestas que recibiría de ustedes serían mucho más en mi 'propio' idioma que los matemáticos. :-) – gordyr

Respuesta

3

Sin habilidades matemáticas (y probablemente útiles para tener una visualización rápida):

Usted tiene 256 valores posibles. Crear una matriz que contiene el valor "dinámico" para cada uno de estos valores:

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

Una vez hecho esto, se puede conseguir fácilmente el valor dinámico:

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

Es posible que pierda un poco de precisión, pero probablemente útil.


valores dinámicos naturales son generados por las funciones matemáticas sine y coseno, en PHP esta sin­Docs (y otros vinculados allí).

Puede utilizar un bucle y que la función de pre-rellenar la matriz, así y volver a utilizar la matriz de modo que haya valores pre-calculados:

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

que utiliza una función variable de aquí, para que pueda escribir múltiple y puede probar fácilmente cuál coincide con sus necesidades.

+0

Gracias hakre, una matriz predefinida sería sin duda la solución más simple, la mente se pregunta por qué no había pensado en ella. Si todo lo demás falla, este es el enfoque que tomaré. Dicho esto, sin embargo, prefiero tener una ecuación simple para hacer el trabajo (que en última instancia se puede modificar simplemente en caso de necesidad) y, como tal, actualmente estoy explorando su sugerencia de seno/coseno. Gracias de nuevo. – gordyr

+0

Para el seno parece que x va de i/255 * 0.5 * PI con i desde 0-255. Podría darte tu curva. Agregará un ejemplo. – hakre

+0

Fantástica respuesta hakre muchas gracias. Tu ejemplo hace exactamente lo que necesito. Por cierto, casi llegué allí usando la función pow como sugirió Alnitak. Estoy seguro de que su método también funcionaría, pero por tomarse el tiempo para dar un ejemplo, mereces la respuesta. Muchísimas gracias a todos. :-) – gordyr

3

Necesita algo similar a la corrección gamma.

Para valores de entrada x en el rango 0.0 -> 1.0, tome y = pow(x, n) cuando n debe estar en el rango 0.2 - 0.7 (ish). Solo elija un número que dé la curva deseada.

Como sus valores están en el rango 0 -> 255, deberá dividir por 255.0, aplicar la función pow y luego multiplicar por 255 nuevamente, p. Ej.

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

La fórmula pow satisface los criterios que 0 y 1 mapa a sí mismos, y más pequeños valores se "amplificadas" más que valores más grandes.

Así es un gráfico que muestra curvas de gamma para n = 1/1,6, 1/2, 1/2,4 y 1/2,8, vs la curva sin (en rojo):

Gamma Curves vs Sin

Cuanto menor sea el valor de n, más "compresión" se aplica al extremo inferior, por lo que la línea azul claro es aquella con n = 1/2.8.

Tenga en cuenta que la curva sin es casi lineal en el rango de 0 a 0,5, por lo que casi no ofrece compresión en el extremo bajo.

Si como sospecho que sus valores son en realidad centran alrededor de 128, entonces usted necesita para modificar un poco la fórmula:

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

aunque veo que the PHP developers have not incluido una función sign en la biblioteca PHP.

+0

Gracias Alnitak, actualmente estoy mirando la sugerencia de hakre y la tuya. (seno/coseno y la función pow, respectivamente.) Muchas gracias por su respuesta y espero poder marcar esto como respuesta pronto. :-) – gordyr

+0

Esto es información fantástica Alnitak. Gracias. De hecho, parece una mejor solución general. Sin embargo, por algún motivo, tengo problemas para obtener la imagen correctamente. Debe haber algo mal con mi implementación de su respuesta. Seguiré intentándolo e informaré. – gordyr

+0

@gordyr son algunos de sus valores negativos o tal vez se basan en un valor cero de 128? – Alnitak

Cuestiones relacionadas