Cámara Raspberry Pi

En esta entrada vamos a hablar sobre la cámara de Raspberry Pi.
Lo primero que tenemos que hacer es conectarla al CSI de la Raspberry Pi como muestra la siguiente imagen:
Ahora encendemos la Raspberry Pi, y si estamos usando el sistema operativo Raspbian, tenemos dos opciones para habilitarla, dependiendo de si trabajamos con entorno grafico o no.
Si queremos habilitarla utilizando comandos, podemos hacerlo de la siguiente manera:
sudo raspi-config
Nos mostrará lo siguiente:
Donde seleccionamos la opción Enable Camera y a continuación pedirá reiniciar la Raspberry para guardar los cambios.
En caso de querer habilitar la cámara usando el entorno grafico, tenemos que seleccionar desde el menu de inicio / preferencias y buscamos la herramienta de Configuración de Raspberry.
Y nos abrirá la siguiente ventana:
Donde marcamos el check de Enabled de la camara y le damos al botón OK. Después reiniciamos la Raspberry Pi.
MJPG-Streamer
Para poder visualizar ‘en tiempo real’ las imágenes o vídeos que este capturando la cámara es necesario crear algún buffer o streamer entre el ordenador y la Raspberry pi, que permitan la descarga y reproducción de archivos (imagen o video) con un cierto peso.
Mjpeg_streamer es un programa que obtiene cada jpeg de la cámara y lo envía a un cliente ejecutado en un ordenador, móvil o Tablet a través de una sesión HTTP, pudiendo reproducirse los datos en cualquier navegador web, o hasta en el programa VideoLanClient (VLC).
Para poder visualizar dicho contenido es necesario realizar los siguientes pasos:
-
Instalar en la Raspberry Pi las librerías libjpeg8-dev, imagemagick y libv4l-dev:
sudo apt-get install libjpeg8-dev imagemagick libv4l-dev
-
Se crea un enlace simbólico (comando ln -s) a la cabecera videodev.h
sudo ln -s /usr/include/linux/videodev2.h /usr/include/linux/videodev.h
-
Se descarga MJPG-Streamer:
wget http://lilnetwork.com/download/raspberrypi/mjpg-streamer.tar.gz
-
Se descomprime:
tar xvzf mjpg-streamer.tar.gz
-
Se instala:
cd mjpg-streamer/mjpg-streamer
./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"
-
Se copian los ficheros necesarios a los directorios del sistema:
sudo cp mjpg_streamer /usr/local/bin
sudo cp output_http.so input_uvc.so /usr/local/lib/
sudo cp -R www /usr/local/www
-
Se crea el directorio temporal donde se irán almacenando las imágenes de la cámara:
mkdir /tmp/stream
-
Ahora solo falta iniciar el MJPG-Streamer:
LD_LIBRARY_PATH=/usr/local/lib mjpg_streamer -i "input_file.so -f /tmp/stream -n pic.jpg" -o "output_http.so -w /usr/local/www"
Si queremos automatizar estos ultimos paso, para que se lancen automaticamente cuando se encienda la Raspberry Pi, podemos crear un script, (inicio.sh) con las siguientes líneas:
#! /bin/bash
# -*- ENCODING: UTF-8 -*-
sudo mkdir /tmp/stream
LD_LIBRARY_PATH=/usr/local/lib mjpg_streamer -i "input_file.so -f /tmp/stream -n pic.jpg" -o "output_http.so -w /usr/local/www"
Ahora tendremos que escribir al final del fichero /home/pi/.bashrc
la siguiente línea:
bash /home/pi/RAISPI/inicio.sh
Para ver las imagenes o videos, se introduce lo siguiente en cualquier navegador de internet:
http://localhost:8080
(si se está probando desde la propia Raspberry Pi)
http://<IP-address>:8080
(Si se está probando desde otro dispositivo, sustituyendo ese por la IP de la Raspberry pi)
Y obtendríamos algo como lo siguiente:
Librería Python picamera
Otra opción para tomar fotos, o grabar video, es crear nuestro propio programa por ejemplo en Python, y usar las librerias que se han desarollado para la cámara como por ejemplo la picamera. Aquí os dejamos un programa que además de poder poner efectos a las fotos que se hagan, o relizar configuraciones de los parámetros de la cámara (resolución, ISO, calidad …) nos permite crear un stream continuo de imágenes, que luego puede mostrarse en un cliente.
#!/usr/bin/python
# -*- coding: utf-8 -*-
#################################################
#
# Camera control module
# Authors: Ismael Tobar and Raquel Muñoz
#################################################
#----Libraries
from time import sleep
import picamera
import RPi.GPIO as GPIO #to control GPIO of the camera led
import threading
import socket
import struct
import io
import errno
#status variables
DISCONNECTED = 0
CONNECTED_OK = 1
CONNECTED_ERROR = 2
status = DISCONNECTED #It's a variable that indicate the error state of the camera
#variables of the camera
path = '/tmp/stream/pic.jpg'
stop = True #to start and stop the thread
camera_resolution_w = 640 #2592 is the max
camera_resolution_h = 480 #1944 is the max
camera_framerate = 15
camera_quality = 5
camera_format = 'jpeg'
camera_brightness = 50 #Valid values are between 0 and 100
camera_exposure_mode = 'auto'
camera_image_effect = 'none'
camera_iso = 0 #Valid values are between 0 (auto) and 1600
camera_led = True
camera_rotation = 0 #Valid values are 0, 90, 180, and 270
camera_saturation = 0 #the color saturation of the camera can be an integer between -100 and 100
camera_sharpness = 0 #the sharpness of the camera can be an integer between -100 and 100
camera_zoom = (0.0, 0.0, 1.0, 1.0)
i = 0
def capturing():
global i
global status
try:
with picamera.PiCamera() as camera:
#we configure the parameters of the camera
camera.resolution = (camera_resolution_w, camera_resolution_h)
camera.framerate = camera_framerate
camera.brightness = camera_brightness
camera.sharpness = camera_sharpness
camera.iso = camera_iso
#camera.start_preview()
camera.rotation = camera_rotation
camera.image_effect = camera_image_effect
camera.zoom = camera_zoom
sleep(0.8)
end_of_image = eoi = '\xff\xd9'
server_socket = socket.socket()
print("Camera: socket created")
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)
print("Camera: socket listening ...")
# Accept a connection
connection = server_socket.accept()[0].makefile('rb')
print("Camera: socket accept")
stream = io.BytesIO()
status = CONNECTED_OK
try:
for foo in camera.capture_continuous(stream, 'jpeg', quality = camera_quality):
#time.sleep(0.2)
connection.write(struct.pack('<L', stream.tell()))
connection.flush()
stream.seek(0)
#send the image
connection.write(stream.read())
connection.flush()
if stop == True:
break
# Reset the stream for the next capture
stream.seek(0)
stream.truncate()
connection.write(struct.pack('<L', 0))
status = DISCONNECTED
print("Camera: break")
except Exception as e:
status = CONNECTED_ERROR
print("Camera capturing exception: ",e)
finally:
camera.close()
connection.close()
server_socket.close()
print("Camera: closed")
print("Camera: exit")
except Exception as e:
if e.errno == errno.EPIPE:
status = DISCONNECTED
print("errno")
else:
i += 1
status = CONNECTED_ERROR
print("Camera exception: ", e)
finally:
picamera.PiCamera().close()
connection.close()
server_socket.close()
print("Camera: closed 2")
def startCamera():
global stop
if stop == True: #it is checked that this thread is started
stop = False
tcamara = threading.Thread(target=capturing)
tcamara.start()
def stopCamera():
global stop
stop = True
def changeQuality(q):
global camera_quality
stopCamera()
if (1<= q <= 100):
camera_quality = q
def changeResolutionHeight(res_h):
global camera_resolution_h
stopCamera()
if (480<= res_h <= 1944):
camera_resolution_h = res_h
def changeResolutionWeight(res_w):
global camera_resolution_w
stopCamera()
if (640 <= res_w <= 2592):
if res_w:
changeCameraFramerate(15) #Because when the resolution is bigger than 1000 it's recommended to set that framerate
camera_resolution_w = res_w
def changeBrightness(b):
global camera_brightness
stopCamera()
if (0 <= b <= 100):
camera_brightness = b
def changeSharpness(s):
global camera_sharpness
stopCamera()
if (-100 <= s <= 100):
camera_sharpness = s
def changeZoom(z):
global camera_zoom
stopCamera()
if (0 <= z <= 100):
z_aux = z/100
camera_zoom = (z_aux,z_aux,1.0,1.0)
def calculateResolution(res, weight_gave = True):
if weight_gave == True: #It means that the value gave is the weight, so we have to calculate the height
if res == 1920:
r_adjusted = 1080 #In this case the aspect ratio is 16:9
elif res == 1296:
r_adjusted = 730 #In this case the aspect ratio is 16:9
elif (640 <= res <= 2592):
r_adjusted = 3*res/4 #In this case the aspect ratio is 4:3
else:
if res == 1080:
r_adjusted = 1920 #In this case the aspect ratio is 16:9
elif res == 730:
r_adjusted = 1296 #In this case the aspect ratio is 16:9
elif (480 <= res <= 1944):
r_adjusted = 4*res/3 #In this case the aspect ratio is 4:3
return r_adjusted
def changeCameraFramerate(f):
global camera_framerate
stopCamera()
if (1 <= f <= 30):
stopCamera()
camera_framerate = f
sleep(0.1)
def changeCameraRotation(d):
global camera_rotation
stopCamera()
if ((d == 0) or (d == 90) or (d == 180) or (d == 270)):
stopCamera()
sleep(0.1)
camera_rotation = d
def changeCameraIso(i):
global camera_iso
stopCamera()
if(0 <= i <= 1600):
stopCamera()
sleep(0.1)
camera_iso = i
def setEffect(e):
global camera_image_effect
global i
i = 0
settign_effect = True
try:
while ((settign_effect == True) and (i < 4)):
stopCamera()
if e == 2:
camera_image_effect = 'negative'
elif e == 3:
camera_image_effect = 'solarize'
elif e == 4:
camera_image_effect = 'emboss'
elif e == 5:
camera_image_effect = 'watercolor'
elif e == 6:
camera_image_effect = 'cartoon'
elif e == 7:
camera_image_effect = 'film'
elif e == 8:
camera_image_effect = 'posterise'
elif e == 9:
camera_image_effect = 'sketch'
elif e == 10:
camera_image_effect = 'oilpaint'
elif e == 11:
camera_image_effect = 'denoise'
elif e == 12:
camera_image_effect = 'gpen'
else:
camera_image_effect = 'none'
sleep(0.1)
startCamera()
settign_effect = False
except Exception as e:
i += 1
if __name__ == "__main__":
terminate = False #finish the while()
# if run directly we'll just create an instance of the class and output
option = 12 #Value not valid
while terminate == False:
sleep(0.1)
option = input('#################################### Menu Camera Robot ######################################\n 0 -> Exit \n 1 -> On camera \n 2 -> Off camera \n 3 -> Change brightness of the camera \n 4 -> Change sharpness of the camera \n 5 -> Change resolution of the camera\n 6 -> Change Effects\n 7 -> Change Zoom\n 8 -> Change Rotation\n 9 -> Change iso\n 10 -> Change Framerate\nOption chosen: \n')
if option == 0:
stopCamera()
terminate = True
elif option == 1:
startCamera()
elif option == 2:
stopCamera()
elif option == 3:
aux = input('Enter the brightness value of the camera (between 0 and 100: )')
if (0 <= aux <= 100):
stopCamera()
changeBrightness(aux)
startCamera()
else:
print('Value not valid')
elif option == 4:
aux = input('Enter the sharpness value of the camera (between -100 and 100: )')
if (-100 <= aux <= 100):
stopCamera()
changeSharpness(aux)
startCamera()
else:
print('Value not valid')
elif option == 5:
aux = input('Enter the resolution you want to change (0 to weight, 1 to height, 2 to exit: )')
if aux == 0:
aux2 = input('Enter the resolution weight: (between 640 and 2592)')
stopCamera()
changeResolutionWeight(aux2)
changeResolutionHeight(calculateResolution(aux2))
startCamera()
elif aux == 1:
aux2 = input('Enter the resolution height: (between 480 and 1944)')
stopCamera()
changeResolutionHeight(aux2)
changeResolutionWeight(calculateResolution(aux2,False))
startCamera()
else:
break
elif option == 6:
aux = input('Enter the effect you want to applicate\n 1 -> None\n 2 -> Negative\n 3 -> Solarize\n 4 -> Emboss\n 5 -> Watercolor\n 6 -> Cartoon\n 7 -> Film\n 8 -> Posterise\n 9 -> Sketch\n 10 -> Oilpaint\n 11 -> Denoise\n 12 -> Gpen\n')
if (1 <= aux <= 12):
setEffect(aux)
else:
print('Value not valid')
elif option == 7:
aux = input('Enter the zoom you want to applicate between 0 and 100%\n')
stopCamera()
changeZoom(aux)
sleep(0.1)
startCamera()
elif option == 8:
aux = input('Enter the degrees you want to rotate the camera: 0, 90, 180, 270:\n')
stopCamera()
changeCameraRotation(aux)
sleep(0.1)
startCamera()
elif option == 9:
aux = input('Enter the iso you want to applicate the camera between 0 and 1600:\n')
stopCamera()
changeCameraIso(aux)
sleep(0.1)
startCamera()
elif option == 10:
aux = input('Enter the framerate you want to applicate to the camera between 0 and 30:\n')
stopCamera()
changeCameraFramerate(aux)
sleep(0.1)
startCamera()
else:
print('Option not valid')
stopCamera()
print('Camera: Exit camera')
En nuestro caso hemos programado el cliente en Java, utilizando las librerías de github de Sarxos webcam, para poder representar en un panel de la interfaz gráfica, lo que visualiza la cámara.
Si te ha interesado esta entrada, puedes ver distintas aplicaciones de la cámara en los siguientes enlaces: