lunes, 4 de julio de 2016

Color Images to Bitonal (BinarizeBradley Algorithm)

Recientemente tuve que implementar una algoritmo para convertir imágenes en colores a blanco y negro (bitonal). El framework AForge.net tiene una librería muy completa para procesamiento de imágenes, sin embargo, está bajo licencia LGPLv3 y no siempre podemos hacer uso de ella en todos los proyectos.

Dejo un enlace a mi propia implementación del algoritmo BinarizeBradley bajo licencia MIT.

El código es una implementación en C# del algoritmo descrito en el siguiente Paper: Adaptive Thresholding Using the Integral Image by Derek Bradley and Gerhard Roth.

Algunas imágenes de prueba:





miércoles, 11 de febrero de 2015

Consultas jerárquicas ordenadas (T-SQL)

Los datos jerárquicos usualmente se almacenan en tablas que contienen referencias recursivas como se muestra en la imagen:


Esta estructura permite almacenar datos jerárquicos, por ejemplo, como han derivado unas distribuciones GNU/Linux de otras.

Id Nombre IdPadre
1 Debian NULL
2 Knoppix 1
3 Ubuntu 1
4 Lindows 1
5 Corel 1
6 Damn Small Linux 2
7 KnoppMyth 2
8 Mint 3
9 Kubuntu 3
10 Xubuntu 3
11 Ulteo 9
12 Redhat NULL
13 Mandrake 12

Si queremos consultar todos los registros de distribuciones basadas en Debian, podemos recurrir a una consulta utilizando la sintaxis CTE (Common Table Expression, SQL Server 2005+) como sigue:

WITH cte
     AS (SELECT A.id, A.idpadre, A.nombre
         FROM   tabla1 A
         WHERE  A.id = 1 --Iniciar con Debian
         UNION ALL
         SELECT B.id, B.idpadre, B.nombre
         FROM   tabla1 B
                INNER JOIN cte C ON B.idpadre = C.id
         WHERE  B.idpadre IS NOT NULL)
SELECT *
FROM   cte 


Esta consulta devolverá los datos en el orden en que los va recuperando. Si quisiéramos que los datos aparezcan ordenados según la jerarquía, deberemos considerar una columna adicional en la consulta que corresponda a la ruta completa desde el registro raíz (Debian) hasta cada registro.

WITH cte
     AS (SELECT A.id, A.idpadre, A.nombre,
                Cast(A.id AS VARCHAR) ruta
         FROM   tabla1 A
         WHERE  A.id = 1 --Iniciar con Debian
         UNION ALL
         SELECT B.id, B.idpadre, B.nombre,
                Cast(C.ruta + '-' + Cast(B.id AS VARCHAR) AS VARCHAR)
         FROM   tabla1 B
                INNER JOIN cte C ON B.idpadre = C.id
         WHERE  B.idpadre IS NOT NULL)
SELECT *
FROM   cte
ORDER  BY ruta ASC; 


La columna Ruta actuará como un "acumulador" de todos los IDs que han de considerarse para llegar desde el registro raíz (Debian) hasta el registro destino.

En el ejemplo, la ruta correspondiente a Ulteo es 1-3-9-11.


miércoles, 21 de enero de 2015

Variables persistentes (.NET)

Desarrollando una pequeña aplicación (Windows Service), me topé con la necesidad de mantener una variable de conteo cuyo valor fuera persistente aún después de reiniciar el servicio.

Si no se dispone de una base de datos o su uso es inapropiado (requiere crear en la base de datos una nueva tabla o campo que no deseamos), se puede pensar en almacenar la información en archivos de texto. En ambos casos es requerido agregar otras librerías al programa e implementar los métodos necesarios para gestionar el almacenamiento y recuperación del dato.

Una buena alternativa es el uso de los user-settings de la aplicación, es posible utilizarlos como variables en tiempo de ejecución y preservar su valor aún después de reiniciar el servicio o aplicación.

Para crear una variable de este tipo, se puede acceder a las propiedades del proyecto desde el Solution Explorer (Visual Studio). Posteriormente, en el apartado de Settings, se agrega una entrada especificando el nombre de la variable, el tipo y el ambito (establecido a nivel de usuario).




















El siguiente código muestra cómo manipular esta variable:

 //Establecer un valor  
 Properties.Settings.Default.ItemCounter = anyIntValue;  
 //Recuperar un valor  
 anyIntValue = Properties.Settings.Default.ItemCounter;  
 //Almacenar el valor de forma persistente  
 Properties.Settings.Default.Save();  


Saludos!

miércoles, 13 de agosto de 2014

Texto a Voz + SRT

Text to Speech + Subrip Subtitle

Algunas veces me gusta leer y al mismo tiempo escuchar lo que leo. Esto me permite llevar un ritmo constante y lograr mayor concentración en la lectura.

El otro día quise subir un texto a Youtube, sintetizado con una voz Loquendo y con subtítulos, de modo que desde Youtube el lector pudiera escuchar y al mismo tiempo leer la transcripción. Procedí a sintetizar el texto a voz utilizando SodelsCot Estándar y la voz de Loquendo Ximena. SodelsCot convierte a un archivo de audio el texto copiado al portapapeles y Youtube tiene una función que permite cargar la transcripción en formato de texto y convertirla a subtítulos en el video. Pero tanto SodelsCot como Youtube han presentado algunos inconvenientes:

  • Si el texto es muy grande, SodelsCot falla en el proceso de conversión de Texto a Voz.
  • Durante la conversión, prácticamente no se puede usar el portapapeles para otra cosa, ya que interfiere con el archivo de audio generado o crea archivos de más.
  • SodelsCot solamente permite convertir un texto a audio a la vez.
  • Si el texto es relativamente grande, Youtube demora muchas horas en procesar la transcripción.
  • Youtube falla frecuentemente, mostrando un mensaje de error en el procesamiento de la transcripción.
