Conclusiones clave
- Los cuadros de recorte de Pillow usan los límites left, upper, right, lower, con right y lower excluidos.
- Los arrays de OpenCV usan cortes de fila y columna, por lo que el orden habitual es image[y1:y2, x1:x2].
- Limita las coordenadas a los límites de la fuente y rechaza las regiones vacías antes de asignar la salida.
Pillow suele ser el camino más corto para operaciones rectangulares de imagen; OpenCV resulta útil cuando el recorte se deriva de un análisis de visión por computadora. Ambas necesitan, en última instancia, límites de píxeles precisos y una codificación de salida explícita.
Lo más importante
- Conserva o elimina deliberadamente los perfiles de color y los metadatos, en lugar de cambiarlos por accidente.
- Elige la calidad de salida y los ajustes de croma según el destino, no según los valores predeterminados de la biblioteca.
Elige la biblioteca a partir del trabajo en torno al recorte
Pillow es una opción práctica por defecto para cargar, recortar, redimensionar y guardar imágenes comunes. Su API se corresponde directamente con operaciones rectangulares de imagen y mantiene la superficie de dependencias relativamente pequeña. OpenCV es una mejor opción cuando el rectángulo proviene de un trabajo de visión por computadora, como análisis de contornos, seguimiento o un detector que ya devuelve coordenadas de NumPy.
No elijas OpenCV solo porque el recorte suene a visión por computadora. Sus convenciones de arrays y color introducen oportunidades adicionales de error cuando la aplicación solo necesita un rectángulo proporcionado por el usuario. Por el contrario, convertir repetidamente entre imágenes de Pillow y arrays de OpenCV consume memoria y puede cambiar el orden de los canales. Mantén la imagen en una sola representación hasta que otra biblioteca aporte un beneficio concreto.
Usa límites semiabiertos de forma consistente
El cuadro de recorte de Pillow se ordena como izquierda, superior, derecha, inferior. Los límites derecho e inferior quedan excluidos, así que el tamaño de salida es derecha menos izquierda por inferior menos superior. Un cuadro de (120, 80, 920, 680) produce entonces una región de 800 por 600. Nombra las coordenadas según su significado en lugar de pasar por la aplicación una tupla de cuatro números sin explicación.
OpenCV usa el segmentado (slicing) de NumPy, que sigue el orden de filas primero. La región equivalente es image[80:680, 120:920], o image[y1:y2, x1:x2]. Ambas convenciones son de intervalo semiabierto, pero su orden difiere. Invertir x e y puede parecer que funciona con una imagen de prueba cuadrada y fallar con imágenes en formato retrato, así que las pruebas deberían usar dimensiones distintas y un marcador asimétrico cerca de una esquina.
from pathlib import Path
from PIL import Image, ImageOps
def crop_image(source: Path, destination: Path, box: tuple[int, int, int, int]) -> None:
with Image.open(source) as image:
oriented = ImageOps.exif_transpose(image)
cropped = oriented.crop(box) # (left, upper, right, lower); right/lower are excluded
cropped.save(destination, format="WEBP", quality=86, method=6)
crop_image(Path("source.jpg"), Path("crop.webp"), (120, 80, 920, 680))Cuadro de Pillow
Pasa las coordenadas izquierda, superior, derecha, inferior, excluyendo los dos últimos bordes.
Segmentado de OpenCV
Segmenta las filas antes que las columnas con image[y1:y2, x1:x2].
Validación
Exige que izquierda < derecha y superior < inferior, y luego limita o rechaza las coordenadas según una política explícita.
Resuelve la orientación antes de seleccionar píxeles
La orientación EXIF puede indicar a los visores que roten o reflejen los píxeles almacenados. Si las coordenadas de recorte provienen de una vista previa ya corregida, normaliza la fuente de la misma manera antes de aplicarlas. Pillow ofrece utilidades que respetan la orientación, como ImageOps.exif_transpose. Con OpenCV, realiza explícitamente la rotación o el volteo equivalente y actualiza las dimensiones que usa el modelo de recorte.
Después de la normalización, no conserves metadatos de orientación obsoletos que volverían a rotar el derivado. Decide por separado qué otros metadatos deberían permanecer. Los perfiles ICC pueden ser necesarios para el color esperado, mientras que el GPS, los identificadores de dispositivo, los comentarios y las miniaturas pueden ser indeseables en una salida pública. Una operación de recorte es un buen punto para aplicar una política de metadatos deliberada en lugar de heredar los valores predeterminados de la biblioteca.
Codifica el resultado de forma deliberada
El recorte no requiere remuestreo cuando los píxeles de origen seleccionados se copian directamente. Cambiar el tamaño del recorte sí requiere un filtro de remuestreo, y la opción adecuada depende de si el contenido es fotografía, texto, arte lineal o pixel art. Mantén el recorte y el cambio de tamaño como funciones distintas en el código para que las pruebas puedan identificar dónde se introdujo suavizado excesivo, artefactos de anillado o aliasing.
Elige formato de salida, calidad, comportamiento de crominancia, manejo de transparencia y perfil de color según el destino. OpenCV suele usar el orden de canales BGR, mientras que Pillow usa RGB, así que convierte explícitamente al cruzar ese límite. La decodificación y codificación repetidas de JPEG acumulan pérdida, y los valores de calidad no son perfectamente comparables entre codificadores. Genera los nuevos derivados a partir del archivo maestro, no de una miniatura anterior.
Protege los procesos de trabajo frente a entradas hostiles o accidentales
Una subida comprimida modesta puede describir una imagen decodificada enorme. Verifica las dimensiones y aplica un límite de píxeles antes de asignar búferes grandes. Las salvaguardas de Pillow contra bombas de descompresión son advertencias útiles, pero las aplicaciones igual necesitan sus propios límites de tamaño de archivo, cantidad de píxeles, fotogramas, tiempo de ejecución y trabajo concurrente. Trata los tipos MIME y las extensiones proporcionados por el cliente como indicios, y deja que un decodificador verifique el contenido.
Rechaza cuadros vacíos, números no finitos, ampliaciones irrazonables, modos no compatibles y coordenadas fuera de la política elegida. Captura los fallos del decodificador en el límite del trabajo y devuelve un error saneado en lugar de una traza de pila. Ejecuta el procesamiento no confiable con permisos restringidos, almacenamiento temporal acotado y sin acceso innecesario a la red. Limpia los archivos temporales después del éxito, la cancelación y el fallo.
Bytes comprimidos
Limita el tamaño de la subida y del objeto importado, pero no lo uses como único control de memoria.
Píxeles decodificados
Acota el ancho multiplicado por el alto y ten en cuenta los fotogramas y los búferes de trabajo.
Duración del trabajo
Aplica tiempos de espera y cancelación para que las entradas corruptas o complejas no puedan ocupar un proceso de trabajo indefinidamente.
Expansión de la salida
Restringe las dimensiones y los formatos solicitados para evitar derivados inesperadamente grandes.
Haz que los trabajos por lotes sean reiniciables
En los lotes, separa el descubrimiento, el procesamiento y la publicación. Deriva una clave de idempotencia a partir de la versión de la fuente, la especificación de recorte, la política del codificador y la versión del pipeline. Escribe en un destino temporal, vuelve a abrir el resultado, verifica sus dimensiones y formato, y luego publica de forma atómica cuando el sistema de almacenamiento lo permita. Un reintento debería reproducir o reutilizar el mismo resultado en lugar de crear otro archivo ambiguo.
Controla la concurrencia según el uso medido de memoria y CPU, no solo según el número de procesos de trabajo. Registra el estado, la duración, las dimensiones de origen, las dimensiones de salida y una categoría de error acotada para cada elemento. Evita que los archivos problemáticos reintenten indefinidamente y aísla las anulaciones manuales del reprocesamiento automático. Las pruebas de rendimiento representativas deberían incluir entradas grandes y malformadas, además de las imágenes pequeñas usadas en las pruebas unitarias.
Traslada el trabajo con imágenes fuera de la ruta de solicitud cuando las operaciones predominan
Un servicio local con Pillow u OpenCV se encarga de la instalación de códecs, las actualizaciones de seguridad, la presión de memoria, las colas, el disco temporal, los reintentos y la transferencia de almacenamiento. Ese control es valioso cuando el recorte está estrechamente ligado a un análisis personalizado. Resulta menos atractivo cuando el servicio se limita en gran medida a mover objetos entre almacenamientos y aplicar rectángulos predecibles a gran escala, una carga de trabajo que un servicio de procesamiento gestionado puede asumir en su lugar.
Cuando las operaciones con imágenes predominan en el servicio, trasládalas a una cola de procesos de trabajo acotada en lugar de mantenerlas dentro de los controladores de solicitud. Los procesos de trabajo pueden leer objetos de origen inmutables, aplicar contratos de recorte validados y publicar salidas versionadas directamente en el almacenamiento de objetos. Esto evita solicitudes web prolongadas y hace explícitos la concurrencia, los reintentos, los límites de memoria, la limpieza de archivos temporales y la publicación idempotente.
Prueba los píxeles, los metadatos y el comportamiento ante fallos
Las pruebas unitarias deberían cubrir cada borde, regiones de un solo píxel, límites negativos y excesivos, cambios de orientación, dimensiones impares, alfa, escala de grises, entrada CMYK y una imagen asimétrica que revele la inversión de x e y. Verifica las dimensiones de salida y las posiciones de los puntos de referencia seleccionados. La comparación píxel a píxel puede ser adecuada para recortes sin pérdida, mientras que las codificaciones con pérdida necesitan verificaciones perceptuales o de error acotado.
Las pruebas de integración deberían reabrir el archivo publicado con un decodificador independiente, confirmar el formato y las dimensiones, inspeccionar la política de metadatos y simular escrituras interrumpidas y trabajos duplicados. Compara las salidas locales y gestionadas solo con los requisitos documentados, no con una igualdad de bytes accidental del codificador. Monitorea las tasas de fallos y los picos de memoria en producción, porque un conjunto de datos de prueba exitoso no puede representar todos los casos límite de los decodificadores de imágenes.
Detalles técnicos que conviene conocer
- Pillow usa un cuadro de recorte semiabierto de izquierda, superior, derecha, inferior. NumPy y OpenCV usan el segmentado con orden de filas primero, lo que hace que una inversión accidental de x/y sea una causa común de recortes incorrectos.
- Una imagen comprimida pequeña puede expandirse hasta convertirse en un búfer de píxeles enorme. Pillow incluye advertencias sobre bombas de descompresión, pero las aplicaciones igual necesitan límites explícitos de píxeles y memoria.
- La calidad de salida JPEG no es comparable entre todos los codificadores, y la decodificación y codificación repetidas de JPEG acumulan pérdida incluso cuando se reutiliza el mismo valor nominal de calidad.
- Image.save puede no conservar ni el EXIF ni el perfil ICC a menos que se pasen deliberadamente, lo que provoca que los metadatos de orientación o la apariencia del color cambien después de un simple recorte.
- OpenCV suele representar los píxeles en orden de canales BGR mientras que Pillow usa RGB, así que cruzar los límites entre estas bibliotecas sin conversión puede intercambiar el rojo y el azul.
- Procesar por mosaicos puede reducir el pico de memoria en algunas operaciones, pero los recortes, filtros y códecs arbitrarios pueden seguir requiriendo la decodificación completa de la imagen de origen.
Un enfoque práctico
- 1
Comprueba la orientación y las dimensiones antes de calcular un recorte.
- 2
Escribe pruebas para bordes de desfase por uno, coordenadas negativas y entradas rotadas.
- 3
Codifica en una salida temporal y verifica las dimensiones antes de publicarla.
- 4
Realiza pruebas de rendimiento con lotes representativos antes de decidir entre procesos de trabajo locales y procesamiento gestionado.
Límite de la arquitectura
Pillow y OpenCV se ejecutan en donde sea que corra el proceso de Python, por lo que la implementación, el soporte de códecs, la presión de memoria, la limpieza de disco, la concurrencia y la publicación segura siguen siendo responsabilidades de la aplicación y no funciones de la biblioteca.
Preguntas frecuentes
¿Qué orden de coordenadas usa Pillow para recortar?
Pillow usa (left, upper, right, lower). Los bordes derecho e inferior quedan excluidos, por lo que el ancho de salida es right menos left y el alto de salida es lower menos upper.
¿Por qué un recorte de OpenCV usa y antes que x?
Una imagen de OpenCV es un array de NumPy indexado por filas y luego columnas. El corte habitual es image[y1:y2, x1:x2].
¿Deberían limitarse las coordenadas fuera de la fuente o rechazarse?
Ambas pueden ser válidas, pero la política debe ser explícita. Rechazar detecta errores previos en la cadena; limitar por los bordes puede admitir selecciones deliberadas si el resultado sigue sin estar vacío y cumple las dimensiones mínimas.
¿Cómo debería manejarse la orientación EXIF?
Normaliza la orientación antes de aplicar las coordenadas de una vista previa visualmente corregida, recalcula las dimensiones y elimina o actualiza los metadatos de orientación en el resultado guardado.
¿Cuándo es preferible el procesamiento gestionado frente a los procesos de trabajo de Pillow u OpenCV?
Es útil cuando el recorte es predecible y gestionar códecs, colas, almacenamiento temporal, reintentos, importaciones y exportaciones no forma parte del valor central del producto.