feat: read gphoto config

This commit is contained in:
2025-09-21 18:46:38 +02:00
parent 508930ae39
commit 19e2c7977c
3 changed files with 94 additions and 9 deletions

View File

@@ -31,6 +31,9 @@ class MainController:
self.photo_button: QPushButton = view.photo_button self.photo_button: QPushButton = view.photo_button
self.photo_button.clicked.connect(self.take_photo) self.photo_button.clicked.connect(self.take_photo)
self.record_button: QPushButton = view.record_button
# self.record_button.clicked.connect(self.fun_test)
self.color_list.colorSelected.connect(self.on_color_selected) self.color_list.colorSelected.connect(self.on_color_selected)
self.color_list.editColor.connect(self.on_edit_color) self.color_list.editColor.connect(self.on_edit_color)
self.thumbnail_list.selectedThumbnail.connect(self.on_thumbnail_selected) self.thumbnail_list.selectedThumbnail.connect(self.on_thumbnail_selected)
@@ -84,7 +87,7 @@ class MainController:
def start_liveview(self): def start_liveview(self):
self.manager.start_camera() self.manager.start_camera()
self.manager.start_stream() # self.manager.start_stream()
def shutdown(self): def shutdown(self):
self.manager.stop() self.manager.stop()

View File

@@ -19,13 +19,15 @@ class CameraManager(QThread):
self.is_connected = False self.is_connected = False
self.start()
def run(self) -> None:
self.timer = QTimer() self.timer = QTimer()
self.timer.setInterval(int(1000 / self.fps)) self.timer.setInterval(int(1000 / self.fps))
self.timer.timeout.connect(self._update_frame) self.timer.timeout.connect(self._update_frame)
self.start()
def run(self) -> None:
# self.timer = QTimer()
# self.timer.setInterval(int(1000 / self.fps))
# self.timer.timeout.connect(self._update_frame)
self.exec() self.exec()
def start_camera(self) -> None: def start_camera(self) -> None:

View File

@@ -1,30 +1,63 @@
from typing import Optional, List
from dataclasses import dataclass, field
import gphoto2 as gp import gphoto2 as gp
import cv2 import cv2
import numpy as np import numpy as np
from .base_camera import BaseCamera from .base_camera import BaseCamera
camera_widget_types = {
gp.GP_WIDGET_WINDOW: "GP_WIDGET_WINDOW", # type: ignore
gp.GP_WIDGET_SECTION: "GP_WIDGET_SECTION", # type: ignore
gp.GP_WIDGET_TEXT: "GP_WIDGET_TEXT", # type: ignore
gp.GP_WIDGET_RANGE: "GP_WIDGET_RANGE", # type: ignore
gp.GP_WIDGET_TOGGLE: "GP_WIDGET_TOGGLE", # type: ignore
gp.GP_WIDGET_RADIO: "GP_WIDGET_RADIO", # type: ignore
gp.GP_WIDGET_MENU: "GP_WIDGET_MENU", # type: ignore
gp.GP_WIDGET_BUTTON: "GP_WIDGET_BUTTON", # type: ignore
gp.GP_WIDGET_DATE: "GP_WIDGET_DATE", # type: ignore
}
@dataclass
class CameraWidget:
id: int
name: str
label: str
type: str
widget: object
value: Optional[str] = None
choices: List[str] = field(default_factory=list)
def __str__(self) -> str:
return f"[{self.id} - {self.type}] '{self.name}' {self.label}\n\tvalue = {self.value} | choices = {self.choices}"
class GPhotoCamera(BaseCamera): class GPhotoCamera(BaseCamera):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.camera = None self.camera = None
self.widgets: List[CameraWidget] = []
def connect(self) -> bool: def connect(self) -> bool:
self.error_msg = None self.error_msg = None
try: try:
self.camera = gp.Camera() # type: ignore self.camera = gp.Camera() # type: ignore
self.camera.init() self.camera.init()
self.read_config()
widget = self.get_setting_by_name("iso")
self.set_setting_by_id(widget.id, "100")
return True return True
except Exception as e: except Exception as e:
self.error_msg = f"[GPHOTO2] {e}" self.error_msg = f"[GPHOTO2] {e}"
self.camera = None self.camera = None
return False return False
def disconnect(self) -> None: def disconnect(self) -> None:
if self.camera: if self.camera:
self.camera.exit() self.camera.exit()
self.camera = None self.camera = None
self.widgets.clear()
def get_frame(self): def get_frame(self):
self.error_msg = None self.error_msg = None
@@ -32,15 +65,62 @@ class GPhotoCamera(BaseCamera):
if self.camera is None: if self.camera is None:
self.error_msg = "[GPHOTO2] Camera is not initialized." self.error_msg = "[GPHOTO2] Camera is not initialized."
return (False, None) return (False, None)
try: try:
file = self.camera.capture_preview() # type: ignore file = self.camera.capture_preview() # type: ignore
data = file.get_data_and_size() data = file.get_data_and_size()
frame = np.frombuffer(data, dtype=np.uint8) frame = np.frombuffer(data, dtype=np.uint8)
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR) frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
return (True, frame) return (True, frame)
except Exception as e: except Exception as e:
self.error_msg = f"[GPHOTO2] {e}" self.error_msg = f"[GPHOTO2] {e}"
return (False, None) return (False, None)
def get_setting_by_id(self, id: int) -> CameraWidget:
return next(w for w in self.widgets if w.id == id)
def get_setting_by_name(self, name: str) -> CameraWidget:
return next(w for w in self.widgets if w.name == name)
def set_setting_by_id(self, id: int, value: str):
widget = self.get_setting_by_id(id)
if value in widget.choices:
widget.widget.set_value(value) # type: ignore
self.camera.set_single_config(widget.name, widget.widget) # type: ignore
def read_config(self):
if not self.camera:
return
self.widgets.clear()
def parse_widget(widget):
temp_widget = CameraWidget(
id=widget.get_id(),
name=widget.get_name(),
label=widget.get_label(),
type=camera_widget_types[widget.get_type()],
widget=widget
)
try:
temp_widget.value = widget.get_value()
except gp.GPhoto2Error:
pass
try:
temp_widget.choices = list(widget.get_choices())
except gp.GPhoto2Error:
pass
self.widgets.append(temp_widget)
for i in range(widget.count_children()):
parse_widget(widget.get_child(i))
config = self.camera.get_config()
parse_widget(config)
for wid in self.widgets:
print(wid)