Con tanta "fricción cognitiva", pensé que sería mejor escribir un pequeño programa de uso personal que permita realizar lo siguiente:
  1. Recibir como entrada un archivo de texto plano.
  2. Generar 2 archivos, uno de audio (mp3 o wav) y un SRT con los subtítulos correspondientes.

SubTTS

SubTTS es el nombre con el que bauticé al programa. Por ahora es una aplicación de consola parametrizable por medio de un archivo de configuración.

SubTTS fue escrito en C# sobre .Net Framework 4.


Utilizando SubTTS

  1. Lo primero es descargar el programa aquí. Para descomprimir el RAR utiliza WinRAR y la clave: cristiandlr.blogspot.com
  2. Una vez descomprimido, ejecutar TTSub.exe para comprobar el listado de voces instaladas. Presionar Ctrl + C para salir del programa.
  3. Editar el archivo de configuración TTSub.exe.config y establecer los siguientes parámetros:
    • PathToText. Ruta completa al archivo de texto que se procesará.
    • WordsPerSub. Número de palabras por cada subtítulo.
    • VoiceName. Una de las voces instaladas (listadas en el paso 2).
    • VoiceRate. Velocidad de lectura, los valores oscilan entre -10 y 10.
    • OutputFormat. WAV o MP3.
  4. Una vez guardada la configuración, ejecutar nuevamente TTSub.exe, pero esta vez presionamos Enter para continuar luego de ver las voces instaladas.
  5. La ventana se cerrará sola al finalizar el trabajo y los archivos resultantes (wav y srt) quedan en la misma carpeta donde está el archivo de texto.

Qué hacer con los archivos?

Por ahora SubTTS es una herramienta que cumple una tarea muy simple. Por sí mismos los archivos de audio (wav o mp3) y srt (subrip subtitle) no pueden utilizarse juntos en un reproductor de audio convencional. El archivo de audio debe ser codificado en un formato de video (mp4, wmv, etc.) para que el reproductor cargue y despliegue los subtítulos. Se puede utilizar una herramienta como Windows Movie Maker para crear un video.

Licenciamiento

El programa es de uso libre para cualquier fin.

2016 11 25 Actualización: He publicado el código fuente en github.

martes, 30 de abril de 2013

Application pools y Web gardens (IIS / APS.NET)

Cuando se tienen varias aplicaciones ASP.NET corriendo sobre un servidor IIS, resulta conveniente crear pools diferentes para aquellas aplicaciones que tengan una demanda considerable.

Un pool de aplicaciones es una forma de agrupar una o más aplicaciones web bajo el dominio de un proceso (o un conjunto de procesos) denominado Worker Process.

Al asociar una aplicación a ese pool, IIS creará una (o más) instancia(s) del Worker Process para cada pool. En caso de que ocurra un fallo en una aplicación que provoque la finalización del Worker Process asociado al pool al que pertenece, otras aplicaciones asociadas a otros pools permanecerán funcionando sin problemas.

Cuando un pool de aplicaciones está controlado por más de una instancia del Worker Process se denomina Web Garden. El número de instancias del web garden es configurable en las propiedades del pool de aplicaciones.

Se debe tomar en cuenta que si la aplicación utiliza variables de sesión no funcionará con Web Gardens, ya que tales variables solo existen dentro del contexto de un único Worker Process.

Configurar un Pool de aplicaciones

Para administrar los pools de aplicaciones, se debe iniciar la interfaz de administración de IIS ejecutando el siguiente comando:

%SystemRoot%\system32\inetsrv\iis.msc

IIS 6

1. En la sección de Application Pools, se pueden crear nuevos pools, haciendo clic derecho sobre la misma, luego en la opción New, seleccionar Application Pool (ver imagen 2)... Para este ejemplo dejaremos los valores por defecto (ver imagen 1).

Imagen 1

2. En el directorio virtual, donde está la aplicación objetivo, clic derecho y elegir Properties. Se mostrará la ventana de propiedades de dicha aplicación. (ver imagen 2)

3. En el combo de Application Pool, se puede seleccionar el pool creado en el paso 1. (ver imagen 2)

Imagen 2

4. Para configurar el número máximo de instancias del Worker Process, presione clic derecho sobre el pool de aplicaciones, elija Properties y vaya a la pestaña Performance. En la sección Web garden, establezca el máximo número de procesos.

Imagen 3

IIS 7

1. Para crear un pool: Presione clic derecho en la sección de Application Pools y elija Add new application pool (imagen 4). Establezca un nombre para el mismo y presione la tecla Enter (imagen 5).

Imagen 4

Imagen 5

2. Para agregar una aplicación al pool creado, vaya a la aplicación o sitio web, haga clic derecho y elija Administrar sitio web / Configuración avanzada (imagen 6). Luego en la propiedad de Grupo de aplicaciones (Application pool) elija el que se creó en el paso anterior (imagen 7).

Imagen 6


Imagen 7

3. Para configurar el Web Garden para el pool creado, vaya al pool de aplicaciones (Sección Grupos de aplicaciones), haga clic derecho sobre el mismo y elija Configuración avanzada. Establezca la propiedad Maximum number of worker processes (Máximo de procesos de trabajo). Ver imagen 8.

Imagen 8