Linux Center Valencia - Resultados de la búsqueda para: shuf

En ImageMagick podemos seleccionar colores de varias maneras, principalmente mediante el nombre predefinido del color o mediante un código hexadecimal.

Ya hemos visto en otros artículos que para trabajar con los colores predefinidos por ImageMagick podemos listarlos con:

convert -list color

Y usar esos colores. Es una forma muy útil y práctica de trabajar, pero esto nos limita a unos cuantos colores, unos setecientos según la versión, podemos saber la cantidad con:

convert -list color | wc -l

Y además no nos permite trabajar con transparencias. 
Por lo tanto, el trabajo con código hexadecimal, aunque nos obligue a un pequeño mayor esfuerzo a la hora de programar, nos ofrece una mayor cantidad de colores. Con los nombres de los colores predefinidos tenemos algo menos de 700 colores frente a los 255 * 255 * 255 colores con los que podemos trabajar si usamos códigos hexadecimales. Y si usamos el canal alpha para las transparencias, el número pasa a ser de  255 * 255 * 255 * 255 = 4.228,250.625 colores posibles.

Podemos escribir a mano el código:

convert -size 500x200 xc:#11223344 imagen.png

imagen.png

O podemos generar ese código aleatoriamente.
Para ello nos ayudaremos de shuf para generar un número aleatorio y bc para convertir de decimal a hexadecimal.

Y veamos una función que nos genere aleatoriamente un código hexadecimal de color en nuestros scripts. Pero que, además de dar la posibilidad de generar aleatoriamente un color aleatorio que le podamos indicar que tenga una tonalidad rojiza, verdosa o azulada, o bien que tenga menos coloración de uno de esos canales, que el color sea claro u oscuro y que tenga o no transparencia. Para ello uso una serie de parámetros en la función:

t T -t -T -> Se añade un canal Alfa de transparencia

d D -d -D o O -o -O -> oscuro o dark, el color generado será oscuro, entre 0 y 85 (255 / 3)

 l L -l -L c C -c -C -> claro o light, el color será claro, entre 170 ( 255 / 3 * 2 ) y 255

gb GB -gb -GB bg BG -bg -BG -> Mayor cantidad de verde y azul que de rojo

rb RB -rb -RB br BR -br -BR -> Mayor cantidad de rojo y azul que de verde

rg RG -rg -RG gr GR -gr -GR -> Mayor cantidad de rojo y verde que de azul

b B -b -B -> Color azulado

g G -g -G -> Color verdoso

r R -r -R -> Color rojizo

 

Con esas premisas, aquí dejo la función en un script de ejemplo:

#!/bin/bash

function devuelvecolor()
{

    if [ $1 = "r" ] || [ $1 = "R" ] || [ $1 = "-r" ] || [ $1 = "-R" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "g" ] || [ $1 = "G" ] || [ $1 = "-g" ] || [ $1 = "-G" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "b" ] || [ $1 = "B" ] || [ $1 = "-b" ] || [ $1 = "-B" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "rg" ] || [ $1 = "RG" ] || [ $1 = "-rg" ] || [ $1 = "-RG" ] || [ $1 = "gr" ] || [ $1 = "GR" ] || [ $1 = "-gr" ] || [ $1 = "-GR" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 0-127 -n 1)
    elif [ $1 = "rb" ] || [ $1 = "RB" ] || [ $1 = "-rb" ] || [ $1 = "-RB" ] || [ $1 = "br" ] || [ $1 = "BR" ] || [ $1 = "-br" ] || [ $1 = "-BR" ]
    then
        let decimalrojo=$(shuf -i 128-255 -n 1)
        let decimalverde=$(shuf -i 0-127 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "gb" ] || [ $1 = "GB" ] || [ $1 = "-gb" ] || [ $1 = "-GB" ] || [ $1 = "bg" ] || [ $1 = "BG" ] || [ $1 = "-bg" ] || [ $1 = "-BG" ]
    then
        let decimalrojo=$(shuf -i 0-127 -n 1)
        let decimalverde=$(shuf -i 128-255 -n 1)
        let decimalazul=$(shuf -i 128-255 -n 1)
    elif [ $1 = "l" ] || [ $1 = "L" ] || [ $1 = "-l" ] || [ $1 = "-L" ] || [ $1 = "c" ] || [ $1 = "C" ] || [ $1 = "-c" ] || [ $1 = "-C" ]
    then
        let decimalrojo=$(shuf -i 170-255 -n 1)
        let decimalverde=$(shuf -i 170-255 -n 1)
        let decimalazul=$(shuf -i 170-255 -n 1)
    elif [ $1 = "d" ] || [ $1 = "D" ] || [ $1 = "-d" ] || [ $1 = "-D" ] || [ $1 = "o" ] || [ $1 = "O" ] || [ $1 = "-o" ] || [ $1 = "-O" ]
    then
        let decimalrojo=$(shuf -i 0-85 -n 1)
        let decimalverde=$(shuf -i 0-85 -n 1)
        let decimalazul=$(shuf -i 0-85 -n 1)
    else
        let decimalrojo=$(shuf -i 0-255 -n 1)
        let decimalverde=$(shuf -i 0-100 -n 1)
        let decimalazul=$(shuf -i 0-255 -n 1)
    fi

    if [ "$2" ]
    then
        if [ $1 = "t" ] || [ $1 = "T" ] || [ $2 = "t" ] || [ $2 = "T" ] || [ $1 = "-t" ] || [ $1 = "-T" ] || [ $2 = "-t" ] || [ $2 = "-T" ]
        then
             let decimaltransparencia=$(shuf -i 30-125 -n 1)
            hexadecimaltransparencia=$(echo "ibase=10;obase=16;$decimaltransparencia" | bc)
            if [ `expr length $hexadecimaltransparencia` -lt 2 ]
            then
                hexadecimaltransparencia="0"$hexadecimaltransparencia
            fi
        fi
    fi


    hexadecimalrojo=$(echo "ibase=10;obase=16;$decimalrojo" | bc)
    if [ `expr length $hexadecimalrojo` -lt 2 ]
    then
        hexadecimalrojo="0"$hexadecimalrojo
    fi
    hexadecimalverde=$(echo "ibase=10;obase=16;$decimalverde" | bc)
    if [ `expr length $hexadecimalverde` -lt 2 ]
    then
        hexadecimalverde="0"$hexadecimalverde
    fi
    hexadecimalazul=$(echo "ibase=10;obase=16;$decimalazul" | bc)
    if [ `expr length $hexadecimalazul` -lt 2 ]
    then
        hexadecimalazul="0"$hexadecimalazul
    fi



    echo "#"$hexadecimalrojo$hexadecimalverde$hexadecimalazul$hexadecimaltransparencia

}

