Mostrando entradas con la etiqueta Pillow. Mostrar todas las entradas
Mostrando entradas con la etiqueta Pillow. Mostrar todas las entradas

martes, 21 de octubre de 2025

MAV. Python.

Pillow

Matriz a partir de imagen


En la [entrada anterior] creamos una imagen a partir de los datos de una matriz. Ahora haremos el proceso inverso: obtener los datos numéricos que definen una imagen dada, lo que equivale a generar una matriz a partir de esos datos.

 

Lo interesante de lo que estamos haciendo es que podemos trabajar con datos numéricos para crear imágenes y viceversa: obtener los datos numéricos de los que se compone una imagen digitalizada. A partir de esto podemos realizar manipulaciones generales o específicas del color y, a partir de éste, también del dibujo y de las formas que conforman la imagen.

En el script que sigue obtenemos la matriz de datos de una imagen dada y, partiendo de ésta, volvemos a construir la imagen, en este caso, sin modificación alguna respecto a la original.

from PIL import Image
import numpy as np

#Cargar imagen

img_dir = 'img/Paisaje.jpg'
img = Image.open(img_dir)

#Visualizamos la imagen cargada

img.show()

#Convertimos la imagen en matriz

array_img = np.array(img)

#Visualizamos la matriz

print(array_img)

#Convertimos de nuevo la matriz en imagen

img_array = Image.fromarray(array_img)

#Visualizamos la imagen creada

img_array.show()

Para ello ha sido suficiente con importar ambas bibliotecas (Pillow y NumPy) y usar dos funciones específicas, una asociada a Numpy (array_img = np.array(img)) y otra a Pillow (img_array = Image.fromarray(array_img)). La primera para convertir la imagen en una matriz y la segunda para invertir el procedimiento.

A partir de aquí se nos abren todas las opciones que derivan del trabajo con matrices numéricas. Todo un mundo.


sábado, 18 de octubre de 2025

MAV. Python.

Pillow

Filtros


Avanzando en el manejo de imágenes trataré en esta entrada sobre una forma compleja de modificarlas. Me refiero al uso de filtros. Trataremos algunos de ellos mediante el módulo ImageFilter.



Un filtro de imágenes es el procesamiento de la imagen para su mejora o modificación, a fin de resultar cierto contenido o mejorar los valores de la imagen desde diferentes perspectivas (luminosidad, modificación del color, nitidez...).

El uso de filtros nos interesa, pues, por los efectos técnicos y artísticos de los mismos, pero también (y es lo que aquí nos trae) por motivos relativos al propio procesamiento, digamos que como preparación previa para posteriores desarrollos, como el reconocimiento automatizado de cierto contenido en las imágenes.

No obstante, en estos momentos nos limitaremos a explicar un número determinado (y limitado) de filtros y mostrar sus efectos. Se trata, pues, de completar la colección de herramientas que hemos ido viendo en entradas precedentes. Además nos sirve de enlace con la temática que desarrollaremos posteriormente, la cual, aunque no hablemos de ella ahora, es la que posibilita los procedimientos que trataremos.

El primer paso para aplicar filtros es importar los módulos...

from PIL import Image, ImageFilter

... y cargar la imagen (vg)...

#Directorio de la imagen
img_dir = 'img/cuadro.png'

#Imagen original
img = Image.open(img_dir)

... la cual, por motivos didácticos, nos interesa ahora que sea compleja y de calidad. En todo caso, el efecto de algunos filtros es fácilmente detectable, pero el de otros no lo es o depende de las características de la imagen original; por eso te recomiendo que pruebes con diferentes imágenes.

Por otra parte, la sintaxis es muy simple:  función filter() aplicada a la variable asociada al archivo (vg. img.filter()) que contiene como parámetro la clase ImageFilter seguida del atributo NOMBRE_DEL_FILTRO, todo ello asociado a una nueva variable (img_FiltroX = img.filter(ImageFilter.CONTOUR)).

Te dejo a continuación el script con los filtros de mayor interés del módulo ImageFilter, aunque sobre eso hay opiniones. El código de cada filtro está comentado (por eso lo dejo en tinta negra) para que puedas activarlos (y visualizarlos) de forma sucesiva.

from PIL import Image, ImageFilter

#Directorio de la imagen
img_dir = 'img/formas.png'

#Imagen original
img = Image.open(img_dir)

img.show() #Ver imagen

#Modificaciones mediante filtros  -----------------------------------------------

