Por que funciona: Unidade 1.2: Captura da imagem, Unidade 1.3: A imagem como dado
Abrir uma imagem e ler seus pixels no OpenCV
Carregue uma foto com cv2.imread, veja que ela é uma grade de números com forma e tipo, e leia um pixel e o brilho médio de uma foto tirada dois stops escura demais.
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.
Para um computador, uma foto é uma tabela de números: um número por cor em cada ponto. Esta lição abre uma foto e lê essa tabela.

Onde você já viu isso: o conta-gotas de qualquer editor de imagem, que mostra os números sob o cursor; a janela Ponteiro do GIMP; a leitura RGB de uma ferramenta de captura de cor da tela.
TL;DR. Abrir uma foto no OpenCV te dá uma grade simples de números que você pode inspecionar e alterar. Esta tem 639 linhas por 960 colunas por 3 canais de cor de valores de 8 bits, e seu brilho médio é 56,6 de 255, por isso ela parece escura.
O problema
Este módulo corrige a foto acima. Ela é uma de dezoito exposições do mesmo abajur e da mesma carta de cores do HDR Photographic Survey [3], e foi tirada em 1,3 segundo, cerca de dois stops (quase quatro vezes menos luz) abaixo da exposição de 5 segundos que o módulo usa como alvo. Antes de corrigir qualquer coisa, você precisa ver o que o OpenCV te entrega quando abre o arquivo.
Abra a imagem
cv2.imread lê o arquivo e devolve um array NumPy [1]. Aperte Rodar: o código é Python e OpenCV de verdade, rodando no seu navegador.
import cv2
img = cv2.imread("dark.webp")
print("shape:", img.shape)
print("dtype:", img.dtype)
cv2.imshow("dark.webp", img)shape: (639, 960, 3) dtype: uint8
| Parte | O que ela diz |
|---|---|
shape (639, 960, 3) | 639 linhas (altura), 960 colunas (largura), 3 canais |
dtype uint8 | cada valor é um número inteiro de 0 a 255 |
cv2.imshow | mostra o array como imagem; aqui ela aparece embaixo da célula |
A ordem é linhas primeiro, depois colunas. A altura vem antes da largura, o contrário de como tamanhos de imagem costumam ser escritos (“960 × 639”), e essa é a primeira coisa que confunde quem está começando.
Leia um pixel, depois a imagem inteira
Indexar o array com [linha, coluna] dá os três valores de um pixel. O OpenCV os guarda como azul, verde, vermelho, e não vermelho, verde, azul: o modo de leitura padrão carrega “the BGR 8-bit format” [1]. Converter para cinza junta os três num único valor de brilho por pixel, e a média desses valores resume em um número o quão clara a foto é.
# Um pixel: linha 320, coluna 480. O OpenCV guarda B, G, R.
print("pixel at row 320, column 480:", img[320, 480])
# A imagem inteira em um número: o brilho médio
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print("mean brightness:", round(grey.mean(), 1), "of 255")pixel at row 320, column 480: [140 175 206] mean brightness: 56.6 of 255
Esse pixel fica no brilho do fundo da cúpula do abajur, por isso é claro. A foto como um todo tem média 56,6: a maior parte dela é mesa e parede escuras. A exposição de 5 segundos da mesma cena, que o módulo usa como alvo, tem média 104,7, e a lição 2 mostra isso com um histograma.
Quebre
Muitas outras bibliotecas Python esperam vermelho, verde, azul. Passe um array do OpenCV para elas sem converter e os canais azul e vermelho trocam de lugar. A célula abaixo faz a troca de propósito para você ver como fica: o abajur quente vira azul frio.
# Finge que outra biblioteca leu o array como R, G, B
swapped = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("blue and red swapped", swapped)
Sua vez
Encontre o maior valor de cinza da foto e guarde em brightest.
brightest = 0 # troque pelo maior valor de cinza de img
print(brightest)Por que funciona
Uma câmera conta a luz que chegou a cada fotossítio durante a exposição. Guardar o resultado amostra a cena numa grade e quantiza cada valor em um de 256 níveis [2], e é daí que vêm a forma e o uint8. A lição An image is an array (em inglês) explica o que a forma e o tipo significam, From photons to counts de onde vêm os números, e Colour spaces por que existem três canais. As três estão na trilha de Fundamentos, unidades 1.2 e 1.3.
Erros comuns
imreaddevolveNoneem vez de falhar. Um caminho errado não dá erro até a próxima linha mexer no array. Testeimg is Nonequando o arquivo puder não existir.- Azul e vermelho trocados. O OpenCV usa B, G, R; matplotlib, Pillow e a maior parte do código web usam R, G, B. Converta com
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)antes de passar o array adiante. img[x, y]em vez deimg[y, x]. Linhas vêm primeiro. Numa imagem que não é quadrada, isso lê o pixel errado ou falha com erro de índice.cv2.imshownum notebook. Num script ele abre uma janela e precisa decv2.waitKey; no Colab e no Jupyter ele não funciona. O notebook do módulo mostra as imagens com matplotlib.
Referências
[1] OpenCV. Getting Started with Images (tutorial, doc/tutorials/introduction/display_image/display_image.markdown). OpenCV 4.11.0, commit 31b0eee. github.com/opencv/opencv
[2] Gonzalez, R. C., & Woods, R. E. (2018). Digital Image Processing (4th ed.), section 2.4 “Image Sampling and Quantization”, p. 47. Pearson.
[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