devuelvecolor R t

Publicado en Multimedia

Aquí traigo un truco sencillo que uso mucho y que puede ser de gran interés para otras personas que automaticen muchos procesos y quieren que parezca que no está todo automatizado. Para simular que algo está hecho a mano, pero realmente está automatizado es necesaria siempre una dosis de aleatoriedad.

Y una forma interesante de aleatorizar los procesos automáticos es seleccionar de forma aleatoria las funciones que realizan tareas.

Para ello necesitamos tener las funciones almacenadas en un fichero distinto al script que las ejecuta e invocarla a través de:

. $bibliotecafunciones
Y seleccionar la función a usar con:

funcionausar=$(grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//')

Con esto lo que hacemos es meter en la variable funcionausar el resultado de grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//'.

Veamos qué hace cada parte de esta línea:

grep function $bibliotecafunciones -> Busca la cadena de texto function en el fichero cuyo nombre está almacenado en la variable $bibliotecafunciones

cut -d " " -f 2 -> Extrae la segunda columna (-f 2) de la cadena que ha recibido siendo los separadores entre columnas el espacio en blanco (-d " ")

shuf -n1 -> Ordena aleatoriamente lo que ha recibido y extrae la primera línea

sed 's/()//' -> Cambia la cadena de texto () por otra cadena vacía, ya que entre las barras no hay nada (//).

Y ahora vamos a ver un ejemplo que no hace nada, pero ilustra lo que estoy comentando:

 

#!/bin/bash

# Recibe en bibliotecafunciones dónde se encuentras las funciones

bibliotecafunciones="lib/bibliotecafunciones.sh"

# Incluye el código del fichero almacenado en $bibliotecafunciones en este script

. $bibliotecafunciones

# Iniciarlizar las variables que usaremos como parámetros para la función seleccionada

let parametro1=1

let parametro2=2

let parametro3=3

 

# Selecciona aleatoriamente la función a usar

funcionausar=$(grep function $bibliotecafunciones | cut -d " " -f 2 | shuf -n1 | sed 's/()//')

# Uso de la función

resultadodelafuncion=$(eval $funcionausar $parametro1 $parametro2 $parametro3)

Y ahora vamos a ver la biblioteca:

function funcionuno()
{
    # Función que hace unas cosas
}

function funciondos()
{
    # Función que hace otras cosas
}

function funcionuno()
{
    # Función que hace cosas distinas
}

function funcionuno()
{
    # Función que hace algo... o no
}

Publicado en Programación

Para saber la duración de un vídeo en un script y usar esa información para tabajar con ella, podemos usar ffmpeg, avconf o un script de Gaspar Fernández disponible desde su web: https://poesiabinaria.net/2016/02/como-extraer-duracion-fotogramas-bitrate-y-fps-de-un-video-para-nuestros-scripts/

Y como en el script el autor indica claramente:

# Do whatever you want with this code.

Vamos a darle uso a esa libertad y usarlo para evolucionar su uso:

Almacenar la duración de un vídeo en una variable

Antes de nada, deberemos copiar al directorio de trabajo ese script y darle permisos de ejecución:

chmod + vinfo.sh

Con esto ya podremos invocarlo desde nuestros scripts y recoger la duración de los vídeos en variables:

duracion=$(./vinfo.sh duration $video)

Extraer algunos fotogramas por minuto de una serie de vídeos

Queremos hacer uno o más vídeos a partir de los brutos tomados en un evento, los típicos recursos que se utilizan mucho en las noticias, en los resúmenes de los eventos o para promocionar un evento a partir de los eventos anteriores. Y además, como nos encanta trabajar con ImageMagick queremos extraer fotogramas para luego meterle efectos y hacer más espectaculares esos clips.

Pues aquí tenemos una posible solución:

#!/bin/bash

# Script que recorre un directorio con brutos de vídeo
# Por cada minuto de duración del vídeo extrae de un punto aleatorio
# tres bloques de 200 fotogramas cada uno
# Guardará esos bloques en un nuevo directorio empaquetados en subdirectorios
# cuyo nombre será igual al nombre del bruto donde se ha extraído sin extensión

directoriooriginales="halloween"
directoriodestino="fotogramas-"$directoriooriginales

for i in $(ls $directoriooriginales)
do
    # Quita la extensión del nombre del fichero original
    # para que el directorio se llame igual
     # y tener así una referencia en caso de tener que volver a usar el original
    sinextension=${i%.*}

    # Calcula la duración del vídeo
    duracion=$(./vinfo.sh duration $directoriooriginales/$i)
    horas=${duracion:0:2}
    minutos=${duracion:3:2}

    # Extrae los fotogramas y almacénalos en directorios numerados
    # consecutivamente con el mismo nombre que el vídeo origina + numeral
    let numeral=1
    for min in $(seq 0 $minutos)
    do    
        for tercios in $(seq 1 3)
        do
            let seg=$(shuf -i 0-59 -n 1)
            mkdir $directoriodestino/$sinextension$numeral    
            
            ffmpeg -i $directoriooriginales"/"$i -ss 00:$min:$seg -vframes 200 $directoriodestino/$sinextension$numeral/captura%03d.png
            let numeral++

        done
    done
done

 

Otros usos de este script:

Buscar una canción que se ajuste al tamaño de un vídeo para usarla como banda sonora
Recortar una canción para que se ajuste a la duración de un vídeo
Crear una pista de vídeo a partir de una cartela que se ajuste a la duración de un podcast

Publicado en Multimedia

Ya sabemos cómo seleccionar aleatoriamente una tipografía para incluir texto en ImageMagick, pero nos puede ocurrir que, al ser aleatoria esa selección, nos elija una tipografía que sean dibujos, signos matemáticos o cualquier otra tipografía que no sea de letras, también nos puede mostrar una tipografía con un alfabeto distinto al nuestro o que no muestre bien algunos caracteres.

Yo siempre me fijo en cuatro caracteres clave: apertura de interrogación y exclamación, vocales con tilde y eñes.

Así pues, voy a usar una cadena de caracteres que tenga interrogaciones, una vocal con tilde y una eñe:

¿Leña? ¡Porrón!

Y como quiero ver qué tipografías que tengo instaladas en cada máquina muestran correctamente estos caracteres, hago los siguientes pasos:

  1. Utilizo un script que escribe la cadena "¿Leña? ¡Porrón!" con todas las tipografías instaladas en ese sistema.
  2. Compruebo las tipografías que muestran bien esos caracteres y además son legibles y cubren mis necesidades para escribir automáticamente sin miedo a que por automatizar se vea mal el texto. Y borro lo que me sobra.
  3. Un segundo script recoge las tipografías "supervivientes" que cumplen mis necesidades y genera una lista con esas tipografías
  4. Selecciono aleatoriamente de ese listado las tipografías para escribir en las imágenes

Script compruebatipografias.sh

#!/bin/bash

directoriotemporaltipografias="tipografias"

if [ ! -d directoriotemporaltipografias ]
then
    mkdir $directoriotemporaltipografias
fi

for tipografia in $(convert -list font | grep "Font" | cut -d " " -f 4)
do
    convert -pointsize 100 -font $tipografia label:"¿Leña? ¡Porrón!" $directoriotemporaltipografias/$tipografia.jpg
done

Veamos qué es lo que hace:

Indico que es un script en bash:

#!/bin/bash

Que el directorio con el que voy a trabajar se llama "tipografias", pero lo meto en una variable por si por cualquier motivo quiero cambiar de directorio:


directoriotemporaltipografias="tipografias"

 

Compruebo si existe o no ese directorio y si no existe, lo creo:
if [ ! -d directoriotemporaltipografias ]
then
    mkdir $directoriotemporaltipografias
fi

Hago un bucle en el que recorre todas las tipografías tal como vimos en el artículo anterior sobre tipografías en ImageMagick: y le digo que me genere una imagen por cada tipografía con la cadena antes indicada de "¿Leña? ¡Porrón!" guardando esas imágenes con el nombre de la tipografía utilizada en el directorio creado para tal efecto:
for tipografia in $(convert -list font | grep "Font" | cut -d " " -f 4)
do
    convert -pointsize 100 -font $tipografia label:"¿Leña? ¡Porrón!" $directoriotemporaltipografias/$tipografia.jpg
done

Selección manual de las tipografías

 

Con esto, tengo un directorio lleno de imágenes con cadenas de texto. Abro el directorio con un navegador de ficheros que muestre una previsualización de cada imagen y selecciono todas las imágenes que no me interesan por el motivo que sea, que generalmente es porque no escribe bien todos los caracteres indicados:

selecciondetipografias.png

 

Otras veces es porque, aunque muestre correctamente los caracteres, no me parecen lo suficientemente legibles o son muy específicos de una determinada fecha: navideños, de Hallowen, con nieve...

Una vez borrados los que en una primera ronda en bruto me han parecido que no cubren mis necesidades (ojo, que cuando seleccionamos aleatoriamente una tipografía es bastante arriesgado poner a trabajar ese script y desentendernos, por lo que es mejor que, en caso de duda, borrar el fichero), paso a una segunda fase en la que miro una por una las tipografías.

A veces nos encontramos que una tipografía escribe correctamente los caracteres pero no nos queremos arriesgar a que un script la seleccione sin nuestra aprobación:

Capacitor.jpgEdgewater.jpg

 

Estas tipografías muestran todos los caracteres, pero quizá no encajen en todos los contextos, por lo que las borro también.

 

 

Script listatipografias.sh

Y una vez que he borrado todo lo que sobra, ejecuto un segundo script:

#!/bin/bash

directoriotemporaltipografias="tipografias"

for fichero in $(ls $directoriotemporaltipografias)
do
    echo ${fichero%.*} >> tipografiasausar.txt
done

rm -r $directoriotemporaltipografias
rmdir $directoriotemporaltipografias

 

En el que le indico:

Que es un script bash:

#!/bin/bash

Que recoja los ficheros de un determinado directorio:
directoriotemporaltipografias="tipografias"

Que recorra ese directorio fichero a fichero y quite la extensión de esos ficheros ${fichero%.*} e incluya el nombre sin extensión en un fichero de texto llamado tipografiasausar.txt añadiendo en cada pasada de for cada tipografía al texto ya existente en ese fichero (>>)
for fichero in $(ls $directoriotemporaltipografias)
do
    echo ${fichero%.*} >> tipografiasausar.txt
done

Que borre el contenido de ese directorio y el propio directorio para que no ocupe espacio en disco ni moleste una vez hecha la selección.
rm -r $directoriotemporaltipografias
rmdir $directoriotemporaltipografias

 

Uso del fichero tipografiasausar.txt

Una vez creado el fichero tipografiasausar.txt para seleccionar aleatoriamente una línea de ese fichero lo podemos hacer con shuf. Así:

tipografia=$(shuf -n 1 tipografiasausar.txt)

 

Y así quedaría un script de ejemplo:

#!/bin/bash
tipografia=$(shuf -n 1 tipografiasausar.txt)
convert -pointsize 100 -fill Blue -font $tipografia label:"Automaticen\ny sean felices" automaticen.png

 

Publicado en Multimedia

En ImageMagick tenemos el parámetro -list que lista los valores que pueden recibir algunos parámetros.

Uno de los parámetros del que se puede listar los valores que puede recibir es font, que es el parámetro que permite seleccionar la tipografía con la que escribir un texto con annotate o label, así pues, si escribimos:

convert -list font

convert nos mostará las tipografías de nuestro sistema con una serie de datos más, como la familia, la dirección...

Font: Zoidal-BRK
    family: Zoidal BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zoidal.ttf
  Font: Zrnic
    family: Zrnic
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/larabie/zrnic___.ttf
  Font: Zurklez-Outline-BRK
    family: Zurklez Outline BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zurklezo.ttf
  Font: Zurklez-Solid-BRK
    family: Zurklez Solid BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zurklezs.ttf
  Font: Æ-Systematic-TT-BRK
    family: Æ Systematic TT BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/aesymatt.ttf
  Font: Ænigma-Scrawl-4-BRK
    family: Ænigma Scrawl 4 BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/aescrawl.ttf

 

Sin embargo, pese a que convert muestra toda esa información el nombre de la tipografía que vamos a usar a la hora de generar un texto con ImageMagick es el que sucede a "Font:". Así pues, si lo que queremos es saber el nombre con el que podremos invocar a las tipografías desde convert para añadir textos en nuestras imágenes o generar imágenes con texto, podremos listar únicamente esas líneas. Y aquí es donde llamamos a nuestro amigo grep:

convert -list font | grep Font

Font: Zakenstein-Rotalic
Font: Zekton
Font: Zekton-Bold
Font: Zekton-Bold-Italic
Font: Zekton-Dots
Font: Zekton-Italic
Font: Zelda-DX-TT-BRK
Font: Zenith-BRK
Font: Zephyrean-BRK
Font: Zephyrean-Gust-BRK
Font: Zero-Threes
Font: Zero-Twos
Font: Zero-Velocity-BRK
Font: ZeroHour
Font: Zirconia-BRK
Font: Zirconia-Cubic-BRK
Font: Zodillinstrisstirust
Font: Zoetrope-BRK
Font: Zoidal-BRK
Font: Zrnic
Font: Zurklez-Outline-BRK
Font: Zurklez-Solid-BRK
Font: Æ-Systematic-TT-BRK
Font: Ænigma-Scrawl-4-BRK


Otra fórmula sería extraer la columna donde están las cadenas de texto que contienen los nombres de las tipografías, el comando cut ayuda mucho en esta tarea:

convert -list font | grep Font | cut -d " " -f 4

Con estos parámetros le decimos a cut, que es un comando que "corta" cadenas, que el separador es un espacio en blanco con -d " ".

Del mismo modo, le podríamos indicar que el separador de columnas es cualqueir otro caracter o cadena de caracteres. El parámetro -f lo que indica es el número de la columna que ha de mostar, en este caso, la cuarta. Veamos:

Zekton
Zekton-Bold
Zekton-Bold-Italic
Zekton-Dots
Zekton-Italic
Zelda-DX-TT-BRK
Zenith-BRK Zephyrean-BRK
Zephyrean-Gust-BRK
Zero-Threes Zero-Twos
Zero-Velocity-BRK
ZeroHour Zirconia-BRK
Zirconia-Cubic-BRK
Zodillinstrisstirust
Zoetrope-BRK
Zoidal-BRK
Zrnic
Zurklez-Outline-BRK
Zurklez-Solid-BRK
Æ-Systematic-TT-BRK
Ænigma-Scrawl-4-BRK

Y ahora que ya tenemos el listado limpio, únicamente tenemos que elegir una cadena al azar. Lo podemos hacer con shuf:
convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1
Intersect-O-BRK

Y si lo probamos muchas veces, veremos que el resultado es aleatorio, por lo que cada vez que ejecutemos esa instrucción será distinta:

tipografiaaleatoria.png

 

Y dentro de un script, el uso sería igual:

#!/bin/bash

tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)

echo "La tipografía seleccionada de forma aleatoria ha salido: "$tipografia

Veamos si así funciona:

tipografiaaleatoria.png

 

Como vemos, cada vez que ejecutamos el script nos muestra una tipografía distinta.

Y ahora, vamos a usarlo con ImageMagick para generar una imagen con una tipografía aleatoria:

#!/bin/bash

tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)

