Imágenes como arrays NumPy: canales, dimensiones y dtype

Básico
OpenCV
OpenCV
Actualizado: 18/04/2026

Imágenes como arrays NumPy

En OpenCV, toda imagen es un array NumPy. Cuando cargas una imagen con cv2.imread(), obtienes un objeto numpy.ndarray que almacena los valores de los píxeles como números enteros.

import cv2
import numpy as np

# Cargar una imagen
imagen = cv2.imread("foto.jpg")

# Verificar que es un array NumPy
print(type(imagen))         # <class 'numpy.ndarray'>
print(imagen.shape)         # (alto, ancho, canales)  p. ej. (480, 640, 3)
print(imagen.dtype)         # uint8
print(imagen.size)          # número total de elementos
print(imagen.ndim)          # 3 para imágenes color, 2 para escala de grises

Esta representación como array NumPy es fundamental: permite usar todas las operaciones vectorizadas y funciones matemáticas de NumPy directamente sobre las imágenes.

El sistema de color BGR

A diferencia de la convención habitual RGB (Rojo-Verde-Azul), OpenCV utiliza el orden BGR (Azul-Verde-Rojo). Este es un detalle histórico heredado de las primeras versiones de la biblioteca, pero tiene implicaciones prácticas importantes.

import cv2
import numpy as np

# Crear una imagen de prueba con un píxel de color rojo puro
# En RGB: (255, 0, 0) → en BGR: (0, 0, 255)
imagen = np.zeros((200, 200, 3), dtype=np.uint8)
imagen[:] = (0, 0, 255)  # Rojo en BGR

cv2.imwrite("rojo_bgr.png", imagen)

# Acceder a los canales
b = imagen[:, :, 0]  # Canal Azul (Blue)
g = imagen[:, :, 1]  # Canal Verde (Green)
r = imagen[:, :, 2]  # Canal Rojo (Red)

print(f"Valor B en (100,100): {b[100, 100]}")   # 0
print(f"Valor G en (100,100): {g[100, 100]}")   # 0
print(f"Valor R en (100,100): {r[100, 100]}")   # 255

Dimensiones de la imagen: shape

El atributo shape de un array NumPy devuelve una tupla con las dimensiones:

  • Imágenes en color: (alto, ancho, 3) — tres canales BGR
  • Imágenes en escala de grises: (alto, ancho) — sin canal de color
  • Imágenes con canal alfa: (alto, ancho, 4) — cuatro canales BGRA
import cv2

# Imagen en color
img_color = cv2.imread("foto.jpg")
alto, ancho, canales = img_color.shape
print(f"Alto: {alto}px, Ancho: {ancho}px, Canales: {canales}")

# Imagen en escala de grises
img_gris = cv2.imread("foto.jpg", cv2.IMREAD_GRAYSCALE)
alto_g, ancho_g = img_gris.shape
print(f"Grises — Alto: {alto_g}px, Ancho: {ancho_g}px")
print(f"Dimensiones: {img_gris.ndim}")  # 2

# Imagen con canal alfa (PNG con transparencia)
img_rgba = cv2.imread("icono.png", cv2.IMREAD_UNCHANGED)
if img_rgba is not None and img_rgba.shape[2] == 4:
    print(f"Imagen con alfa: {img_rgba.shape}")  # (alto, ancho, 4)

Estructura interna de una imagen como array

El siguiente diagrama muestra cómo se organiza una imagen en color dentro de un array NumPy tridimensional:

flowchart TD
    A[Imagen BGR] --> B["ndarray (Height x Width x Channels)"]
    B --> C[Eje 0: Height - filas]
    B --> D[Eje 1: Width - columnas]
    B --> E[Eje 2: Channels - 3 canales]
    E --> F[Canal 0: Blue]
    E --> G[Canal 1: Green]
    E --> H[Canal 2: Red]
    C --> I["Cada celda: valor uint8 (0-255)"]
    F --> I
    G --> I
    H --> I

Cada píxel ocupa 3 bytes (uno por canal BGR) con valores entre 0 y 255. Una imagen en escala de grises tiene solo 2 dimensiones (Height x Width) y un único valor por píxel.

Tipo de datos (dtype)

El tipo de datos por defecto de las imágenes OpenCV es uint8 (entero sin signo de 8 bits), que almacena valores entre 0 y 255.

import cv2
import numpy as np

img = cv2.imread("foto.jpg")

print(f"Tipo de datos: {img.dtype}")          # uint8
print(f"Valor mínimo: {img.min()}")           # 0
print(f"Valor máximo: {img.max()}")           # 255

# Convertir a float32 para operaciones que requieren precisión decimal
img_float = img.astype(np.float32)
print(f"Float32 — dtype: {img_float.dtype}")  # float32

# Normalizar al rango [0.0, 1.0]
img_normalizada = img.astype(np.float32) / 255.0
print(f"Min: {img_normalizada.min():.2f}, Max: {img_normalizada.max():.2f}")