#Filtro BLUR (difuminar)
'''
img_Blur = img.filter(ImageFilter.BLUR)
img_Blur.show()
'''
#Filtro CONTOUR (contorno)
'''
img_Cont = img.filter(ImageFilter.CONTOUR)
img_Cont.show()
'''
# Filtro DETAIL (detalle)
'''
img_Det = img.filter(ImageFilter.DETAIL)
img_Det.show()
'''
#Filtros EDGE_ENHANCE y EDGE_ENHANCE_MORE  (realzar bordes)
'''
img_Bor1 = img.filter(ImageFilter.EDGE_ENHANCE)
img_Bor1.show()
'''
'''
img_Bor2 = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
img_Bor2.show()
'''
#Filtro EMBOSS (efecto grabado)
'''
img_Emb = img.filter(ImageFilter.EMBOSS)
img_Emb.show()
'''
#Filtro FIND_EDGES (detección de bordes)
'''
img_BorDetec = img.filter(ImageFilter.FIND_EDGES)
img_BorDetec.show()
'''
#Filtro SHARPEN (agudizar)
'''
img_Ag = img.filter(ImageFilter.SHARPEN)
img_Ag.show()
'''
#Filtros SMOOTH y SMOOTH_MORE (suavizar)
'''
img_Su1 = img.filter(ImageFilter.SMOOTH)
img_Su1.show()
'''
'''
img_Su2 = img.filter(ImageFilter.SMOOTH_MORE)
img_Su2.show()
'''

El esperado efecto de cada filtro queda explicado en el comentario que antecede, así que no es necesaria más explicación. Lo que sí te sugiero desde el punto de vista técnico-estético, que es el que ahora nos interesa, es que pruebes con diferentes imágenes (tamaño, calidad, formato, complejidad compositiva...) 

viernes, 17 de octubre de 2025

MAV. Python

Pillow

Usos básicos (IV)



Esta entrada complementa [la anterior], incluso puede que debiera ser previa pero en todo caso considero que no debe faltar en esta exposición de recursos para el tratamiento de imágenes ya que en ella trato sobre una función básica en Pillow relativa al cambio de tipo de imagen.

 

Me estoy refiriendo al cambio de modelo de imagen según sus atributos de color, tema este de cierta complejidad, pero que aquí vamos a resumir de forma drástica a las cuestiones que considero tienen mayor interés, quedando el resto para que tú profundices en ellas.

Por mi parte me limitaré a decir que podemos trabajar con imágenes en blanco y negro, imágenes en escala de grises (esta conversión ya la vimos en la entrada antes referida) e imágenes en color. Y dentro de estas últimas podemos distinguir entre imágenes formadas por combinaciones de colores básicos (formato RBG, extensión jpg) e imágenes que añaden a lo anterior información sobre niveles de transparencia (formato RGBA, extensión png). No son los únicos, pero por ahora es suficiente.

Empecemos por lo de siempre...

from PIL import Image

... es suficiente para lo que tenemos que hacer, no siendo necesarios (al contrario que antes) más módulos. Cargamos una imagen en formato png (por eso de trabajar con el formato más complejo)...

#Directorio de la imagen
img_dir = 'img/Estadistica.png'

#Imagen original
img = Image.open(img_dir)

... y visualizamos su atributo modo...

print(img.mode) -> Devuelve RGBA

Y para finalizar este proceso (ya conocido) podemos visualizar la imagen

img.show()

A partir de aquí empezaremos con las transformaciones que partirán siempre de la imagen original para facilitar la comparación.