convert -pointsize 100 -font $tipografia label:"Disfruten del\nSoftware Libre" disfruten.png

disfruten.png

 

Y vamos a hacer un for para comprobar que realmente genera imágenes con distintas tipografías:

#!/bin/bash

for i in $(seq 1 3)
do
    tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)
    convert -pointsize 100 -font $tipografia label:"Disfruten del\nSoftware Libre" disfruten$i.png
done


disfruten1.pngdisfruten3.pngdisfruten2.png

Vista la forma básica de generar textos con tipografías aleatorias, veremos también cómo hacer una selección previa de las tipografías para usar aquellas tipografías que se ajusten a nuestras necesidades.

Publicado en Multimedia
Miércoles, 12 Septiembre 2018 20:31

Generar números aleatoriamente con shuf

Ya hemos visto que, dado que %$valor lo que hace es calcular el resto de la división entre la cifra que precede a % (dividendo) y la cifra que sucede a % (divisor), $RANDOM%limitesuperior no vale para generar números aleatorios de forma fideligna (a no ser que seamos trileros, pero en este caso no buscamos una verdadera aleatoriedad).

También hemos visto que shuf sí que sirve para crear órdenes aleatorios. Y ahora vamos a ver cómo usar shuf para generar números aleatorios.

Lanzamiento a cara o cruz de una moneda (aleatoriedad entre dos valores)

