Files
ocv_rpicam/ocv_rpicam.py
T
jens 06be8c83ea - read metadata in callback
- clamp shutter speed to frame duration minimum
2024-07-15 17:27:24 +02:00

218 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
from typing import Union, overload
from picamera2 import Picamera2, MappedArray, Metadata
from pprint import pprint
import json
import cv2
import time
#import numpy as np
#import argparse
#import sys
#import csv
#import matplotlib.pyplot as plt
items = [
"ColourCorrectionMatrix",
"Saturation",
"Contrast",
"Sharpness",
"Brightness",
"NoiseReductionMode",
"AeEnable",
"AeMeteringMode",
"AeConstraintMode",
"AeExposureMode",
"AwbEnable",
"AwbMode",
"ExposureValue",
"ExposureTime",
"AnalogueGain",
"ColourGains",
"ScalerCrop",
"FrameDurationLimits",
"FrameRate"
]
picam2 = Picamera2()
pprint(picam2.sensor_modes)
settings = {'NoiseReductionMode': 0, 'AeExposureMode': 0, 'ExposureTime': 10000, 'AnalogueGain': 1, 'FrameRate': picam2.sensor_modes[0]['fps']}
caps = {"FrameRate": (1, picam2.sensor_modes[0]['fps'], None)}
def load_settings():
_result = {}
try:
with open("settings.json", "r") as fp:
_result = json.load(fp)
except Exception:
pass
return _result
def save_settings(_settings):
with open("settings.json", "w") as fp:
json.dump(_settings, fp, indent=0)
def apply_settings(_settings):
for item in _settings:
c = caps[item]
value = _settings[item]
if value < c[0] or value > c[1]:
raise Exception(f"Invalid Value for {item}")
picam2.set_controls({item: value})
def set_value(item: str, value):
clamped_value = value
c = caps[item]
clamped_value = max(c[0], min(c[1], value))
picam2.set_controls({item: clamped_value})
settings[item] = clamped_value
return clamped_value
def get_value(item: str):
return picam2.camera_controls[item]
fps_ist = 0
fps_soll = 0
def process(request):
timestamp = time.strftime("%Y-%m-%d %X")
# read metadata from request
metadata = Metadata(request.get_metadata())
# Clamp our shutter value to minimum of FrameDuration
caps["ExposureTime"] = (caps["ExposureTime"][0], metadata.FrameDuration)
with MappedArray(request, "main") as m:
# Display timestamp on frame
cv2.putText(m.array, timestamp, (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
if metadata is not None:
# Display exposure time
cv2.putText(m.array, f"ExposureTime : {metadata.ExposureTime:.1f}/{shutter:.1f}", (20, m.array.shape[0] - 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 240, 0), 2)
# Display frame time
cv2.putText(m.array, f"FrameDuration : {metadata.FrameDuration:.1f}", (20, m.array.shape[0] - 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 240, 0), 2)
# Display FPS on frame
cv2.putText(m.array, f"Frame rate : {fps_ist:.1f}/{fps_soll:.1f}", (20, m.array.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 240, 0), 2)
if __name__ == '__main__':
for item in items:
try:
caps[item] = (picam2.camera_controls[item][0], picam2.camera_controls[item][1])
except KeyError:
print(f"{item}: Not implemented")
# Config
camera_config = picam2.create_preview_configuration({'format': 'XRGB8888', 'size': picam2.sensor_modes[0]['size']})
camera_config = picam2.create_preview_configuration({'format': 'XRGB8888', 'size': (800, 600)})
picam2.configure(camera_config)
# Load and apply our settings
settings |= load_settings()
apply_settings(settings)
# Init vars
shutter = settings['ExposureTime']
gain = settings['AnalogueGain']
fps_soll = settings['FrameRate']
# Print status
pprint(f"Capabilities: {caps}")
pprint(f"Settings: {settings}")
pprint(f"Camera config: {picam2.camera_configuration()}")
# Register OCV processing callback
picam2.pre_callback = process
# Start
picam2.start()
while True:
# Start timer
timer = cv2.getTickCount()
# Capture frame
frame = picam2.capture_array("main")
# Process the frame using OpenCV operations
cv2.imshow('Frame', frame)
# Exit the loop on pressing 'q'
key = cv2.pollKey() & 0xFF
if key == ord('q'):
break
elif key == ord('w'):
shutter -= 1000
print(f"Shutter: {shutter}")
elif key == ord('s'):
shutter -= 100
print(f"Shutter: {shutter}")
elif key == ord('x'):
shutter -= 1
print(f"Shutter: {shutter}")
elif key == ord('e'):
shutter += 1000
print(f"Shutter: {shutter}")
elif key == ord('d'):
shutter += 100
print(f"Shutter: {shutter}")
elif key == ord('c'):
shutter += 1
print(f"Shutter: {shutter}")
elif key == ord('h'):
gain -= 1
print(f"Gain: {gain}")
elif key == ord('j'):
gain += 1
print(f"Gain: {gain}")
elif key == ord('r'):
fps_soll -= 1
print(f"FPS: {fps_soll}")
elif key == ord('f'):
fps_soll -= 0.1
print(f"FPS: {fps_soll}")
elif key == ord('v'):
fps_soll -= 0.01
print(f"FPS: {fps_soll}")
elif key == ord('t'):
fps_soll += 1
print(f"FPS: {fps_soll}")
elif key == ord('g'):
fps_soll += 0.1
print(f"FPS: {fps_soll}")
elif key == ord('b'):
fps_soll += 0.01
print(f"FPS: {fps_soll}")
# Update control settings and keep vars within ranges
shutter = set_value('ExposureTime', shutter)
gain = set_value('AnalogueGain', gain)
fps_soll = set_value('FrameRate', fps_soll)
# Write contrrols to camera
with picam2.controls as controls:
controls.ExposureTime = shutter
controls.AnalogueGain = gain
controls.FrameRate = fps_soll
# Calculate Frames per second (FPS)
fr = cv2.getTickFrequency() / (cv2.getTickCount() - timer)
alpha = 0.2
fps_ist = (1-alpha)*fps_ist + alpha*fr
# Release the capture and close windows
save_settings(settings)
cv2.destroyAllWindows()