Primero convertimos la imagen a escala de grises. Esto ya lo sabemos hacer con el módulo ImageOps y la función grayscale() (img_gris = ImageOps.grayscale(img)), pero ahora lo haremos desde el módulo principal Image mediante la función convert() (la verdadera artífice de esta conversión, que requiere como parámetro el identificador del modo color, concretamente L para la conversión a escala de grises (img_gris = img.convert('L'))

El paquete completo de instrucciones incluye la identificación del modo, el visionado de la nueva imagen (que podremos comparar con la original) y su archivo como imagen.

#Escala de grises
img_gris = img.convert('L')
print(img_gris.mode)             -> Devuelve L
img_gris.show()
img_gris.save('img/grafgris.png') #Guardar imagen

Si tratamos de invertir el proceso (convertir L a color, lógicamente obtenemos de nuevo una imagen en escala de grises, pero su modo sí se modifica al especificado en la conversión:

  • convert('RGBA') -> Genera RGBA
  • convert('RGB') -> Genera RGB
Finalmente convertiremos RGBA a RGB como paso previo a convertir la imagen de extensión png (con transparencias) a jpg (sin transparencias)...

# De RGBA a RGB
img_cv = img.convert('RGB')
print(img_cv.mode)                 -> Devuelve RGB
img_cv.show()
img_cv.save('img/grafcv.jpg') #Guardar imagen

... obteniendo el mismo efecto que antes (escala de grises) si realizamos la conversión inversa, aunque ahora la diferencia entre la original RGBA y la RGBA reformulada es menos evidente a la vista.

MAV. Python


Pillow

Usos básicos (III)


Ahora vamos a trabajar con el color, la luz y la nitidez. Para ello necesitamos algunos módulos, concretamente ImageChops,  ImageOps e ImageEnhance.

 

No será ésta la única entrada que dediquemos a esta temática, dado que se presentan múltiples opciones, lo cual puede tener el efecto negativo de distraernos de nuestros objetivos, ya que sobrepasa de largo nuestras necesidades pero resulta muy atrayente. Trataré de minimizar este efecto, pero difícil será no caer en excesos.

Para no empezar pecando de palabrería, presento el script donde desarrollo cómo generar ciertos efectos relativos al color, la luminosidad y la nitidez. Después comentaré algunas cuestiones. Por cierto, la fuente está disponible en [este enlace]. Te recomiendo visualizarlo.

from PIL import Image, ImageChops, ImageEnhance, ImageOps

#Cargar imagen base
img_dir = 'img/grafico.jpg'
img = Image.open(img_dir)

#Leer sus atributos
print(img.format, img.size, img.mode)

#Ver imagen base
img.show()

#Modificaciones -------------------------------------------------------------

#Invertir colores
img_inv = ImageChops.invert(img)
img_inv.show()

#Escala de grises
img_gris = ImageOps.grayscale(img)
img_gris.show()

#Resaltar luces
img_luz = ImageEnhance.Brightness(img).enhance(5)
img_luz.show()

#Contraste
img_cont = ImageEnhance.Contrast(img).enhance(5)
img_cont.show()

#Disminuir nitidez
img_nitida = ImageEnhance.Sharpness(img).enhance(-10)
img_nitida.show()

Trato en él cinco efectos: la inversión del color, la conversión a escala de grises, la luminosidad, el contraste y la nitidez de la imagen. Para ello hacemos uso de los módulos ImageChops, ImageOps e ImageEnhance, éste último para las tres modificaciones de luz, contraste y nitidez mediante funciones que reciben como parámetro la imagen, pero con el añadido de una segunda función con un parámetro numérico de efecto ordinal o de grado de intensidad (del efecto).



jueves, 16 de octubre de 2025

MAV. Python


Pillow

Usos básicos (II)



Aprendimos a cargar y guardar una imagen, así que ahora nos toca aprender a realizar algunas manipulaciones que pueden sernos de utilidad cuando trabajamos con imágenes. Se me ocurren algunas.

   


Dando por resueltos los pasos previos y la carga de la imagen, empezaré por cambiar su tamaño (grande a pequeño, claro)...

img_pq = img.resize((400,300))
img_pq.show()
img_pq.save('img/paisaje_pq.png')

... para lo que empleamos la función resize() que contiene una tupla como parámetro, la cual define el tamaño de la imagen resultante (img_pq = img.resize((400,300)))

También disponemos de una función que genera directamente una imagen en miniatura, aunque también requiere definir el tamaño de esa miniatura.

mini = (100,100)
img.thumbnail(mini)
img.save('img/paisaje_mini.png')

Puede que necesitemos rotar la imagen, tarea para la que disponemos de varias funciones, posiblemente la más versátil rotate() que recibe como parámetro los grados de rotación.

img_giro = img.rotate(50)
img_giro.show()
img_giro.save('img/paisaje_giro.png')

También podemos rotar la imagen en espejo, aunque para ello necesitamos trabajar con el módulo ImageOps que deberemos importar (from PIL Import Image, ImageOps).

img_espejo = ImageOps.mirror(img)
img_espejo.show()
img_espejo.save('img/paisaje_espejo.png')

Otra acción que nos puede interesar es recortar un trozo de la imagen. Para ello definimos una tupla indicando la zona a recortar y después aplicamos la función crop(), usando la tupla como parámetro.

zona = (100,100,500,500)
parte_img = img.crop(zona)
parte_img.show()
parte_img.save('img/paisaje_parte.png')

Finalmente vamos a unir dos imágenes mediante el método paste(). Este procedimiento requiere una explicación un poco más elaborada que los anteriores, por lo que lo voy a presentar en un script nuevo.

from PIL import Image

#Creamos la imagen de base

final = Image.new("RGB",(1800,1600),"black")

#Cargar primera imagen

img_dir1 = 'img/paisaje.png'

img_a = Image.open(img_dir1)

#Cargar segunda imagen

img_dir2 = 'img/cara.png'

img_b = Image.open(img_dir2)

#Pegamos las imágenes

final.paste(img_a,(0,650))

final.paste(img_b,(1000,0))

#Mostramos la imagen resultante y la guardamos 

final.show()

final.save('img/unir.png')

Observa que empezamos creando una imagen (con función de contenedor, en realidad) mediante el método new() (final = Image.new("RGB",(1800,1600),"black")), el cual requiere varios parámetro: el sistema de color ("RGB"), el tamaño ((1800,1600)) y el color de fondo ("black").

Después cargamos las dos (en este caso) imágenes que deseamos unir (vg. img_a = Image.open(img_dir1)) y las pegamos sucesivamente sobre el contenedor (vg final.paste(img_a,(0,650))), para lo que empleamos el método paste() que recibe como parámetros la imagen a pegar (img_a) y la posición en la que se sitúa su ángulo superior izquierdo ((0,650)).

Espero que estas manipulaciones te sean de interés. Pillow dispone de muchas más, algunas de las cuales veremos en próximas entradas.



MAV. Python

Pillow

Usos básicos (I)



Aunque es una biblioteca relativamente simple y limitada en cuanto a prestaciones (de ahí lo limitado de su uso), me ha parecido interesante incluirla en este blog precisamente por su sencillez, que nos proporciona un buen acercamiento al tema y nos provee de herramientas, algunas de ellas disponibles como utilidades de servicios (Impress, por ejemplo), pero que mediante Pillow podemos manejar con mayor eficiencia, además de proporcionarnos medios para automatizar ciertos procedimientos que, de otro modo, deberemos realizar "manualmente".


    

Parece evidente que lo primero que tendremos que aprender es a cargar y a guardar una imagen, pero para ello, antes tendremos que tener disponible la biblioteca. Procedamos.

from PIL import Image
#Cargar la imagen
img_dir = 'img/paisaje.png'
img = Image.open(img_dir)

#Leer algunos de sus atributos

print(img.format, img.size, img.mode)

#Visualizar la imagen

img.show()

#Guardar imagen

img.save("img/paisaje2.png")

No es mucho lo hecho, pero sí importante: accedemos y cargamos la imagen en memoria (img = Image.open(img_dir)), realizamos alguna manipulación elemental, por eso de hacer algo, como visualizarla (img.show()) y terminamos el script guardando una copia de la imagen (img.save("img/paisaje2.png")).

En la siguiente entrada nos dedicaremos a realizar algunas manipulaciones que sí tengan efecto sobre la imagen resultante, pero manteniendo como estrategia básica la consideración de la imagen como un todo. Existen otros planteamientos, pero aun es pronto para verlos.

MAV. Python

 Procesamiento básico de imágenes


Necesitamos trabajar con imágenes para muchas cosas y desde diferentes perspectivas, algunas muy básicas, como su manejo como documentos o como la simple traslación "a lo digital" de procedimientos manuales, incluyendo el corta-pega y similares. A todo esto (y a más, pero a esto fundamentalmente) es a lo que vamos a llamar procesamiento básico de imágenes.


Disponemos de varias herramientas en Python que, en lo que nos proponemos ahora, sirven para lo mismo, pero que se diferencian en procesamientos de mayor complejidad y especificidad. En esta subsección nos vamos a limitar a dos: Pilow y OpenCV. Con ambas vamos a construir lo que podríamos llamar una navaja multiusos para el manejo básico de imágenes.

La primera, Pilow, es la más sencilla (de instalar y usar), pero sobradamente útil. Puedes acceder a su documentación oficial [desde este enlace], incluye un interesante manual on-line. Y desde [aquí] un mini-curso en YouTube.

La biblioteca OpenCV no es Python en sentido estricto, pero puede ser usada mediante este lenguaje. Su instalación no es más complicada que la de Pilow, pero sí su uso, claro que en consonancia con su potencia y posibilidades de uso. Para descargarla accedemos a [esta página] y [este enlace]  te lleva a un mini-tutorial en You Tube.

En las próximas entradas iremos desarrollando algunas opciones de manejo de imágenes que nos proporcionan ambas bibliotecas. La intención no es tratarlas en profundidad (eso queda para ti en función de tus intereses), pero sí disponer, al final del proceso, de un conjunto de recursos de utilidad para que puedas manejar las imágenes que pudieras necesitar para el desarrollo de tus recursos.