Veamos cómo usar shuf en el primer ejemplo que usé en contra de $RANDOM: una aleatoriedad dos valores. Pero antes de ello, vuelvo a remarcar que shuf no genera nada, sino que hace un orden aleatorio de una lista. Así que primero hay que generar una lista y luego ordenar aleatoriamente con shuf.

¿Qué formas podemos generar una lista?

Veamos varias formas de hacerlo:

En un fichero auxiliar:

#/bin/bash

let comienzo=0
let final=1

for i in $(seq $comienzo $final)
do
    echo $i >> numeros.txt
done

Y ahora podemos ejecutarlo y luego ordenar con shuf. Veamos a ver si la aleatoriedad es tal:

 

En este pantallazo vemos que de 12 tiradas, han salido siete veces 0 y cinco veces 1. Está dentro de la normalidad. Pero vamos a ver qué ocurre si tiramos mil veces la moneda:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    let moneda=$(shuf -n1 numeros.txt)
    if [ $moneda -eq 0 ]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

Y lo comprobamos (vuelvo a poner pantallazo para que se vea que no hay trampa ni cartón):

comprobacionconfichero.png

 

¡Incluso me ha llegado a dar un empate de 500 a 500!

Visto que shuf es más válido en este caso, vamos a ver cómo generar una lista aleatoria con shuf. Compruebo en el mismo script para evitar hacer un artículo excesivamente largo:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    numeros=$(shuf -i 0-1)    
    if [[ ${numeros:0:1} == "0" ]]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

