refactor: enhance mock camera classes and update camera detection logic
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
GP_WIDGET_WINDOW = 0
|
||||
GP_WIDGET_SECTION = 0
|
||||
GP_WIDGET_TEXT = 0
|
||||
GP_WIDGET_RANGE = 0
|
||||
GP_WIDGET_TOGGLE = 0
|
||||
GP_WIDGET_RADIO = 0
|
||||
GP_WIDGET_MENU = 0
|
||||
GP_WIDGET_BUTTON = 0
|
||||
GP_WIDGET_DATE = 0
|
||||
|
||||
class GPhoto2Error(Exception):
|
||||
pass
|
||||
|
||||
@@ -19,6 +29,65 @@ class CameraFileMock:
|
||||
return self._data
|
||||
return self._data, len(self._data)
|
||||
|
||||
class CameraListMock:
|
||||
def count(self):
|
||||
return 1
|
||||
|
||||
def get_name(self, idx):
|
||||
return f"mock_name {idx}"
|
||||
|
||||
def get_value(self, idx):
|
||||
return f"mock_value {idx}"
|
||||
|
||||
class MockPortInfo:
|
||||
def __init__(self, address):
|
||||
self.address = address
|
||||
|
||||
class PortInfoList:
|
||||
def __init__(self):
|
||||
self._ports = []
|
||||
|
||||
def load(self):
|
||||
# Dodaj przykładowe porty
|
||||
self._ports = [MockPortInfo("usb:001,002"), MockPortInfo("usb:001,003")]
|
||||
|
||||
def lookup_path(self, port_address):
|
||||
for idx, port in enumerate(self._ports):
|
||||
if port.address == port_address:
|
||||
return idx
|
||||
raise ValueError("Port not found")
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self._ports[idx]
|
||||
|
||||
class ConfigMock:
|
||||
def get_id(self):
|
||||
return 0
|
||||
def get_name(self):
|
||||
return "name"
|
||||
def get_label(self):
|
||||
return "label"
|
||||
def get_type(self):
|
||||
return 0
|
||||
def get_value(self):
|
||||
return "value"
|
||||
def get_choices(self):
|
||||
return []
|
||||
def count_children(self):
|
||||
return 0
|
||||
def get_child(self):
|
||||
return ConfigMock()
|
||||
|
||||
|
||||
class CameraAbilitiesList:
|
||||
def __init__(self) -> None:
|
||||
self.abilities = []
|
||||
def load(self):
|
||||
return
|
||||
def lookup_model(self, name):
|
||||
return 1
|
||||
def get_abilities(self, abilities_index):
|
||||
return 0
|
||||
|
||||
class Camera:
|
||||
def __init__(self):
|
||||
@@ -62,3 +131,18 @@ class Camera:
|
||||
|
||||
self._frame_counter += 1
|
||||
return CameraFileMock(frame)
|
||||
|
||||
def set_port_info(self, obj):
|
||||
return False
|
||||
|
||||
def get_config(self):
|
||||
return ConfigMock()
|
||||
|
||||
def set_single_config(self, name, widget):
|
||||
return True
|
||||
|
||||
def gp_camera_autodetect():
|
||||
return CameraListMock()
|
||||
|
||||
def check_result(obj):
|
||||
return obj
|
||||
@@ -1,11 +1,15 @@
|
||||
from typing import Optional, List
|
||||
from dataclasses import dataclass, field
|
||||
import gphoto2 as gp
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from .base_camera import BaseCamera
|
||||
|
||||
try:
|
||||
import gphoto2 as gp # type: ignore
|
||||
except:
|
||||
import controllers.mock_gphoto as gp
|
||||
|
||||
camera_widget_types = {
|
||||
gp.GP_WIDGET_WINDOW: "GP_WIDGET_WINDOW", # type: ignore
|
||||
gp.GP_WIDGET_SECTION: "GP_WIDGET_SECTION", # type: ignore
|
||||
@@ -18,6 +22,16 @@ camera_widget_types = {
|
||||
gp.GP_WIDGET_DATE: "GP_WIDGET_DATE", # type: ignore
|
||||
}
|
||||
|
||||
operations = [
|
||||
("GP_OPERATION_NONE", gp.GP_OPERATION_NONE), # type: ignore
|
||||
("GP_OPERATION_CAPTURE_IMAGE", gp.GP_OPERATION_CAPTURE_IMAGE), # type: ignore
|
||||
("GP_OPERATION_CAPTURE_VIDEO", gp.GP_OPERATION_CAPTURE_VIDEO), # type: ignore
|
||||
("GP_OPERATION_CAPTURE_AUDIO", gp.GP_OPERATION_CAPTURE_AUDIO), # type: ignore
|
||||
("GP_OPERATION_CAPTURE_PREVIEW", gp.GP_OPERATION_CAPTURE_PREVIEW), # type: ignore
|
||||
("GP_OPERATION_CONFIG", gp.GP_OPERATION_CONFIG), # type: ignore
|
||||
("GP_OPERATION_TRIGGER_CAPTURE", gp.GP_OPERATION_TRIGGER_CAPTURE), # type: ignore
|
||||
]
|
||||
|
||||
|
||||
class GPhotoCamera(BaseCamera):
|
||||
def __init__(self) -> None:
|
||||
@@ -33,11 +47,21 @@ class GPhotoCamera(BaseCamera):
|
||||
if not cameras or cameras.count() == 0: # type: ignore
|
||||
return {}
|
||||
|
||||
abilities_list = gp.CameraAbilitiesList() # type: ignore
|
||||
abilities_list.load()
|
||||
camera_list = {}
|
||||
for i in range(cameras.count()): # type: ignore
|
||||
name = cameras.get_name(i) # type: ignore
|
||||
port = cameras.get_value(i) # type: ignore
|
||||
camera_list[i] = {"name": name, "port": port}
|
||||
|
||||
abilities_index = abilities_list.lookup_model(name)
|
||||
abilities = abilities_list.get_abilities(abilities_index)
|
||||
abilities_name = []
|
||||
for name, bit in operations:
|
||||
if abilities.operations & bit: # type: ignore
|
||||
abilities_name.append(name)
|
||||
|
||||
camera_list[i] = {"name": name, "port": port, "abilities": abilities_name}
|
||||
return camera_list
|
||||
|
||||
def connect(self, index: int | None = None) -> bool:
|
||||
@@ -117,7 +141,7 @@ class GPhotoCamera(BaseCamera):
|
||||
if not self.camera:
|
||||
return False
|
||||
|
||||
self.camera.set_single.config(config['name'], config['widget'])
|
||||
self.camera.set_single_config(config['name'], config['widget'])
|
||||
return True
|
||||
|
||||
def parse_config(self, config):
|
||||
|
||||
@@ -28,24 +28,18 @@ class OpenCvCamera(BaseCamera):
|
||||
def detect():
|
||||
camera_list = enumerate_cameras(cv2.CAP_ANY)
|
||||
result = {}
|
||||
seen_ports = set()
|
||||
|
||||
for camera in camera_list:
|
||||
# unikamy duplikatów tego samego /dev/videoX albo tej samej ścieżki na Windows/macOS
|
||||
if camera.path in seen_ports:
|
||||
continue
|
||||
|
||||
cap = cv2.VideoCapture(camera.index, camera.backend) # próbujemy otworzyć
|
||||
ret, frame = cap.read()
|
||||
cap = cv2.VideoCapture(camera.index, camera.backend)
|
||||
# ret, frame = cap.read()
|
||||
cap.release()
|
||||
|
||||
if ret and frame is not None and frame.size > 0:
|
||||
result[camera.index] = {
|
||||
"name": camera.name,
|
||||
"port": camera.path,
|
||||
"backend": camera.backend,
|
||||
}
|
||||
seen_ports.add(camera.path)
|
||||
# if ret and frame is not None and frame.size > 0:
|
||||
result[camera.index] = {
|
||||
"name": camera.name,
|
||||
"port": camera.path,
|
||||
"backend": camera.backend,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user