Skip to content

Commit c57eca5

Browse files
committed
Merge branch 'feat/bullseye_64_20240304' into feat/bookworm_32_64
2 parents faa8d75 + 732efd7 commit c57eca5

File tree

14 files changed

+122
-84
lines changed

14 files changed

+122
-84
lines changed

coderbot/api.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import urllib
1010

1111
import connexion
12-
import picamera
1312
from flask import Response, request, send_file
1413
from werkzeug.datastructures import Headers
1514

@@ -213,7 +212,7 @@ def getPhoto(name):
213212
try:
214213
media_file = cam.get_photo_file(name)
215214
return send_file(media_file, mimetype=mimetype.get(name[:-3], 'image/jpeg'), max_age=0)
216-
except picamera.exc.PiCameraError as e:
215+
except Exception as e:
217216
logging.error("Error: %s", str(e))
218217
return 503
219218
except FileNotFoundError:

coderbot/camera.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,23 @@ def get_instance(cls):
6060

6161
def __init__(self):
6262
logging.info("starting camera")
63+
cfg = config.Config.get()
6364
cam_props = {"width":640, "height":512,
64-
"cv_image_factor": config.Config.get().get("cv_image_factor"),
65-
"exposure_mode": config.Config.get().get("camera_exposure_mode"),
66-
"framerate": config.Config.get().get("camera_framerate"),
67-
"bitrate": config.Config.get().get("camera_jpeg_bitrate"),
68-
"jpeg_quality": int(config.Config.get().get("camera_jpeg_quality"))}
65+
"cv_image_factor": cfg.get("cv_image_factor"),
66+
"exposure_mode": cfg.get("camera_exposure_mode"),
67+
"framerate": cfg.get("camera_framerate"),
68+
"bitrate": cfg.get("camera_jpeg_bitrate"),
69+
"jpeg_quality": int(cfg.get("camera_jpeg_quality"))}
6970
self._camera = camera.Camera(props=cam_props)
7071
self.recording = False
7172
self.video_start_time = time.time() + 8640000
7273
self._image_time = 0
73-
self._cv_image_factor = int(config.Config.get().get("cv_image_factor", 4))
74-
self._image_refresh_timeout = float(config.Config.get().get("camera_refresh_timeout", 0.1))
75-
self._color_object_size_min = int(config.Config.get().get("camera_color_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
76-
self._color_object_size_max = int(config.Config.get().get("camera_color_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
77-
self._path_object_size_min = int(config.Config.get().get("camera_path_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
78-
self._path_object_size_max = int(config.Config.get().get("camera_path_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
74+
self._cv_image_factor = int(cfg.get("cv_image_factor", 4))
75+
self._image_refresh_timeout = float(cfg.get("camera_refresh_timeout", 0.1))
76+
self._color_object_size_min = int(cfg.get("camera_color_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
77+
self._color_object_size_max = int(cfg.get("camera_color_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
78+
self._path_object_size_min = int(cfg.get("camera_path_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
79+
self._path_object_size_max = int(cfg.get("camera_path_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
7980
self.load_photo_metadata()
8081
if not self._photos:
8182
self._photos = []
@@ -86,7 +87,7 @@ def __init__(self):
8687
self.save_photo_metadata()
8788

8889
self._cnn_classifiers = {}
89-
cnn_model = config.Config.get().get("cnn_default_model", "")
90+
cnn_model = cfg.get("cnn_default_model", "")
9091
if cnn_model != "":
9192
try:
9293
self._cnn_classifiers[cnn_model] = CNNManager.get_instance().load_model(cnn_model)

coderbot/cv/camera.py

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import logging
2626
from threading import Condition
2727
import numpy as np
28-
import picamera
28+
from picamera2 import Picamera2
29+
from picamera2.encoders import Encoder, MJPEGEncoder, H264Encoder
30+
from picamera2.outputs import FileOutput, FfmpegOutput
2931

3032
class Camera(object):
3133

@@ -34,90 +36,83 @@ class Camera(object):
3436
VIDEO_FILE_EXT = ".mp4"
3537
VIDEO_FILE_EXT_H264 = '.h264'
3638

37-
class StreamingOutputMJPEG(object):
39+
class StreamingOutputMJPEG(io.BufferedIOBase):
3840
def __init__(self):
3941
self.frame = None
40-
self.buffer = io.BytesIO()
4142
self.condition = Condition()
4243

4344
def write(self, buf):
44-
if buf.startswith(b'\xff\xd8'):
45-
# New frame, copy the existing buffer's content and notify all
46-
# clients it's available
47-
self.buffer.truncate()
48-
with self.condition:
49-
self.frame = self.buffer.getvalue()
50-
self.condition.notify_all()
51-
self.buffer.seek(0)
52-
return self.buffer.write(buf)
45+
with self.condition:
46+
self.frame = buf
47+
self.condition.notify_all()
5348

54-
class StreamingOutputBGR(object):
49+
class StreamingOutputBGR(io.BufferedIOBase):
5550
def __init__(self, resolution):
5651
self.frame = None
5752
self.condition = Condition()
5853
self.resolution = resolution
59-
self.count = 0
6054

6155
def write(self, buf):
6256
with self.condition:
6357
frame = np.frombuffer(buf, dtype=np.uint8)
6458
self.frame = frame.reshape(self.resolution[1], self.resolution[0], 4)
6559
self.frame = np.delete(self.frame, 3, 2)
6660
self.condition.notify_all()
67-
return len(buf)
6861

6962
def __init__(self, props):
7063
logging.info("camera init")
71-
self.camera = picamera.PiCamera()
64+
self.camera = Picamera2()
65+
self.camera.configure(self.camera.create_video_configuration(main={"size": (props.get('width', 640), props.get('height', 512))}))
7266
self.camera.resolution = (props.get('width', 640), props.get('height', 512))
73-
self.out_rgb_resolution = (int(self.camera.resolution[0] / int(props.get('cv_image_factor', 4))), int(self.camera.resolution[1] / int(props.get('cv_image_factor', 4))))
67+
self.out_rgb_resolution = (int(props.get('width', 640) / int(props.get('cv_image_factor', 4))), int(props.get('height', 512) / int(props.get('cv_image_factor', 4))))
7468
self.camera.framerate = float(props.get('framerate', 20))
7569
self.camera.exposure_mode = props.get('exposure_mode', "auto")
7670
self.output_mjpeg = self.StreamingOutputMJPEG()
77-
self.output_bgr = self.StreamingOutputBGR(self.out_rgb_resolution)
78-
self.h264_encoder = None
71+
self.encoder_streaming = MJPEGEncoder(10000000)
72+
self.encoder_streaming.output = [FileOutput(self.output_mjpeg)]
73+
self.encoder_h264 = H264Encoder()
74+
#self.output_bgr = self.StreamingOutputBGR(self.out_rgb_resolution)
75+
#self.h264_encoder = None
7976
self.recording = None
8077
self.video_filename = None
8178
self._jpeg_quality = props.get('jpeg_quality', 20)
8279
self._jpeg_bitrate = props.get('jpeg_bitrate', 5000000)
8380

8481
def video_rec(self, filename):
8582
self.video_filename = filename[:filename.rfind(".")]
86-
self.camera.start_recording(self.video_filename + self.VIDEO_FILE_EXT_H264, format="h264", quality=23, splitter_port=2)
83+
output = FfmpegOutput(output_filename=filename)
84+
self.encoder_h264.output = [output]
85+
self.camera.start_encoder(self.encoder_h264, output)
86+
#self.camera.start_recording(self.encoder_h264, FfmpegOutput(output_filename=filename))
87+
#self.camera.start_recording(self.video_filename + self.VIDEO_FILE_EXT_H264, format="h264", quality=23, splitter_port=2)
8788

8889
def video_stop(self):
89-
logging.debug("video_stop")
90-
self.camera.stop_recording(2)
91-
92-
# pack in mp4 container
93-
params = " -loglevel quiet -stats -framerate " + str(self.camera.framerate) + \
94-
" -i " + self.video_filename + self.VIDEO_FILE_EXT_H264 + \
95-
" -c copy " + self.video_filename + self.VIDEO_FILE_EXT
96-
97-
os.system(self.FFMPEG_CMD + params)
98-
# remove h264 file
99-
os.remove(self.video_filename + self.VIDEO_FILE_EXT_H264)
90+
logging.info("video_stop")
91+
self.camera.stop_encoder(encoders=[self.encoder_h264])
92+
#self.camera.stop_recording()
10093

10194
def grab_start(self):
102-
logging.debug("grab_start")
103-
self.camera.start_recording(self.output_mjpeg, format="mjpeg", splitter_port=0, bitrate=self._jpeg_bitrate)
104-
self.camera.start_recording(self.output_bgr, format="bgra", splitter_port=1, resize=self.out_rgb_resolution)
95+
logging.info("grab_start")
96+
self.camera.start()
97+
self.camera.start_encoder(self.encoder_streaming)
98+
#self.camera.start_recording(self.output_mjpeg, format="mjpeg", splitter_port=0, bitrate=self._jpeg_bitrate)
99+
#self.camera.start_recording(self.output_bgr, format="bgra", splitter_port=1, resize=self.out_rgb_resolution)
105100

106101
def grab_stop(self):
107-
logging.debug("grab_stop")
108-
109-
self.camera.stop_recording(0)
110-
self.camera.stop_recording(1)
102+
logging.info("grab_stop")
103+
self.camera.stop_encoder(encoders=[self.encoder_streaming])
111104

112105
def get_image_jpeg(self):
113106
with self.output_mjpeg.condition:
114107
self.output_mjpeg.condition.wait()
115108
return self.output_mjpeg.frame
116109

117110
def get_image_bgr(self):
118-
with self.output_bgr.condition:
119-
self.output_bgr.condition.wait()
120-
return self.output_bgr.frame
111+
buf = self.camera.capture_buffer()
112+
frame_from_buf = np.frombuffer(buf, dtype=np.uint8)
113+
frame = frame_from_buf.reshape(self.camera.resolution[1], self.camera.resolution[0], 4)
114+
frame = np.delete(frame, 3, 2)
115+
return frame
121116

122117
def set_overlay_text(self, text):
123118
try:

coderbot/cv/image.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ class Image():
3636
r_from = np.float32([[0, 0], [640, 0], [640, 480], [0, 480]])
3737
r_dest = np.float32([[0, -120], [640, -120], [380, 480], [260, 480]])
3838

39-
_aruco_detector = cv2.aruco.ArucoDetector(
40-
cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_ARUCO_ORIGINAL),
41-
cv2.aruco.DetectorParameters())
39+
try:
40+
_aruco_detector = cv2.aruco.ArucoDetector(
41+
cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_ARUCO_ORIGINAL),
42+
cv2.aruco.DetectorParameters())
43+
except AttributeError:
44+
_aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_ARUCO_ORIGINAL)
45+
_aruco_parameters = cv2.aruco.DetectorParameters_create()
46+
4247

4348
_face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
4449

coderbot/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import os
66
import logging
77
import logging.handlers
8-
import picamera
98
import connexion
109

1110
from connexion.options import SwaggerUIOptions
@@ -78,10 +77,11 @@ def run_server():
7877
logging.warning("Audio not present")
7978

8079
try:
80+
logging.info("starting camera")
8181
cam = Camera.get_instance()
8282
Motion.get_instance()
83-
except picamera.exc.PiCameraError:
84-
logging.warning("Camera not present")
83+
except Exception as e:
84+
logging.warning("Camera not present", str(e))
8585

8686
CNNManager.get_instance()
8787
EventManager.get_instance("coderbot")

coderbot/v1.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,13 @@ paths:
533533
type: string
534534
minLength: 1
535535
maxLength: 256
536+
pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
536537
description: text to be "spoken"
537538
locale:
538539
type: string
539540
minLength: 1
540541
maxLength: 2
541-
pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
542+
pattern: '^[a-zA-Z]+$'
542543
description: locale of text to be "spoken"
543544
required:
544545
- text
@@ -716,6 +717,7 @@ components:
716717
properties:
717718
name:
718719
type: string
720+
pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
719721
tag:
720722
type: string
721723
Program:

stub/picamera/__init__.py

Lines changed: 0 additions & 3 deletions
This file was deleted.

stub/picamera2/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from picamera2.camera import Picamera2
2+

stub/picamera/camera.py renamed to stub/picamera2/camera.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from picamera_mock import PiCameraMock as PiCamera
1+
from picamera2_mock import Picamera2Mock as Picamera2
22

33
class array(object):
44
def __init(self):

stub/picamera2/encoders.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Encoder():
2+
pass
3+
4+
class MJPEGEncoder(Encoder):
5+
def __init__(self, bitrate):
6+
pass
7+
8+
class H264Encoder(Encoder):
9+
def __init__(self, bitrate=100000):
10+
pass

0 commit comments

Comments
 (0)