CameraActivity: make camera-independent

This commit is contained in:
Thomas Farstrike
2026-02-10 19:17:02 +01:00
parent 52d7fed8de
commit bfd3804118
4 changed files with 168 additions and 156 deletions
+29 -13
View File
@@ -126,20 +126,36 @@ SensorManager.init(None)
# === CAMERA HARDWARE ===
try:
# Try to initialize webcam to verify it's available
def init_cam(width, height, colormode):
try:
# Try to initialize webcam to verify it's available
import webcam
return webcam.init("/dev/video0", width=width, height=height)
except Exception as e:
print(f"Info: webcam initialization failed, camera will not be available: {e}")
def deinit_cam(cam_obj):
import webcam
test_cam = webcam.init("/dev/video0", width=320, height=240)
if test_cam:
webcam.deinit(test_cam)
from mpos import CameraManager
CameraManager.add_camera(CameraManager.Camera(
lens_facing=CameraManager.CameraCharacteristics.LENS_FACING_FRONT,
name="Video4Linux2 Camera",
vendor="ACME"
))
except Exception as e:
print(f"Info: webcam initialization failed, camera will not be available: {e}")
webcam.deinit(cam_obj)
def capture_cam(cam_obj, colormode):
import webcam
return webcam.capture_frame(cam_obj, "rgb565" if colormode else "grayscale")
def apply_cam_settings(cam_obj, prefs):
print("V4L Camera doesn't support settings for now, skipping...")
from mpos import CameraManager
CameraManager.add_camera(CameraManager.Camera(
lens_facing=CameraManager.CameraCharacteristics.LENS_FACING_FRONT,
name="Video4Linux2 Camera",
vendor="ACME",
init=init_cam,
deinit=deinit_cam,
capture=capture_cam,
apply_settings=apply_cam_settings
))
print("linux.py finished")
@@ -109,6 +109,8 @@ sdcard.init(cmd_pin=2,clk_pin=42,d0_pin=41)
# LightsManager will not be initialized (functions will return False)
# === CAMERA HARDWARE ===
from mpos import CameraManager
def init_cam(width, height, colormode):
try:
from camera import Camera, GrabMode, PixelFormat, FrameSize, GainCeiling
@@ -203,7 +205,11 @@ def deinit_cam(cam):
except Exception as e:
print(f"Indev enable got exception: {e}")
from mpos import CameraManager
def capture_cam(cam_obj, colormode):
return cam_obj.capture()
def apply_cam_settings(cam_obj, prefs):
return CameraManager.ov_apply_camera_settings(cam_obj, prefs)
# MaTouch ESP32-S3 has OV3660 camera (3MP, up to 2048x1536)
# Camera pins are available but initialization is handled by the camera driver
@@ -213,6 +219,7 @@ CameraManager.add_camera(CameraManager.Camera(
vendor="OmniVision",
init=init_cam,
deinit=deinit_cam,
capture=capture_cam
))
print("matouch_esp32_s3_2_8.py finished")
+122 -1
View File
@@ -37,7 +37,7 @@ class Camera:
Represents a camera device with its characteristics.
"""
def __init__(self, lens_facing, name=None, vendor=None, version=None, init=None, deinit=None):
def __init__(self, lens_facing, name=None, vendor=None, version=None, init=None, deinit=None, capture=None, apply_settings=None):
"""Initialize camera metadata.
Args:
@@ -52,6 +52,8 @@ class Camera:
self.version = version or 1
self.init_function = init
self.deinit_function = deinit
self.capture_function = capture
self.apply_settings_function = apply_settings
def __repr__(self):
facing_names = {
@@ -70,6 +72,14 @@ class Camera:
if self.deinit_function:
return self.deinit_function(cam_obj)
def capture(self, cam_obj, colormode=None):
if self.capture_function:
return self.capture_function(cam_obj, colormode)
def apply_settings(self, cam_obj, prefs):
if self.apply_settings_function:
return self.apply_settings_function(cam_obj, prefs)
class CameraManager:
"""
Centralized camera device management service.
@@ -237,6 +247,117 @@ class CameraManager:
return resolution_map.get((width, height), FrameSize.R240X240)
@staticmethod
def ov_apply_camera_settings(self, cam, prefs):
if not cam or not prefs:
print("ov_apply_camera_settings: Skipping because invalid prefs or cam object")
return
try:
# Basic image adjustments
brightness = prefs.get_int("brightness")
cam.set_brightness(brightness)
contrast = prefs.get_int("contrast")
cam.set_contrast(contrast)
saturation = prefs.get_int("saturation")
cam.set_saturation(saturation)
# Orientation
hmirror = prefs.get_bool("hmirror")
cam.set_hmirror(hmirror)
vflip = prefs.get_bool("vflip")
cam.set_vflip(vflip)
# Special effect
special_effect = prefs.get_int("special_effect")
cam.set_special_effect(special_effect)
# Exposure control (apply master switch first, then manual value)
exposure_ctrl = prefs.get_bool("exposure_ctrl")
cam.set_exposure_ctrl(exposure_ctrl)
if not exposure_ctrl:
aec_value = prefs.get_int("aec_value")
cam.set_aec_value(aec_value)
# Mode-specific default comes from constructor
ae_level = prefs.get_int("ae_level")
cam.set_ae_level(ae_level)
aec2 = prefs.get_bool("aec2")
cam.set_aec2(aec2)
# Gain control (apply master switch first, then manual value)
gain_ctrl = prefs.get_bool("gain_ctrl")
cam.set_gain_ctrl(gain_ctrl)
if not gain_ctrl:
agc_gain = prefs.get_int("agc_gain")
cam.set_agc_gain(agc_gain)
gainceiling = prefs.get_int("gainceiling")
cam.set_gainceiling(gainceiling)
# White balance (apply master switch first, then mode)
whitebal = prefs.get_bool("whitebal")
cam.set_whitebal(whitebal)
if not whitebal:
wb_mode = prefs.get_int("wb_mode")
cam.set_wb_mode(wb_mode)
awb_gain = prefs.get_bool("awb_gain")
cam.set_awb_gain(awb_gain)
# Sensor-specific settings (try/except for unsupported sensors)
try:
sharpness = prefs.get_int("sharpness")
cam.set_sharpness(sharpness)
except:
pass # Not supported on OV2640?
try:
denoise = prefs.get_int("denoise")
cam.set_denoise(denoise)
except:
pass # Not supported on OV2640?
# Advanced corrections
colorbar = prefs.get_bool("colorbar")
cam.set_colorbar(colorbar)
dcw = prefs.get_bool("dcw")
cam.set_dcw(dcw)
bpc = prefs.get_bool("bpc")
cam.set_bpc(bpc)
wpc = prefs.get_bool("wpc")
cam.set_wpc(wpc)
# Mode-specific default comes from constructor
raw_gma = prefs.get_bool("raw_gma")
print(f"applying raw_gma: {raw_gma}")
cam.set_raw_gma(raw_gma)
lenc = prefs.get_bool("lenc")
cam.set_lenc(lenc)
# JPEG quality (only relevant for JPEG format)
#try:
# quality = prefs.get_int("quality", 85)
# cam.set_quality(quality)
#except:
# pass # Not in JPEG mode
print("Camera settings applied successfully")
except Exception as e:
print(f"Error applying camera settings: {e}")
# ============================================================================
# Class method delegation (at module level)
@@ -140,18 +140,8 @@ class CameraActivity(Activity):
self.cam = CameraManager.get_cameras()[0].init(self.width, self.height, self.colormode)
if self.cam:
# Apply saved camera settings, only for internal camera for now:
self.apply_camera_settings(self.scanqr_prefs if self.scanqr_mode else self.prefs, self.cam, self.use_webcam) # needs to be done AFTER the camera is initialized
else:
print("camera app: no internal camera found, trying webcam on /dev/video0")
try:
# Initialize webcam with desired resolution directly
print(f"Initializing webcam at {self.width}x{self.height}")
self.cam = webcam.init("/dev/video0", width=self.width, height=self.height)
self.use_webcam = True
except Exception as e:
print(f"camera app: webcam exception: {e}")
# Start refreshing:
if self.cam:
CameraManager.get_cameras()[0].apply_settings(self.cam, self.scanqr_prefs if self.scanqr_mode else self.prefs) # needs to be done AFTER the camera is initialized
# Start refreshing:
print("Camera app initialized, continuing...")
self.update_preview_image()
self.capture_timer = lv.timer_create(self.try_capture, 100, None)
@@ -159,9 +149,7 @@ class CameraActivity(Activity):
def stop_cam(self):
if self.capture_timer:
self.capture_timer.delete()
if self.use_webcam:
webcam.deinit(self.cam)
elif self.cam:
if self.cam:
CameraManager.get_cameras()[0].deinit(self.cam)
self.cam = None
if self.image_dsc: # it's important to delete the image when stopping the camera, otherwise LVGL might try to display it and crash
@@ -337,11 +325,10 @@ class CameraActivity(Activity):
self.startActivity(intent)
def try_capture(self, event):
if not self.cam:
return
try:
if self.use_webcam and self.cam:
self.current_cam_buffer = webcam.capture_frame(self.cam, "rgb565" if self.colormode else "grayscale")
elif self.cam and self.cam.frame_available():
self.current_cam_buffer = self.cam.capture()
self.current_cam_buffer = CameraManager.get_cameras()[0].capture(self.cam, self.colormode)
except Exception as e:
print(f"Camera capture exception: {e}")
return
@@ -351,8 +338,10 @@ class CameraActivity(Activity):
self.image.set_src(self.image_dsc)
if self.scanqr_mode:
self.qrdecode_one()
if not self.use_webcam and self.cam:
try:
self.cam.free_buffer() # After QR decoding, free the old buffer, otherwise the camera doesn't provide a new one
except Exception as e:
pass # some camera API's don't have this
def print_qr_buffer(self, buffer):
try:
@@ -373,127 +362,6 @@ class CameraActivity(Activity):
if buffer.startswith(bom):
return buffer[3:]
return buffer
def apply_camera_settings(self, prefs, cam, use_webcam):
"""Apply all saved camera settings to the camera.
Only applies settings when use_webcam is False (ESP32 camera).
Settings are applied in dependency order (master switches before dependent values).
Args:
cam: Camera object
use_webcam: Boolean indicating if using webcam
"""
if not cam or use_webcam:
print("apply_camera_settings: Skipping (no camera or webcam mode)")
return
try:
# Basic image adjustments
brightness = prefs.get_int("brightness")
cam.set_brightness(brightness)
contrast = prefs.get_int("contrast")
cam.set_contrast(contrast)
saturation = prefs.get_int("saturation")
cam.set_saturation(saturation)
# Orientation
hmirror = prefs.get_bool("hmirror")
cam.set_hmirror(hmirror)
vflip = prefs.get_bool("vflip")
cam.set_vflip(vflip)
# Special effect
special_effect = prefs.get_int("special_effect")
cam.set_special_effect(special_effect)
# Exposure control (apply master switch first, then manual value)
exposure_ctrl = prefs.get_bool("exposure_ctrl")
cam.set_exposure_ctrl(exposure_ctrl)
if not exposure_ctrl:
aec_value = prefs.get_int("aec_value")
cam.set_aec_value(aec_value)
# Mode-specific default comes from constructor
ae_level = prefs.get_int("ae_level")
cam.set_ae_level(ae_level)
aec2 = prefs.get_bool("aec2")
cam.set_aec2(aec2)
# Gain control (apply master switch first, then manual value)
gain_ctrl = prefs.get_bool("gain_ctrl")
cam.set_gain_ctrl(gain_ctrl)
if not gain_ctrl:
agc_gain = prefs.get_int("agc_gain")
cam.set_agc_gain(agc_gain)
gainceiling = prefs.get_int("gainceiling")
cam.set_gainceiling(gainceiling)
# White balance (apply master switch first, then mode)
whitebal = prefs.get_bool("whitebal")
cam.set_whitebal(whitebal)
if not whitebal:
wb_mode = prefs.get_int("wb_mode")
cam.set_wb_mode(wb_mode)
awb_gain = prefs.get_bool("awb_gain")
cam.set_awb_gain(awb_gain)
# Sensor-specific settings (try/except for unsupported sensors)
try:
sharpness = prefs.get_int("sharpness")
cam.set_sharpness(sharpness)
except:
pass # Not supported on OV2640?
try:
denoise = prefs.get_int("denoise")
cam.set_denoise(denoise)
except:
pass # Not supported on OV2640?
# Advanced corrections
colorbar = prefs.get_bool("colorbar")
cam.set_colorbar(colorbar)
dcw = prefs.get_bool("dcw")
cam.set_dcw(dcw)
bpc = prefs.get_bool("bpc")
cam.set_bpc(bpc)
wpc = prefs.get_bool("wpc")
cam.set_wpc(wpc)
# Mode-specific default comes from constructor
raw_gma = prefs.get_bool("raw_gma")
print(f"applying raw_gma: {raw_gma}")
cam.set_raw_gma(raw_gma)
lenc = prefs.get_bool("lenc")
cam.set_lenc(lenc)
# JPEG quality (only relevant for JPEG format)
#try:
# quality = prefs.get_int("quality", 85)
# cam.set_quality(quality)
#except:
# pass # Not in JPEG mode
print("Camera settings applied successfully")
except Exception as e:
print(f"Error applying camera settings: {e}")
"""
def zoom_button_click_unused(self, e):