Fix picam support

This commit is contained in:
ABelliqueux 2025-02-15 10:08:13 +01:00
parent d254b6307b
commit e03d5e7872
4 changed files with 72 additions and 32 deletions

View File

@ -29,12 +29,12 @@ import sys
import gphoto2 as gp
camera_current_settings = {
'capturemode' : 3, # use IR remote
'imagesize' : 2, # use size S (1936x1296)
'whitebalance' : 1, # Natural light
'capturetarget' : 0, # Internal memory
'nocfcardrelease' : 0, # Allow capture without sd card
'recordingmedia' : 1, # Write to RAM
'capturemode' : dict(min=0, max=4, default=0, value=3), # 0: single,1: burst,2:Timer,3:2S Remote,4:Quick remote
'imagesize' : dict(min=0, max=2, default=0, value=2), # 0:L, 1:M, 2: S (1936x1296)
'whitebalance' : dict(min=0, max=7, default=0, value=1), # 0 Automatic 1 Daylight 2 Fluorescent 3 Tungsten 4 Flash 5 Cloudy 6 Shade 7 Preset
'capturetarget' : dict(min=0, max=1, default=0, value=0), # Internal memory
# ~ 'nocfcardrelease' : dict(min=0, max=1, default=0, value=0), # Allow capture without sd card
# ~ 'recordingmedia' : dict(min=0, max=1, default=0, value=1), # Write to RAM
}
def initialize_camera():
@ -50,14 +50,30 @@ def initialize_camera():
return camera, current_camera_config
def apply_gphoto_setting(config, setting, new_value):
# TODO: find how to use gp.CameraWidget.get_range() and check parameter value is in range before applying.
def apply_gphoto_setting(config, setting, new_value, inc=False):
# find the $setting config item
try:
# Get widget with name $setting
cur_setting = gp.check_result(gp.gp_widget_get_child_by_name(config, setting))
# find corresponding choice
cur_setting_choice = gp.check_result(gp.gp_widget_get_choice(cur_setting, new_value))
# set config value
gp.check_result(gp.gp_widget_set_value(cur_setting, cur_setting_choice))
# Get a list of available choices
choices = list(gp.check_result(gp.gp_widget_get_choices(cur_setting)))
# Build dict with name/value equivalence
choices_dict = {choices.index(i):i for i in list(choices)}
# Increment mode : current value is increased or looped
if inc:
# Get current setting value
new_value = gp.check_result(gp.gp_widget_get_value(cur_setting))
# Check current value + 1 is in range
if new_value in range(0, len(choices)):
# Apply or loop value accordingly
pass
# If new_value exists in list, apply
if new_value['value'] in choices_dict:
cur_setting_choice = gp.check_result(gp.gp_widget_get_choice(cur_setting, new_value['value']))
# set config value
gp.check_result(gp.gp_widget_set_value(cur_setting, cur_setting_choice))
except:
print("Configuration error while setting {} to {}".format(setting, new_value))
@ -66,15 +82,13 @@ def apply_dslr_settings(camera_settings):
camera, config = initialize_camera()
# iterate over the settings dictionary
for setting in camera_settings:
print(setting)
print(camera_settings[setting])
apply_gphoto_setting(config, setting, camera_settings[setting])
# validate config
status = gp.check_result(gp.gp_camera_set_config(camera, config))
# close camera
camera.exit()
return status
def check_status_value(config, value, optimal_value=None):
cur_check = gp.check_result(gp.gp_widget_get_child_by_name(config, value))

View File

@ -2,6 +2,7 @@
import cv2
import gettext
from itertools import count
from importlib import import_module
import os
# Needed for utf-8 text
from PIL import ImageFont, ImageDraw, Image
@ -222,7 +223,7 @@ class webcam():
class showmewebcam(webcam):
def __init__(self):
self.serialutils = __import__('serialutils')
self.serialutils = import_module('serialutils')
super().__init__()
self.camera_current_settings = {
'auto_exposure': dict(min=0, max=1, step=1, default=camera_settings['auto_exposure'], value=camera_settings['auto_exposure']),
@ -267,8 +268,10 @@ class picam():
self.onionskin_was_on = self.onionskin
self.liveview_only = False
# Pi Cam V3 setup
self.Picamera2 = __import__('picamera2.Picamera2')
self.Transform = __import__('libcamera.Transform')
self.Picamera2 = getattr(import_module('picamera2'), 'Picamera2')
self.Transform = getattr(import_module('libcamera'), 'Transform')
# ~ self.Picamera2 = __import__('picamera2.Picamera2')
# ~ self.Transform = __import__('libcamera.Transform')
# ~ from picamera2 import Picamera2
# ~ from libcamera import Transform
try:
@ -308,10 +311,7 @@ class picam():
# Same as in webcam() class
def capture_preview(self):
ret, overlay = self.cam.read()
if not ret:
print(_("Failed to grab frame."))
return False
overlay = cam.capture_array("main")
# Resize preview to fit screen
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
if self.liveview_only:
@ -359,10 +359,11 @@ class picam():
self.cam.set_controls({'AeFlickerMode': 1, 'AeFlickerPeriod':10000})
def apply_setting(self, to_set:list=None, inc:bool=False):
for setting in to_set:
if inc:
self.increment_setting(setting)
self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']})
if to_set is not None:
for setting in to_set:
if inc:
self.increment_setting(setting)
self.cam.set_controls({self.cam_settings_map[setting] : self.camera_current_settings[setting]['value']})
def flip_image(self):
self.cam.stop()
@ -390,7 +391,7 @@ class picam():
class dslr():
def __init__(self):
# ~ import gphoto2 as gp
self.gp = __import__('gphoto2')
self.gp = import_module('gphoto2')
self.camera_current_settings = {
'capturemode' : dict(min=0, max=4, default=0, value=1), # 0: single,1: burst,2:Timer,3:2S Remote,4:Quick remote
'imagesize' : dict(min=0, max=2, default=2, value=2), # 0:L, 1:M, 2: S (1936x1296)

View File

@ -1,9 +1,8 @@
# Stopi2
## Branche libcamera
## Branche gphoto / réflexe nunmérique
**Ceci est la branche qui restaure la possibilité d'utiliser des périphériques compatibles rpi-libcamera (Modules Raspicam v1,v2 et v3).**
**En utilisant la [branche correspondante pour la télécommande picote](/arthus/picote/src/branch/picamera), vous pouvez régler la mise au point du module caméra avec un [codeur rotatif](https://fr.wikipedia.org/wiki/Codeur_rotatif).**
**Ceci est la branche qui restaure la possibilité d'utiliser des périphériques compatibles [gphoto](http://gphoto.org/doc/remote).**
<a style="max-height: 300px;display: inline-block;" href="./stopi2/raw/branch/master/stopi_station.jpg"><img src="./stopi_station.jpg"/><a/>
@ -16,6 +15,7 @@ Encore une fois, l'objectif est de créer un logiciel simple et minimaliste dans
* [Pelure d'oignon](https://fr.wikipedia.org/wiki/Pelure_d'oignon#Sciences_et_techniques) entre la dernière image et le flux vidéo.
* Un seul fichier de configuration permet de régler les options (résolution, images/secondes, mirroir vertical/horizontal, )
* Auto configuration de la camera au démarrage (exposition et balance des blancs)
* Pilotage de certains réglages de la caméra depuis la télécommande/clavier (balance des blancs, rotation de l'image, mise au point (picam V3), exposition...)
* Prévisualisation de l'animation
* Exportation vidéo avec [ffmpeg](https://ffmpeg.org/)
* Interface localisée (anglais et français disponible pour le moment.)
@ -23,6 +23,22 @@ Encore une fois, l'objectif est de créer un logiciel simple et minimaliste dans
## Banc de test
Ce script a été testé avec une webcam compatible V4L2, une ["showmewebcam"](https://github.com/showmewebcam/showmewebcam) à base de rpi 0 et d'un module caméra v2 (8Mp), et un ordinateur classique sous [Debian](https://debian.org) et un [RPI 4B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) munis d'un module [Picamera V3](https://www.raspberrypi.com/products/camera-module-3/).
Voici un récapitulatif des tests effectués :
| Machine \ Type de Caméra | Webcam | [Showmewebcam](https://github.com/showmewebcam/showmewebcam) | RPI Caméra module V1 (5MP) | [RPI Caméra module V3](https://www.raspberrypi.com/products/camera-module-3/) (12MP) | [Réflexe numérique](http://gphoto.org/doc/remote) (Nikon D3000/D40x)|
| --- | --- | --- | --- | --- | --- |
| Raspberry Pi 4B (Debian 12) | | | &check; | | |
| PC Linux (Debian, Manjaro) | &check; | &check; | N/A | N/A | &check; |
## Feuille de route
Des fonctions supplémentaires sont prévues :
* Réflexe numérique: utilisation du liveview de l'appareil (si je trouve un modèle compatible pour le développement)
## Contributions
Les contributions et rapports de bugs sont les bienvenus !
## Installation
@ -33,15 +49,16 @@ Dans un terminal :
1. Installer les dépendances suivantes :
```
# Avec une distribution basée sur Debian (Ubuntu, Mint...)
sudo apt install --no-install-recommends --no-install-suggests git ffmpeg python3-pip python3-venv libtiff5-dev libtopenjp2 libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev libharfbuzz-dev libfribidi-dev libxcb1-dev python3-tk python3-dev libopenblas-dev libatlas-base-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev libqtgui4 libqt4-test v4l-utils
sudo apt install --no-install-recommends --no-install-suggests git ffmpeg python3-pip python3-venv libtiff5-dev libopenjp2-7 libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev libharfbuzz-dev libfribidi-dev libxcb1-dev python3-tk python3-dev libopenblas-dev libatlas-base-dev libhdf5-dev libhdf5-serial-dev libatlas-base-dev libjasper-dev libqtgui4 libqt4-test v4l-utils
```
- (Optionnel) Pour installer un environnement graphique minimal sur une [installation console](https://debian-facile.org/doc:install:installation-minimale) : `sudo apt install --no-install-recommends --no-install-suggests openbox xserver-xorg xinit pcmanfm gmrun lxterminal hsetroot unclutter plymouth plymouth-themes`
2. Cloner le dépôt dans le dossier de votre choix : `git clone https://git.arthus.net/arthus/stopi2.git`
3. Aller dans répertoire du projet : `cd stopi2`
4. Créer un environnement virtuel (venv) Python : `python -m venv ./`
- `pip install -vvv --upgrade pip setuptools wheel`
- (Optionnel) Dans le cas de l'utilisation d'une "raspicam", il faudra ajouter le paramètre `--system-site-packages` pour avoir accès au module picamera2, et installer la librairie correspondante `python3-picamera2`.
5. Activer l'environnement virtuel avec `source bin/activate`
6. Installer les dépendances python (~150Mo) : `pip install -r requirements.txt`
6. Installer les dépendances python (~150Mo) : `MAKEFLAGS="-j$(nproc)" pip install -r requirements.txt`
7. Activer l'éxécution du script : `chmod +x stopi2.sh`
8. Lancer le script : `./stopi2.sh`

View File

@ -15,4 +15,12 @@ def send_serial_cmd(cam_port, cmd:str, clear=True):
else:
append = b'\r'
con.write(str.encode(cmd) + append)
con.close()
con.close()
def main():
cmd = "/usr/bin/v4l2-ctl --all"
send_serial_cmd(find_cam_port(), cmd)
if __name__ == '__main__':
import sys
sys.exit(main())