Por que funciona: Unidade 1.2: Captura da imagem, Unidade 1.3: A imagem como dado
Recortar, redimensionar e salvar uma imagem no OpenCV
Termine a correção: recorte a carta de cores com fatiamento de array, reduza a foto com cv2.resize e INTER_AREA e salve com cv2.imwrite, onde a mesma imagem tem 54 KB como JPEG e 276 KB como PNG.
Tradução assistida por máquina do original em inglês. Números, código e referências foram conferidos com ele; o texto não foi revisado por um falante nativo. Ler o original. Os labs interativos e o código estão em inglês.
Recortar guarda uma parte da foto, redimensionar muda quantos pixels ela tem e salvar a grava num arquivo. Esta lição faz as três coisas com a foto corrigida.

Onde você já viu isso: a ferramenta Cortar de qualquer app de fotos; as opções de tamanho e qualidade de Exportar ou Salvar como em qualquer editor de imagem.
TL;DR. Um recorte é uma fatia do array, um redimensionamento recebe o tamanho como largura e depois altura, e o formato do arquivo decide o tamanho da imagem salva. A foto corrigida fica com 54 KB em JPEG com qualidade 90 e 276 KB em PNG.
O problema
A correção da lição 3, multiplicar por 2,4, é a que o projeto mantém. Esta é a última etapa do projeto. Falta o que você faria com qualquer foto antes de compartilhar: ficar com a parte interessante, deixá-la menor e gravá-la num arquivo.
Recortar, redimensionar, salvar
Um recorte não precisa de função. A imagem é um array (lição 1), então fixed[150:450, 0:330] são as linhas 150 a 449 e as colunas 0 a 329: a carta de cores e o braço do abajur. cv2.resize recebe o novo tamanho como (largura, altura) e um método de interpolação; o tutorial do OpenCV recomenda INTER_AREA para reduzir [1]. cv2.imwrite escolhe o formato pelo nome do arquivo e recebe as opções do formato como uma lista [2].
import os
import cv2
fixed = cv2.convertScaleAbs(cv2.imread("dark.webp"), alpha=2.4)
chart = fixed[150:450, 0:330] # linhas 150-449, colunas 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
| Chamada | O que faz |
|---|---|
img[r0:r1, c0:c1] | um recorte: linhas r0 a r1 - 1, colunas c0 a c1 - 1 |
cv2.resize(img, (w, h), interpolation=cv2.INTER_AREA) | um novo tamanho, largura primeiro; INTER_AREA para reduzir |
cv2.imwrite(name, img, [cv2.IMWRITE_JPEG_QUALITY, 90]) | salva; a qualidade JPEG vai de 0 a 100 e o padrão é 95 [2] |
O JPEG tem cerca de um quinto do tamanho do PNG. O JPEG descarta os detalhes a que o olho é menos sensível, e o PNG mantém todos os valores intactos. Para uma foto que vai ser compartilhada, JPEG ou WebP; para qualquer coisa que você vai medir de novo, PNG, porque um JPEG altera os números.
O recorte é uma visão (view) de fixed, e não uma cópia: mude um pixel de chart e o mesmo pixel de fixed muda. Chame .copy() quando quiser os dois independentes.
Quebre
img.shape dá (altura, largura). cv2.resize quer (largura, altura). Passe na ordem do shape e a foto sai esticada para o lado errado.
# cv2.resize recebe (largura, altura); img.shape é (altura, largura)
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)
Sua vez
Redimensione fixed para 320 pixels de largura, mantendo as proporções, e guarde em small.
small = fixed # redimensione para 320 pixels de largura, mantendo as proporções
print(small.shape)Por que funciona
Reduzir uma foto é reamostrá-la numa grade mais grossa, e o valor de cada pixel novo tem de ser interpolado a partir dos antigos [4]. Escolher valores sem fazer a média sobre a área que cada pixel novo cobre causa aliasing, os degraus e o moiré de Sampling: the pixel grid (em inglês). O OpenCV descreve INTER_AREA como “resampling using pixel area relation”, que “gives moire’-free results” ao reduzir [5], e INTER_LINEAR, o padrão de cv2.resize, como interpolação bilinear simples. O que o JPEG descarta, e o que isso faz com as medições, está em File formats and compression (em inglês).
Erros comuns
- Largura e altura trocadas. A célula Quebre.
- Editar um recorte e alterar o original. Fatias são visões; use
.copy(). - Salvar como
.jpge medir o arquivo depois. O JPEG altera os valores dos pixels; guarde um PNG de tudo que você for analisar. - Deixar a interpolação padrão ao reduzir muito.
cv2.resizeusaINTER_LINEARpor padrão, que interpola entre alguns vizinhos em vez de fazer a média da área inteira, então reduções grandes podem gerar aliasing [5].
Referências
[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