# Volver a uint8
img_recuperada = (img_normalizada * 255).astype(np.uint8)

Acceso y modificación de píxeles

Acceder a un píxel individual

import cv2

img = cv2.imread("foto.jpg")

# Leer píxel en fila=100, columna=200 (notación [fila, columna])
pixel = img[100, 200]
print(f"Píxel (100,200): B={pixel[0]}, G={pixel[1]}, R={pixel[2]}")

# En escala de grises, un solo valor
img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
valor = img_gris[100, 200]
print(f"Intensidad en escala de grises: {valor}")

Modificar un píxel

import cv2
import numpy as np

img = cv2.imread("foto.jpg")

# Modificar un píxel individual
img[100, 200] = [255, 0, 0]  # Azul puro en BGR

# Verificar el cambio
print(img[100, 200])  # [255   0   0]

Regiones de interés (ROI) con slicing

El slicing de NumPy permite extraer y modificar regiones rectangulares de una imagen de forma muy eficiente.

import cv2
import numpy as np

img = cv2.imread("foto.jpg")

# Extraer una ROI (Region of Interest)
# Sintaxis: img[y_inicio:y_fin, x_inicio:x_fin]
roi = img[50:200, 100:300]
print(f"Tamaño de la ROI: {roi.shape}")

# Copiar la ROI a otra posición de la misma imagen
img[300:450, 100:300] = roi

# Rellenar una región con un color sólido
img[10:60, 10:60] = [0, 255, 0]  # Cuadrado verde

cv2.imwrite("imagen_con_roi.png", img)

Separar y fusionar canales

import cv2
import numpy as np

img = cv2.imread("foto.jpg")

# Separar en canales individuales
b, g, r = cv2.split(img)

print(f"Canal B: shape={b.shape}, dtype={b.dtype}")  # (alto, ancho), uint8

# Crear imagen solo con canal rojo activo
solo_rojo = np.zeros_like(img)
solo_rojo[:, :, 2] = r  # Canal R en posición 2

# Fusionar canales
img_fusionada = cv2.merge([b, g, r])
print(f"Imagen fusionada: {img_fusionada.shape}")

# Acceso alternativo más eficiente que split (copia la vista del array)
canal_b = img[:, :, 0]
canal_g = img[:, :, 1]
canal_r = img[:, :, 2]

Crear imágenes desde cero

import cv2
import numpy as np

# Imagen negra (ceros) de 300x400 píxeles en color
negro = np.zeros((300, 400, 3), dtype=np.uint8)

# Imagen blanca
blanco = np.ones((300, 400, 3), dtype=np.uint8) * 255

# Imagen de color uniforme (azul en BGR)
azul = np.full((300, 400, 3), (255, 0, 0), dtype=np.uint8)

# Imagen de ruido aleatorio
ruido = np.random.randint(0, 256, (300, 400, 3), dtype=np.uint8)

# Gradiente horizontal en escala de grises
gradiente = np.tile(np.arange(0, 256, dtype=np.uint8), (300, 1))
gradiente_ancho = cv2.resize(gradiente, (400, 300))

cv2.imwrite("negro.png", negro)
cv2.imwrite("blanco.png", blanco)
cv2.imwrite("ruido.png", ruido)

Información completa de una imagen

import cv2
import numpy as np

def info_imagen(img, nombre="imagen"):
    """Muestra información completa sobre un array de imagen."""
    if img is None:
        print(f"{nombre}: None (error al cargar)")
        return

    print(f"\n--- {nombre} ---")
    print(f"  Tipo Python:    {type(img)}")
    print(f"  Shape:          {img.shape}")
    print(f"  dtype:          {img.dtype}")
    print(f"  Num elementos:  {img.size:,}")
    print(f"  Memoria (bytes):{img.nbytes:,}")
    print(f"  Valor mín:      {img.min()}")
    print(f"  Valor máx:      {img.max()}")
    print(f"  Valor medio:    {img.mean():.2f}")

img_color = cv2.imread("foto.jpg")
img_gris  = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)

info_imagen(img_color, "Imagen color BGR")
info_imagen(img_gris, "Imagen escala de grises")

Comprender la representación interna de las imágenes como arrays NumPy es la base de todo lo que haremos con OpenCV. Cada operación que apliquemos (filtros, transformaciones, detección de bordes) actúa sobre esta estructura matricial.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, OpenCV es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de OpenCV

Explora más contenido relacionado con OpenCV y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Entender que las imágenes en OpenCV son arrays NumPy de tipo ndarray. Conocer el orden de dimensiones (alto, ancho, canales) y el sistema de color BGR. Acceder y modificar píxeles individuales y regiones de interés (ROI) con slicing. Trabajar con los tipos de datos uint8, float32 y float64 en imágenes. Separar y fusionar canales de color con cv2.split() y cv2.merge().