listaconshuf.png

 

Funciona... y de nuevo hemos tenido un empate a 500 en una tirada.

Pero ahora te puedes preguntar, por qué si existe el parámetro -i en shuf para generar una lista con orden aleatorio y el parámetro -n para extraer un número determinado de elementos, ¿por qué no lo usas en la misma línea?

No te falta razón para pensarlo, pero quería mostrar distintas formas de lanzar la moneda. Y hacer un artículo evolutivo que acabase con la mejor opción:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    numeros=$(shuf -i 0-1 -n 1)    
    if [[ $numeros == "0" ]]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

listaconshufin.png

Y vuelve a funcionar... incluso me ha dado otro empate a 500.

¿Y si en lugar de tirar a cara o cruz hacemos un rango mayor, por ejemplo de 0 a 1000?

Simplemente le cambiamos el rango en -i. Y si además, para comprobar si funciona, vamos a aumentar el número de tiradas.

#/bin/bash

let ceros=0
let quinientos=0
let miles=0

for i in $(seq 1 10000)
do
    numeros=$(shuf -i 0-1000 -n 1)    
    if [[ $numeros == "0" ]]
    then
        let ceros++
    elif [[ $numeros == "500" ]]
    then
        let quinientos++
    elif [[ $numeros == "1000" ]]
    then
        let miles++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de quinientos que ha salido es: "$quinientos
echo "El número de miles que ha salido es: "$miles

Y al probarlo, da unos resultados tales como:

 

 

delunoalmil.png

 

Que son unos resultados que son totalmente coherentes dentro de lo que es la aleatoriedad por lo que podemos decir que la mejor forma para generar un número aleatorio en Bash es

shuf -i $limiteinferior-$limitesuperior -n 1

Publicado en Programación
Miércoles, 12 Septiembre 2018 00:02

Aleatoriedad con shuf

