Pular para conteúdo

Aula 1 — Fundamentos de Imagem Digital e Representação em Memória (PDI)

Nesta aula você vai consolidar a teoria mínima necessária para executar o notebook prático:

Lab01 — Intro PID

O objetivo não é decorar termos, mas entender como a imagem é representada e o que acontece quando você lê, visualiza e altera pixels.


Como usar este handout

Fluxo recomendado

  1. Antes do notebook: leia até a seção 5 e responda os quizzes conforme aparecem.
  2. Durante o notebook: use este material como referência (principalmente BGR/RGB, shape, dtype, resize).
  3. Depois (5 min): revise apenas as perguntas que errou e valide no código.

Objetivos de aprendizagem

Ao final desta aula, você deve ser capaz de:

  1. Explicar o que significa uma imagem ser um sinal discreto 2D (amostragem + quantização).
  2. Interpretar a estrutura de uma imagem em Python como arrays NumPy (H×W×C).
  3. Diferenciar BGR (OpenCV) de RGB (Matplotlib) e evitar visualização “com cores erradas”.
  4. Identificar dtype (ex.: uint8) e o range de valores que ele suporta.
  5. Aplicar operações simples: tons de cinza, resize/amostragem, leitura de pixel, alteração de pixels.
  6. Entender por que varrer imagem com for é lento e quando isso faz sentido.

1) Imagem digital: amostragem e quantização

Uma imagem digital pode ser vista como um sinal contínuo (mundo real) convertido em uma estrutura discreta:

  • Amostragem (sampling): define quantos pixels teremos (resolução).
  • Quantização (quantization): define quantos valores possíveis cada pixel pode assumir.

Em termos práticos:

  • Mais resolução ⇒ mais detalhes espaciais, mas maior custo de processamento.
  • Mais bits por pixel ⇒ mais níveis de intensidade (ex.: 8 bits ⇒ 256 níveis).
#

Qual definição descreve melhor amostragem em imagens?

#

Uma imagem de 8 bits por pixel tem quantos níveis possíveis de intensidade?


2) Como a imagem aparece no código (NumPy)

No notebook, após carregar uma imagem, você verá algo como:

  • Imagem em tons de cinza: array 2D
    shape = (H, W)
  • Imagem colorida: array 3D
    shape = (H, W, C) com C = 3 (canais)

Interpretação:

  • H = número de linhas (altura)
  • W = número de colunas (largura)
  • C = canais de cor

Regra prática de indexação

Em NumPy/OpenCV você acessa como img[y, x] (linha primeiro, coluna depois).
Ou seja: (y, x)(linha, coluna).

#

Em NumPy/OpenCV, se img.shape == (720, 1280, 3), o que isso significa?

#

Qual acesso é correto para pegar um pixel na posição (x=50, y=10) em NumPy/OpenCV?


3) BGR vs RGB: por que as cores “ficam erradas”?

  • OpenCV (cv2) lê imagens em BGR (Blue, Green, Red).
  • Matplotlib (plt.imshow) espera RGB.

Se você fizer:

img = cv2.imread("NATUREZA_1.jpg")
plt.imshow(img)
as cores provavelmente ficarão trocadas.

A correção é converter:

img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)

Pegadinha clássica

Se você não converter BGR→RGB, seu pipeline pode “parecer” errado, mas o problema é apenas de visualização (não necessariamente do processamento).

#

Qual é a ordem padrão de canais ao carregar uma imagem com cv2.imread()?

#

Para visualizar corretamente no Matplotlib uma imagem lida pelo OpenCV, você normalmente faz:


4) Tons de cinza: o que muda?

Uma imagem em tons de cinza pode ser vista como uma única banda de intensidade.

No OpenCV:

  • cv2.imread(path, cv2.IMREAD_GRAYSCALE)
  • ou cv2.imread(path, 0)

Na visualização com Matplotlib, use:

plt.imshow(img_gray, cmap="gray")

Por que usar cmap='gray'?

Sem o cmap, o Matplotlib pode aplicar um mapa de cores (colormap) que não representa “cinza” de verdade, o que atrapalha sua interpretação.

#

No OpenCV, carregar uma imagem diretamente em tons de cinza pode ser feito com:

#

Ao usar plt.imshow() para mostrar uma imagem em tons de cinza, o mais correto é:


5) Tipos (dtype) e range: por que isso importa?

A maioria das imagens lidas com OpenCV vem como:

  • dtype = uint8
  • valores no range [0, 255]

Isso tem consequências:

  • Ao fazer contas, você pode ter overflow ou clipping se não controlar o tipo.
  • Para operações matemáticas (ex.: normalização, filtros, gamma), é comum converter para float32, calcular e depois voltar para uint8 com recorte.

Exemplo de boa prática (ideia geral):

img_f = img.astype("float32") / 255.0
# ... processa ...
img_u8 = (img_f * 255).clip(0, 255).astype("uint8")
#

Uma imagem uint8 tipicamente tem valores de intensidade entre e .

#

Qual é o motivo mais comum para converter uma imagem para float32 antes de certas operações?


6) Amostragem na prática: resize e interpolação

No notebook, você usa cv2.resize() para mudar o tamanho:

img2 = cv2.resize(img_rgb, (600, 400), cv2.INTER_LINEAR)

Dois pontos importantes:

  1. O tamanho é informado como (largura, altura) — atenção: é o inverso do shape.
  2. A interpolação define como os novos pixels são estimados:

  3. INTER_NEAREST: rápido, pode “pixelar”

  4. INTER_LINEAR: padrão, bom para muitos casos
  5. INTER_AREA: geralmente bom para reduzir (downsample)
#

O cv2.resize(img, (600, 400), ...) recebe o tamanho no formato:

#

Qual interpolação tende a ser boa para reduzir a imagem (downsample)?


7) Acessando e alterando pixels

Acesso a um pixel (colorido):

(b, g, r) = img_bgr[y, x]

Acesso a um pixel (cinza):

v = img_gray[y, x]

Alterar pixels pode ser feito com for, mas isso é caro:

for y in range(img.shape[0]):
    for x in range(img.shape[1]):
        img[y, x] = (255, 0, 0)

Custo computacional

Uma imagem 1080p tem ~2 milhões de pixels.
Dois for aninhados em Python ficam lentos rapidamente.

Alternativa profissional: usar operações vetorizadas (NumPy) e máscaras. Você verá isso nas próximas aulas.

#

Marque as afirmativas verdadeiras sobre varrer uma imagem com for em Python: