Por qué funciona: Unidad 1.2: Captura de la imagen, Unidad 1.3: La imagen como datos
Recortar, redimensionar y guardar una imagen en OpenCV
Termina la corrección: recorta la carta de colores con slicing de arrays, reduce la foto con cv2.resize e INTER_AREA y guárdala con cv2.imwrite, donde la misma imagen pesa 54 KB como JPEG y 276 KB como PNG.
Traducción asistida por máquina del original en inglés. Los números, el código y las referencias se comprobaron contra él; el texto no fue revisado por un hablante nativo. Leer el original. Los labs interactivos y el código están en inglés.
Recortar conserva una parte de la foto, redimensionar cambia cuántos píxeles tiene y guardar la escribe en un archivo. Esta lección hace las tres cosas con la foto corregida.

Dónde ya lo has visto: la herramienta Recortar de cualquier app de fotos; las opciones de tamaño y calidad de Exportar o Guardar como en cualquier editor de imágenes.
TL;DR. Un recorte es una porción del array, un redimensionado recibe el tamaño como ancho y luego alto, y el formato del archivo decide cuánto pesa la imagen guardada. La foto corregida pesa 54 KB en JPEG con calidad 90 y 276 KB en PNG.
El problema
La corrección de la lección 3, multiplicar por 2,4, es la que conserva el proyecto. Este es el último paso del proyecto. Queda lo que harías con cualquier foto antes de compartirla: quedarte con la parte interesante, hacerla más pequeña y escribirla en un archivo.
Recortar, redimensionar, guardar
Un recorte no necesita ninguna función. La imagen es un array (lección 1), así que fixed[150:450, 0:330] son las filas 150 a 449 y las columnas 0 a 329: la carta de colores y el brazo de la lámpara. cv2.resize recibe el nuevo tamaño como (ancho, alto) y un método de interpolación; el tutorial de OpenCV recomienda INTER_AREA para reducir [1]. cv2.imwrite elige el formato por el nombre del archivo y recibe las opciones del formato como una lista [2].
import os
import cv2
fixed = cv2.convertScaleAbs(cv2.imread("dark.webp"), alpha=2.4)
chart = fixed[150:450, 0:330] # filas 150-449, columnas 0-329
thumb = cv2.resize(fixed, (480, 320), interpolation=cv2.INTER_AREA)
cv2.imwrite("fixed.jpg", fixed, [cv2.IMWRITE_JPEG_QUALITY, 90])
cv2.imwrite("fixed.png", fixed)
for name in ("fixed.jpg", "fixed.png"):
print(name, os.path.getsize(name) // 1024, "KB")
cv2.imshow("the crop", chart)
cv2.imshow("the thumbnail", thumb)fixed.jpg 54 KB fixed.png 276 KB
| Llamada | Qué hace |
|---|---|
img[r0:r1, c0:c1] | un recorte: filas r0 a r1 - 1, columnas c0 a c1 - 1 |
cv2.resize(img, (w, h), interpolation=cv2.INTER_AREA) | un nuevo tamaño, ancho primero; INTER_AREA para reducir |
cv2.imwrite(name, img, [cv2.IMWRITE_JPEG_QUALITY, 90]) | guarda; la calidad JPEG va de 0 a 100 y por defecto es 95 [2] |
El JPEG pesa más o menos una quinta parte del PNG. JPEG descarta el detalle al que el ojo es menos sensible, y PNG conserva todos los valores sin cambios. Para una foto que vas a compartir, JPEG o WebP; para cualquier cosa que vayas a volver a medir, PNG, porque un JPEG cambia los números.
El recorte es una vista (view) de fixed, no una copia: cambia un píxel de chart y el mismo píxel de fixed cambia. Llama a .copy() cuando quieras que sean independientes.
Rómpelo
img.shape da (alto, ancho). cv2.resize quiere (ancho, alto). Pásale el orden del shape y la foto sale estirada hacia el lado equivocado.
# cv2.resize recibe (ancho, alto); img.shape es (alto, ancho)
h, w = fixed.shape[:2]
squashed = cv2.resize(fixed, (h // 2, w // 2))
print("asked for", (h // 2, w // 2), "got shape", squashed.shape)
cv2.imshow("width and height swapped", squashed)asked for (319, 480) got shape (480, 319, 3)
Tu turno
Redimensiona fixed a 320 píxeles de ancho, manteniendo sus proporciones, y guárdalo en small.
small = fixed # redimensiona a 320 píxeles de ancho, manteniendo las proporciones
print(small.shape)Por qué funciona
Reducir una foto es volver a muestrearla en una rejilla más gruesa, y el valor de cada píxel nuevo tiene que interpolarse a partir de los antiguos [4]. Elegir valores sin promediar sobre el área que cubre cada píxel nuevo produce aliasing, los escalones y el moiré de Sampling: the pixel grid (en inglés). OpenCV describe INTER_AREA como “resampling using pixel area relation”, que “gives moire’-free results” al reducir [5], e INTER_LINEAR, el valor por defecto de cv2.resize, como interpolación bilineal simple. Qué descarta JPEG, y qué le hace eso a las mediciones, está en File formats and compression (en inglés).
Errores comunes
- Ancho y alto invertidos. La celda Rómpelo.
- Editar un recorte y cambiar el original. Las porciones son vistas; usa
.copy(). - Guardar como
.jpgy medir el archivo después. JPEG cambia los valores de los píxeles; guarda un PNG de todo lo que vayas a analizar. - Dejar la interpolación por defecto al reducir mucho.
cv2.resizeusaINTER_LINEARpor defecto, que interpola entre unos pocos vecinos en lugar de promediar toda el área, así que las reducciones grandes pueden producir aliasing [5].
Referencias
[1] OpenCV. Geometric Transformations of Images, section “Scaling” (Python tutorial, doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown). OpenCV 4.11.0, commit 31b0eee. github.com/opencv/opencv
[2] OpenCV. ImwriteFlags in modules/imgcodecs/include/opencv2/imgcodecs.hpp. OpenCV 4.11.0, commit 31b0eee. github.com/opencv/opencv
[3] Fairchild, M. D. (2007). The HDR Photographic Survey. IS&T 15th Color Imaging Conference, pp. 233–238. doi:10.2352/CIC.2007.15.1.art00044
[4] Gonzalez, R. C., & Woods, R. E. (2018). Digital Image Processing (4th ed.), section 2.4 “Image Sampling and Quantization”, Image Interpolation, p. 61, and section 4.5 “Extensions to Functions of Two Variables”, Aliasing in Images, p. 279. Pearson.
[5] OpenCV. InterpolationFlags and resize in modules/imgproc/include/opencv2/imgproc.hpp. OpenCV 4.11.0, commit 31b0eee. github.com/opencv/opencv