En tres artículos he estado argumentando en contra del uso de $RANDOM para generar números aleatorios:

El mito de $((RANDOM%$limitesuperior))
Más sobre la "aleatoriedad" de $RANDOM
Dados cargados en $RANDOM

Pero es poco honesto criticar algo sin aportar una solución, así que aquí voy a explicar el uso de shuf y en otro artículo explicaré varias formas de usar shuf para generar números aleatorios.

El uso de shuf

shuf se puede usar para ordenar aleatoriamente un fichero de texto:

shuf fichero.txt

shuf.png

Como vemos al usar cat, las palabras de fichero.txt tenían un orden que, al usar shuf, han cambiado de orden.

También shuf permite seleccionar X elementos de una lista. Ya lo hemos usado otras veces, como al elegir aleatoriamente una tipografía o un color con ImageMagick. Pero veamos con el ejemplo anterior:

shuf -n2 fichero

Con el parámetro -n$numerodelineas muestra el número de líneas incado como valor a -n.

Otra forma de usar shuf es recibiendo una lista desde la salida de otro fichero.

Veamos un ejemplo creando una serie de ficheros en un directorio y luego seleccionando uno al azar recogiendo con shuf la salida de ls.

 

Otro parámetro muy interesante es -o para especificar un fichero donde guardar la salida de shuf. Evolucionemos la instrucción anterior:

ls | shuf -o ordenaleatorio.txt

Publicado en Programación

Ahora que ya sabemos crear lienzos con textos y añadir textos a imágenes con ImageMagick, vamos a evolucionar nuestros scripts y nuestros diseños trabajando con las tipografías.

Listar las tipografías instaladas

Para listar las fipografías que tenemos en nuestro sistema, podemos usar el parámetro -list de ImageMagick:

convert -list font

Esto nos dará un listado enorme de tipografías e información sobre ellas, así que si queremos verlas una a una hemos de filtrar la salida del comando. Por ejemplo, podremos ver todo el listado y movernos por él con

convert -list font | less

pantallazofont.png

Saber el número de tipografías instaladas

Como vemos en el anterior, al listar las tipografías, convert muestra el fichero que lee al listar las tipografías (/etc/ImageMagick-6/type-ghostscript.xml). Pero no es el único fichero xml de donde puede leer, sino de todos los /etc/ImageMagick-6/type-*. Y luego muestra seis líneas por tipografía.

Así pues, si queremos saber cuántas tipografías tenemos instaladas, podemos usar un pequeño script que nos reste las líneas que no nos interesa y el resultado dividirlo entre seis (es una opción tan válida como cualquier otra) u optimizar el esfuerzo escribiendo:

convert -list font | grep "Font:" | wc -l

Listar las tipografías limpias

Ahora que ya sabemos con cuántas tipografías distintas podemos trabajar, vamos a listarlas limpias, ya que con convert -list font | grep "Font:" lo que nos mostaría sería las línas con este formato:

  Font: Zero-Twos
  Font: Zero-Velocity-BRK
  Font: ZeroHour
  Font: Zirconia-BRK
  Font: Zirconia-Cubic-BRK
  Font: Zodillinstrisstirust
  Font: Zoetrope-BRK
  Font: Zoidal-BRK
  Font: Zrnic
  Font: Zurklez-Outline-BRK
  Font: Zurklez-Solid-BRK
  Font: Æ-Systematic-TT-BRK
  Font: Ænigma-Scrawl-4-BRK

