tuxgo/tuxgo/camera.py

92 lines
2.4 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 Wojtek Porczyk <woju@hackerspace.pl>
import numpy as np
import picamera2 # pylint: disable=import-error
from loguru import logger
def get_char_for_pixel(pixel):
s = sum(pixel)
if s > 614:
return '\u2588'
if s > 460:
return '\u2593'
if s > 307:
return '\u2592'
if s > 153:
return '\u2591'
return ' '
def print_frame_to_console(frame):
for row in frame:
print(''.join(get_char_for_pixel(cell) for cell in row))
print()
class Camera:
def __init__(self, size):
self._exposure = 1.0
size = tuple(map(int, size))
self.camera = picamera2.Picamera2()
self.camera.preview_configuration.update(
{
'main': {
'format': 'BGR888',
'size': size,
},
'lores': None,
'raw': None,
'display': None,
'encode': None,
'controls': {
'ExposureValue': self._exposure,
},
}
)
self.camera.configure('preview')
# ExposureValue vanishes from controls for some reason
@property
def exposure(self):
return self._exposure
@exposure.setter
def exposure(self, value):
self._exposure = max(-8, min(8, value))
self.camera.controls.ExposureValue = self._exposure
def __enter__(self):
self.camera.start()
def __exit__(self, exc_type, exc_value, exc_tb):
try:
self.camera.stop()
except SystemError: # raised on double stop
pass
def resize(self, size):
logger.debug(f'resize({size=})')
# this is in picamera2.py:
# if size[0] % 2 or size[1] % 2:
# raise RuntimeError("width and height should be even")
x, y = map(int, size)
x -= x & 1
y -= y & 1
self.camera.preview_configuration.update({'size': (x, y)})
self.camera.switch_mode('preview')
def capture_frame(self, rotate=0):
'''returns (array, metadata)
array has shape (height, width, 3)
'''
request = self.camera.capture_request()
frame = request.make_array('main')
metadata = picamera2.Metadata(request.get_metadata())
request.release()
return np.rot90(frame, rotate), metadata