202 lines
5.5 KiB
Python
Executable File
202 lines
5.5 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
|
|
|
|
picam2 = Picamera2()
|
|
pprint(picam2.sensor_modes)
|
|
|
|
items = [
|
|
"ColourCorrectionMatrix",
|
|
"Saturation",
|
|
"Contrast",
|
|
"Sharpness",
|
|
"Brightness",
|
|
"NoiseReductionMode",
|
|
"AeEnable",
|
|
"AeMeteringMode",
|
|
"AeConstraintMode",
|
|
"AeExposureMode",
|
|
"AwbEnable",
|
|
"AwbMode",
|
|
"ExposureValue",
|
|
"ExposureTime",
|
|
"AnalogueGain",
|
|
"ColourGains",
|
|
"ScalerCrop",
|
|
"FrameDurationLimits",
|
|
"FrameRate"
|
|
]
|
|
|
|
settings = {'AeEnable': 0, 'AwbEnable': 0, 'NoiseReductionMode': 0, 'ExposureTime': 10000, 'AnalogueGain': 1, 'FrameRate': picam2.sensor_modes[0]['fps']}
|
|
caps = {"FrameRate": (1, picam2.sensor_modes[0]['fps'], None)}
|
|
fps_ist = 0
|
|
fps_soll = 0
|
|
|
|
|
|
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 clamp_and_store(item: str, value):
|
|
clamped_value = value
|
|
c = caps[item]
|
|
clamped_value = max(c[0], min(c[1], value))
|
|
settings[item] = clamped_value
|
|
|
|
return clamped_value
|
|
|
|
|
|
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)
|
|
|
|
shutter_keys = {'w': -1000, 's': -100, 'x': -1, 'e': 1000, 'd': 100, 'c': 1}
|
|
gain_keys = {'h': -1, 'j': 1}
|
|
fps_keys = {'r': -1, 'f': -0.1, 'v': -0.01, 't': 1, 'g': 0.1, 'b': 0.01}
|
|
|
|
def keypress_changed(key_defs: dict, key: int):
|
|
_res = None
|
|
try:
|
|
_res = key_defs[str(chr(key))]
|
|
except KeyError:
|
|
pass
|
|
|
|
return _res
|
|
|
|
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
|
|
|
|
control_changed = False
|
|
v = keypress_changed(shutter_keys, key)
|
|
if v is not None:
|
|
control_changed = True
|
|
shutter = clamp_and_store('ExposureTime', shutter + v)
|
|
print(f"Shutter: {shutter}")
|
|
|
|
v = keypress_changed(gain_keys, key)
|
|
if v is not None:
|
|
control_changed = True
|
|
gain = clamp_and_store('AnalogueGain', gain + v)
|
|
print(f"Gain: {gain}")
|
|
|
|
v = keypress_changed(fps_keys, key)
|
|
if v is not None:
|
|
control_changed = True
|
|
fps_soll = clamp_and_store('FrameRate', fps_soll + v)
|
|
print(f"FPS: {fps_soll}")
|
|
|
|
if control_changed:
|
|
# 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()
|