Lo cual, a modo orientativo, nos puede servir si queremos leerlas con nuestros ojos, pero si queremos usarlas en un script no nos vale como argumento de -font. Para limpiarlo, le decimos que queremos la segunda columna de ese resultado y que la separación es " " con cut -f 2 -d ":" (recordemos que con cut sólo podemos indicar un único carácter de separación, así que no podemos indicarque que el separador sea  ": ". Nos devuelve algo parecido (dependiendo de las tipografías que tengamos en cada sitema) a esto:

 Zero-Threes
 Zero-Twos
 Zero-Velocity-BRK
 ZeroHour
 Zirconia-BRK
 Zirconia-Cubic-BRK
 Zodillinstrisstirust
 Zoetrope-BRK
 Zoidal-BRK
 Zrnic
 Zurklez-Outline-BRK
 Zurklez-Solid-BRK
 Æ-Systematic-TT-BRK
 Ænigma-Scrawl-4-BRK

Vaya, tal como sospechaba, al no poder indicarle que el separador es ": ", me deja un espacio en blanco. Bueno, cualquier problema es relativo si tenemos amigos que nos ayuden a solucionarlos. Y en GNU/Linux tenemos un amigo que se llama sed que nos puede ayudar a limpiar estas cadenas:

convert -list font | grep "Font:" | cut -d ":" -f 2 | sed 's/ //g'

Zero-Twos
Zero-Velocity-BRK
ZeroHour
Zirconia-BRK
Zirconia-Cubic-BRK
Zodillinstrisstirust
Zoetrope-BRK
Zoidal-BRK
Zrnic
Zurklez-Outline-BRK
Zurklez-Solid-BRK
Æ-Systematic-TT-BRK
Ænigma-Scrawl-4-BRK

Seleccionar una tipografía aleatoria

Ya he conseguido las cadenas limpias. con las tipografías a utilizar. Pero no sé cuál de ellas usar, así que dejaré que sea shuf quien elija alguna al azar:

convert -list font | grep "Font:" | cut -d ":" -f 2 | sed 's/ //g' | shuf -n1

Con esta instrucción conseguimos que de forma aleatoria nos diga una única tipografía.

Y para verlo claramente, vamos a hacer un script de ejemplo:

#!/bin/bash

for i in $(seq 1 5)
do
    tipografia=$(convert -list font | grep "Font:" | cut -d ":" -f 2 | sed 's/ //g' | shuf -n1
)
    convert -size 500x200 -background CadetBlue -font $tipografia -pointsize 45 -gravity Center label:"Linux Center" cartelalinuxcenter$i.png
done

Y el resultado (cambiará cada vez que lo ejecutéis):

 

Publicado en Multimedia

Ya hemos visto cómo dividir horizontal y verticalmente en partes iguales una imagen, pero, ¿y si queremos hacer la dividisión únicamente en un eje?

Se lo indicaremos a crop con el porcentaje seguido de x100% si queremos que los cortes sean verticales o con 100%x seguido del porcentaje si queremos que la división sea horizontal. Así:

convert $origen -crop 50%x100% $corteshorizontales
convert $origen -crop 100%x50% $cortesverticales

Veamos un ejemplo: supongamos que queremos desordenar aleatoriamente una imagen en 10 franjas verticales.

Para pasar de:

guarderia_calle_Reino.jpg

A esto (o parecido, porque al ser aleatorio, cada vez que ejecutemos el script nos generará una imagen distinta): 

guarderia_desordenada.jpg

Veamos el script:

 

 

#!/bin/bash

origen="guarderia_calle_Reino.jpg"
destino="guarderia_desordenada.jpg"
ordendeimagenes=""

convert $origen -crop 10%x100% temporales%d.jpg

numerosaleatorios=$(shuf -i 0-9)

for i in $(seq 1 10)
do
      posicion=$(echo $numerosaleatorios | cut -d " " -f $i)
      ordendeimagenes="temporales"$posicion".jpg "$ordendeimagenes
done

convert $ordendeimagenes +append $destino

Explicación del script

Como siempre, vamos a ver paso a paso qué hemos hecho en este script:

#!/bin/bash -> Para indicar el shell que queremos usar
Después, las variables que vamos a utilizar. No me cansaré de repetir que ser ordenados ayuda a mantener y mejorar nuestros scripts, así como que otras personas puedan adaptarlos a sus necesidades. 
convert $origen -crop 10%x100% temporales%d.jpg -> dividimos en recortes iguales de un tamaño del 10% horizontalmente y un 100% vertical de la imagen original 
numerosaleatorios=$(shuf -i 0-9) -> Creamos una variable que contenga una serie de números del 0 al 9 (indicamos el rango con -i 0-9) ordenados aleatoriamente (shuf desordena)
Después recorremos esa variable con un for que irá del 1 al 10 ya que cut empieza a contar desde el 1, mientras que las imágenes creadas con -crop empiezan en 0.
Con posicion=$(echo $numerosaleatorios | cut -d " " -f $i) recortamos el listado anterior indicando que las partes a recortar están separadas con un espacio en blanco (indicado con -d " ") y que cada vez que pasa por el for muestre la columna correspondiente (indicado con -f $i) recordando que cut comienza a contar por 1.
Concatenamos los nombres de los ficheros a unir con       ordendeimagenes="temporales"$posicion".jpg "$ordendeimagenes. Lo que hacemos es añadir a una cadena de texto que hemos inicializado al comienzo como una cadena vacía (ordendeimagenes="") los ficheros con el patrón fijo que hemos indicado al hacer el recorte ("temporales"), la posición de la imagen que hemos extraido de la cadena aleatoria ($posicion) y la extensión seguida de un espacio (".jpg ") para que entre los nombres de los ficheros haya un espacio en blanco que permita que al unirlos después, lo entienda como ficheros distintos. 
Y, por último, concatenamos esos ficheros horizontalmente con +append. (Para concatenarlos verticalmente sería con -append). 

Publicado en Multimedia
Jueves, 02 Agosto 2018 20:35

Los colores predefinidos en ImageMagick

ImageMagick cuenta con una serie de colores predefinidos a los que podemos llamar por su nombre en lugar de por su código hexadecimal. Es más cómodo invocarlos por su nombre, aunque es más preciso hacerlo por su código. Así que cada uno que elija lo que más le interese, aunque en este artículo nos vamos a centrar en los colores preestablecidos y cómo sacarle partido a este listado. 

Saber los colores predefinidos con los que podemos trabajar

Para poder listar en ImageMagick está el parámetro -list. 

convert -list $listaamostrar

Nos mostrará la lista que le pidamos. En este caso, le pediremos que liste los colores:

convert -list color

Y nos mostrará el listado de colores. En mi caso:

$ convert -list color | wc -l$ convert -list color | wc -l
683

Me dice que tengo 683 colores predefinidos. Con wc -l le he pedido que me diga únicamente las líneas del listado, no el listado en sí, y así sé el número de colores que tengo. 

Saber los tonos de un determinado color

Si quiero saber los distintos colores predefinidos basados en un determinado color, lo que puedo hacer es redirigir la salida del listado a un grep e indicarle el patrón. Veamos cómo listar las tonalidades de rojo que tengo:

convert -list color | grep Redconvert -list color | grep Red
DarkRed               srgb(139,0,0)                                 SVG X11 
IndianRed             srgb(205,92,92)                               SVG X11 XPM 
IndianRed1            srgb(255,106,106)                             X11 
IndianRed2            srgb(238,99,99)                               X11 
IndianRed3            srgb(205,85,85)                               X11 
IndianRed4            srgb(139,58,58)                               X11 
MediumVioletRed       srgb(199,21,133)                              SVG X11 XPM 
OrangeRed             srgb(255,69,0)                                SVG X11 XPM 
OrangeRed1            srgb(255,69,0)                                X11 
OrangeRed2            srgb(238,64,0)                                X11 
OrangeRed3            srgb(205,55,0)                                X11 
OrangeRed4            srgb(139,37,0)                                X11 
PaleVioletRed         srgb(219,112,147)                             SVG X11 XPM 
PaleVioletRed1        srgb(255,130,171)                             X11 
PaleVioletRed2        srgb(238,121,159)                             X11 
PaleVioletRed3        srgb(205,104,137)                             X11 
PaleVioletRed4        srgb(139,71,93)                               X11 
VioletRed             srgb(208,32,144)                              X11 XPM 
VioletRed1            srgb(255,62,150)                              X11 
VioletRed2            srgb(238,58,140)                              X11 
VioletRed3            srgb(205,50,120)                              X11 
VioletRed4            srgb(139,34,82)                               X11

Pero vemos que esto es un listado con tres columnas y que me da más información que la que voy a usar a la hora de invocar un color, ya que para esto, utilizaré únicamente el nombre. Así que limpiaré el listado y me quedaré con la primera columna que es la que me interesa: 

convert -list color | grep Red | cut -f 1 -d " "
DarkRed
IndianRed
IndianRed1
IndianRed2
IndianRed3
IndianRed4
MediumVioletRed
OrangeRed
OrangeRed1
OrangeRed2
OrangeRed3
OrangeRed4
PaleVioletRed
PaleVioletRed1
PaleVioletRed2
PaleVioletRed3
PaleVioletRed4
VioletRed
VioletRed1
VioletRed2
VioletRed3
VioletRed4

Así ya podemos ver el listado limpio y podemos trabajar con esos valores

Recorrer el listado de colores

En muchas ocasiones nos interesa utilizar distintos tonos de un color, por ejemplo, para dar ir cambiando la tonalidad de una imagen. Para ello, una vez que tenemos el listado limpio, únicamente tenemos que recorrerlo con un for:


function hazlienzosdecolor()

{
     for i in $(convert -list color | grep Red | cut -f 1 -d " ")
     do
          #Instrucciones
     done
}

Supongamos que queremos hacer una serie de lienzos de un tamaño determinado basados en un color que le pasemos como parámetro. Podríamos hacer un script como este:

 

 

#!/bin/bash

tamlienzo="200x100"
let numlienzo=0

function hazlienzosdecolor()
{
     if [ $1 ] && [ "$(convert -list color | grep $1 | cut -f 1 -d " ")" ]
     then
          for i in $(convert -list color | grep $1 | cut -f 1 -d " ")
          do
               destino="lienzo"$1$numlienzo".png"
               convert -size $tamlienzo xc:$i $destino
               let numlienzo++
           done
      fi
}

hazlienzosdecolor $1

Y al ejecutarlo, genera:

./hazlienzosdecolor Orange

lienzoOrange0.pnglienzoOrange9.pnglienzoOrange8.pnglienzoOrange7.pnglienzoOrange6.pnglienzoOrange5.pnglienzoOrange4.pnglienzoOrange3.pnglienzoOrange2.pnglienzoOrange1.png

 

Qué hemos hecho en este script:

Primero indicamos las variables, de esta forma, si queremos modificarlas en cualquier momento, las tenemos localizadas a simple vista

Después le decimos que si al ejecutarse el script recibe un parámetro ([ $1 ]), y además (&&) este es un color válido ([ "$(convert -list color | grep $1 | cut -f 1 -d " ")" ]) ejecute estas órdenes:

for i in $(convert -list color | grep $1 | cut -f 1 -d " ")-> Recorre el listado de los colores que contengan el valor indicado en el primer parámetro y únicamente el primer campo del listado

destino="lienzo"$1$numlienzo".png" -> Da valor a la variable destino con una cadena de texto, en este caso el patrón "lienzo", luego el nombre el color que ha indicado el usuario, el número que corresponde a ese lienzo y la extensión ".png"

convert -size $tamlienzo xc:$i $destino -> Genera el lienzo

let numlienzo++ -> Suma uno a la variable numlienzo para que el siguiente lienzo a crear tenga el próximo número correlativo.

Seleccionar un color de forma aleatoria

Para seleccionar un color aleatorio, no le indicaremos un patrón (quitamos el grep $1) y lo que tenemos que indicarle al listado generado es que lo desordene y muestre sólo un color, que se lo indicaremos con shuf -n 1:
convert -list color | cut -f 1 -d " " | shuf -n 1

Y si lo queremos usar en un script para que una variable recoja ese color aleatorio, podemos hacer:

  

#!/bin/bash

function coloraleatorio()
{
          color=$(convert -list color | cut -f 1 -d " " | shuf -n 1)
          echo $color
}

color=$(coloraleatorio)

echo $color

Puede parecer excesivo hacer una función para algo tan sencillo, pero cuando estás generando muchos colores aleatorios al cabo del día, se agradece tener funciones creadas ;)

Publicado en Multimedia

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí