diff --git a/dslr_helper.py b/dslr_helper.py
index b6238b9..08e421e 100644
--- a/dslr_helper.py
+++ b/dslr_helper.py
@@ -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))
diff --git a/frame_opencv.py b/frame_opencv.py
index fd4491d..a7dc528 100644
--- a/frame_opencv.py
+++ b/frame_opencv.py
@@ -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)
diff --git a/readme.md b/readme.md
index b16f246..a6d262f 100644
--- a/readme.md
+++ b/readme.md
@@ -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).**
@@ -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) | | | ✓ | | |
+| PC Linux (Debian, Manjaro) | ✓ | ✓ | N/A | N/A | ✓ |
+
+## 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`
diff --git a/serialutils.py b/serialutils.py
index f51d4a5..8e0daa4 100644
--- a/serialutils.py
+++ b/serialutils.py
@@ -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()
\ No newline at end of file
+ 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())
\ No newline at end of file