- Aprende a programar la ESP32-CAM en Micropython. Parte 1
- Aprende a programar la ESP32-CAM en Micropython. Parte 2
En la primera parte de este tutorial destinado a aprender a utilizar la ESP32-CAM en Micropython te expliqué como grabar un custom firmware en la placa. En esta segunda entrega veremos en detalle los objetos y métodos que agrega este firmware y que nos permiten tener acceso a las funciones de la cámara.
Control de la cámara
Una vez que tenemos el firmware instalado en nuestra ESP32-CAM podemos comenzar a programarla desde Micropython. (La instalación del firmware está explicada en este artículo anterior)
El primer paso es importar el módulo camera que incluye un objeto del mismo nombre que cuenta con 12 métodos para configurar la cámara y capturar imágenes.
Estos métodos son los siguientes:
- init
- deinit
- flip
- mirror
- framesize
- quality
- contrast
- saturation
- brightness
- speffect
- whitebalance
- capture
Veamos a continuación cada uno de ellos en detalle
init
Método: init
Activa e inicializa la cámara
Formato: camera.init (0, parámetro=valor, …)
Los parámetros aceptados en init son los siguientes, con sus valores posibles entre corchetes.
xclk_freq_hz: Frecuencia de reloj de la cámara en Hz. [10000000, 20000000 ]
frame_size: Tamaño de la imagen capturada (ver método framesize mas abajo)
pixel_format: Formato de la imagen capturada [JPEG, YUV422, GRAYSCALE, RGB565]
jpeg_quality: Calidad de la imagen capturada [10..63]. Los valores menores representan mayor calidad
fb_location: Ubicación de la imagen capturada [DRAM, PSRAM]. Es conveniente usar PSRAM.
Ejemplo:
camera.init (0, format=camera.JPEG, fb_location=camera.PSRAM)
deinit
Método: deinit ()
Desactiva la cámara
Parámetros:
No tiene
Ejemplo:
camera.deinit ()
flip
Método: flip (orientación)
Cambia la orientación vertical de la imagen
Parámetros:
Orientación = 0 > Imagen normal
Orientación = 1 > Imagen invertida
Ejemplo:
camera.flip (0) #Sin invertir
mirror
Método: mirror (orientación)
Cambia la orientación horizontal de la imagen
Parámetros:
Orientación = 0 > Imagen normal
Orientación = 1 > Imagen invertida
Ejemplo:
camera.mirror (1) #Invertida
framesize
Método: framesize (tamaño)
Especifica el tamaño y resolución de la imagen capturada
Parámetros:
tamaño debe tener alguno de los siguientes valores:
FRAME_96X96 = 96*96
FRAME_QQVGA = 160*120
FRAME_QCIF = 176*144
FRAME_HQVGA = 240*160
FRAME_240X240 = 240*240
FRAME_QVGA = 320*240
FRAME_CIF = 352*288
FRAME_HVGA = 480*320
FRAME_VGA = 640*480
FRAME_SVGA = 800*600
FRAME_XGA = 1024*768
FRAME_HD = 1280*720
FRAME_SXGA = 1280*1024
FRAME_UXGA = 1600*1200
FRAME_FHD = 1920*1080
FRAME_P_HD = 2048*1152
FRAME_P_3MP = 2048*1536
FRAME_QXGA = 2048*1536
FRAME_QHD = 2560*1440
FRAME_WQXGA = 2560*1600
FRAME_P_FHD
FRAME_QSXGA = 2560*2048
Ejemplo:
camera.framesize (camera.FRAME_CIF)
quality
Método: quality (calidad)
Especifica la calidad de la imagen capturada.
Parámetros:
calidad puede variar entre 10 (calidad alta) y 63 (calidad baja)
Ejemplo:
camera.quality (10)
contrast
Método: contrast (contraste)
Especifica el contraste de la imagen
Parámetros:
contraste puede variar entre -2 (contraste bajo) y 2 (contraste alto). Por omisión vale 0.
Ejemplo:
camera.contrast (1)
saturation
Método: saturation (saturación)
Especifica la saturación (intensidad de los colores) de la imagen
Parámetros:
saturación puede variar entre -2 (baja intensidad) y 2 (alta intensidad). Por omisión vale 0.
Ejemplo:
camera.saturation (-1)
brightness
Método: brightness (brillo)
Especifica el brillo de la imagen
Parámetros:
brillo puede variar entre -2 (mas bajo) y 2 (mas alto). Por omisión vale 0.
Ejemplo:
camera.brightness (1)
speffect
Método: speffect (efecto)
Aplica un efecto a la imagen
Parámetros:
efecto puede ser uno de los siguientes:
EFFECT_NONE (por omisión)
EFFECT_NEG = negativo
EFFECT_BW = ByN (escala de grises)
EFFECT_RED = Rojizo
EFFECT_GREEN = Verdoso
EFFECT_BLUE = Azulado
EFFECT_RETRO = Sepia
Ejemplo:
camera.speffect (camera.EFFECT_NONE)
whitebalance
Método: whitebalance (modo)
Equilibra los niveles de los colores básicos (Rojo, Verde y Azul).
Parámetros:
modo puede ser uno de los siguientes:
WB_NONE = sin compensación
WB_SUNNY = compensa días soleados
WB_CLOUDY = compensa días nublados
WB_OFFICE = compensa iluminación fría
WB_HOME = compensa iluminación cálida
Ejemplo:
camera.whitebalance (camera.WB_NONE)
capture
Método: capture ()
Captura una imagen
Parámetros:
No tiene.
Ejemplo:
img = camera.capture()
Programa
El siguiente es un ejemplo sencillo que toma imágenes cada 10 segundos y las almacena como archivos en la memoria Flash del ESP32. Es una modificación del programa de ejemplo que se puede encontrar en el repositorio del firmware.
Como se puede ver, en las líneas 1, 2 y 3 se importan los módulos necesarios, empezando por camera.
En la línea 7 se define led en el pin 4, donde está conectado el flash de la cámara.
En la línea 9 se inicializa la variable foto a 1, para contar las imágenes que se van capturando e incluirlo en el nombre del archivo cuando las mismas se graben en la memoria.
A continuación, en la línea 11 se inicia un bucle para capturar las imágenes cada 10 segundos. Lo primero es generar el nombre del archivo que se va a guardar como “Capx.jpg” donde x será reemplazado por el valor de la variable foto.
Luego desde la línea 15, dentro de un bloque try se hace la inicialización y configuración de la cámara y luego la captura de la imagen (línea 50).
import camera from time import sleep import machine #Pin del led de flash led = machine.Pin(4, machine.Pin.OUT) foto=1 while (True): nombre = "Cap"+str(foto)+".jpg" print (nombre) try: camera.init(0, format=camera.JPEG, fb_location=camera.PSRAM) #Establece el brillo camera.brightness(-1) #Orientacion normal camera.flip(0) #Orientación normal camera.mirror (0) #Resolución camera.framesize(camera.FRAME_XGA) #contraste camera.contrast(2) #saturacion camera.saturation (-2) #calidad camera.quality(10) # special effects camera.speffect(camera.EFFECT_NONE) # white balance camera.whitebalance(camera.WB_NONE) #Enciende flash #led.value(1) sleep (0.5) #Captura la imagen img = camera.capture() print ("Tamaño=",len(img)) #Apaga flash led.value(0) #desactivar cámara camera.deinit () #Guardar la imagen en el sistema de archivos imgFile = open(nombre, "wb") imgFile.write(img) imgFile.close() foto+=1 sleep (10) except Exception as err: print ("Error= "+str (err)) sleep (2)
En la línea 46 está comentado el encendido del flash. Si lo necesitas debes descomentar esta línea.
El print de la línea 51 muestra el tamaño de la imagen. Este programa está pensado sólo como un ejemplo del uso de los métodos de la cámara y por esta razón las imágenes se graban en la flash del ESP32 y no en la tarjeta SD. La idea es tomar unas pocas imágenes y descargarlas luego a una computadora para verlas, y no que funcione como un time lapse, por ejemplo. Si tomas muchas imágenes (depende de la resolución) puede que obtengas un Error 28 (memoria llena).
Usando Thonny es muy fácil descargar las imágenes a la computadora. Debes activar la visualización de los archivos, hacer click derecho sobre la imagen que quieras descargar y seleccionar Descargar a (carpeta).
Siguiendo con el análisis del programa de ejemplo, en las líneas 61, 62 y 63 se graba la imagen en la memoria como un archivo binario. Si quieres puedes aprender como trabajar con este tipo de archivos en este artículo anterior.
En la línea 65 se incrementa el contador de imágenes y en la 67 se realiza el retardo de 10 segundos.
Si hubiera algún error dentro del bloque try, desde la línea 69 se captura el error en el bloque exception donde se muestra el mensaje del error producido y se espera 2 segundos.
Ejemplos y observaciones
Las siguientes son algunas imágenes de ejemplo tomadas con distintas configuraciones, calidades y resoluciones.
No es fácil obtener imágenes de buena calidad. Las variaciones de iluminación entre ambientes abiertos y cerrados hace necesario ajustar los distintos parámetros de configuración de la cámara, como brillo, contraste o saturación.
A mayor tamaño de imagen es necesaria una mayor iluminación. En interiores se obtienen mejores resultados con resoluciones bajas.
No se pueden lograr simultáneamente resoluciones altas y calidad de imagen alta. Si se aumenta la resolución, sobre todo en los valores mas elevados, hay que comenzar a disminuir la calidad. Por ejemplo en formato XGA se puede tener la calidad mas alta (el valor de 10) pero en SXGA la calidad debe disminuirse (un valor de 20) y mas aún en UXGA (un valor de 30).
En exteriores es habitual que las imágenes contengan zonas “quemadas” es decir blancas debido a la cantidad de luz. Tal vez esto podria evitarse reduciendo el tiempo de exposición, pero esta función no esta disponible en este firmware.
Si bien el firmware admite valores de resolución muy elevados, con mi ESP32-CAM con una cámara OV2640, siempre obtuve error para valores superiores a UXGA (1600*1200 = 1.8 MPx). Los valores de resolución mayores tal vez estén reservados para otros modelos de cámara.
Conclusión
El firmware de lemariva nos permite programar la ESP32-CAM en Micropython y pone a nuestra disposición una serie de métodos para controlar las funciones mas comunes de la cámara de una forma sumamente sencilla. En este artículo te mostré como utilizar cada uno de ellos y como emplearlos en un ejemplo sencillo que toma imágenes con la cámara a intervalos de tiempo regulares. Esta es una base que puede emplearse para proyectos mucho mas ambiciosos y complejos. En otros artículos iré compartiendo mas ideas y mas aplicaciones de esta interesante placa, siempre programados en Micropython.
Cualquier duda o sugerencia, puedes dejarla en la sección de comentarios. Hasta la próxima!
Como siempre un excelente trabajo !!!
Lo he seguido al pie de la letra y me ha funcionado.
Muchas gracias Profe !!!
Saludos desde México.
Gracias Fredy! Que bueno que te ha funcionado!
Es posible tomar videos con este dispositivo?
Hola Lalo, hasta donde yo he podido ver, solo para imagenes fijas.
Hola!
Muchas gracias por todo el aporte.
Tengo una duda, has probado el ESP32CAM con otro módulo de cámara? (OV5640, OV3660)
Gracias.
Hola Achel, no, sólo con la OV2640
Buenos días,
Acabo de descubrir tu blog y me ha parecido genial, gran trabajo!
He buscado mucho y no he encontrado, tengo el firmware de Shariltumin (1.18), al inicializar la cámara con:
import camera
camera.init(0, xclk_freq=20000000)
(o con xclk_freq_hz, como pones tú)
Me da el error: TypeError: function doesn’t take keyword arguments
Como si la función init no admitiera parámetros (incluso probando con otros argumentos).
Alguna idea?
Muchas gracias.
Hola Enrique, muchas gracias!
Un keyword argument es el que se especifica como key=valor. En tu caso puede ser que camera.init no espere xclk_freq=20000000 sino simplemente 20000000.
Cuando escribí este artículo probé el firmware de Shariltumin y me pareció que tenía poca funcionalidad. Veo que ahora hay una actualización del 2022. Ha mejorado en este tiempo?
Gracias por responder tan rápido.
Si no es parámetro con nombre, no sé en qué orden tendría que poner la frecuencia. No encuentro documentación. Me parecía raro que cambiaran los parámetros en la función camera.init de un custom firmware a otro.
Intento ganar más FPS para hacer streaming y he leído que una forma puede ser cambiando la frecuencia.
Empecé con el ESP32CAM con tu blog e instalé el firm de Lemariva, pero vi que el firm de Shariltumin se actualizaba más a menudo y me quedé con ese (además si no recuerdo mal el Lemariva, no tenía algo que el que tengo sí, creo que la versión de MP era la 1.14 en vez de la 1.18).
Ah, ya entiendo… estás llamando a camera.init con el formato del firmware de lemariva en el firmware de Shariltumin. Estoy en lo correcto?
Bueno, no necesariamente tienen que coincidir los parámetros, puede que cada programador lo haga a su manera. Dando un vistazo al repositorio de Shariltumin veo que la documentación es muy pobre (creo que por eso tambien decidi no utilizarlo) y en los pocos ejemplos que veo se invoca a camera.init sin parámetros. Puede que me equivoque pero tal vez no acepta parámetros y la configuración es fija, lo que explicaría el mensaje de error.
Correcto. Es todo como dices.
Eso me estaba temiendo, pero viendo el GitHub el .c del modulo, parece que tiene el parámetro, por eso me parecía raro. Tampoco tiene los nombres de las constantes… Así que está claro que iguales no son.
Pero será lo que dices, pensaba que todos los módulos de camera eran iguales, independientemente de quien compilara todo el firm.
Como veo que Lemariva ha actualizado al menos la versión de MP igual le doy otra oportunidad.
Hay dos ficheros y parecen que los dos tienen cámara, sabes que diferencia hay entre ellos?
micropython_cmake_9fef1c0bd_esp32_idf4.x_ble_camera.bin y micropython_camera_feeeb5ea3_esp32_idf4_4.bin
Así mirando un poco rápido los nombres que uno tiene BT y la cámara y el otro no. Sabes si es la única diferencia?
Un saludo
Hola Enrique. En mis pruebas, el que dice ble_camera no me funcionó, pero puede que exista una nueva versión. La verdad no sé en que se diferencian, como dices será que añade algo para BT…
Intento cargar un programa en micropython con la ESP32 Cam pero la que tiene el sensor PiR incorporado, además de la OLED; el SP32, el micro ESP32 es el ESP32-WROER-BMe sale el siguiente error: Error= Camera Init Failed. No se que puede ser… Gracias.
Hola Amado. Por lo que me describes me parece que tu cámara es la TTGO T-Camera de la marca Lilygo. Si es así, debe tener conexiones diferentes a la de la ESP32-CAM que utilicé yo y el firmware no está adaptado para ese modelo en particular.
Buenas profe, acabo de seguir los pasos que indicas y pude instalar firm y correr perfectamente el programa. El inconveniente que tengo es que cuando descargo las imagenes creadas no las puedo abrir me indica que están dañadas. que puede llegar a ser? estimo que debe ser un tema de formato…. agradeceria tu ayuda. saludos
Hola Gustavo, las descargas a la computadora y luego intentas abrirlas?
Puedes hacer un video del proceso para usar la sd