bluer-sbc 8.121.1__py3-none-any.whl → 8.151.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bluer-sbc might be problematic. Click here for more details.

bluer_sbc/.abcli/alias.sh CHANGED
@@ -1,5 +1,7 @@
1
1
  #! /usr/bin/env bash
2
2
 
3
- alias @sbc=bluer_sbc
3
+ alias @camera=bluer_sbc_camera
4
4
 
5
5
  alias grove=bluer_sbc_grove
6
+
7
+ alias @sbc=bluer_sbc
@@ -0,0 +1,51 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # internal function to bluer_ai_seed.
4
+ # seed is NOT local
5
+ function bluer_ai_seed_headless_rpi() {
6
+ bluer_ai_seed add_kaggle
7
+
8
+ bluer_ai_seed add_ssh_key sudo
9
+
10
+ # https://serverfault.com/a/1093530
11
+ # https://packages.ubuntu.com/bionic/all/ca-certificates/download
12
+ local certificate_name="ca-certificates_20230311ubuntu0.18.04.1_all"
13
+ seed="${seed}wget --no-check-certificate http://security.ubuntu.com/ubuntu/pool/main/c/ca-certificates/$certificate_name.deb$delim"
14
+ seed="${seed}sudo dpkg -i $certificate_name.deb$delim_section"
15
+ seed="${seed}sudo apt-get update --allow-releaseinfo-change$delim"
16
+ seed="${seed}sudo apt-get install -y ca-certificates libgnutls30$delim"
17
+ seed="${seed}sudo apt install -y python3-venv$delim"
18
+ seed="${seed}sudo apt install -y cmake build-essential$delim"
19
+ seed="${seed}sudo apt install -y libjpeg-dev zlib1g-dev libfreetype6-dev liblcms2-dev libopenjpeg-dev libtiff-dev libwebp-dev$delim"
20
+ seed="${seed}sudo apt-get install libopenblas-base$delim"
21
+
22
+ seed="${seed}sudo apt-get --yes --force-yes install git$delim_section"
23
+
24
+ bluer_ai_seed add_repo
25
+
26
+ seed="${seed}mkdir -pv ~/storage/temp/ignore$delim"
27
+ seed="${seed}touch ~/storage/temp/ignore/headless$delim_section"
28
+
29
+ bluer_ai_seed add_bluer_ai_env
30
+
31
+ seed="${seed}sudo apt install -y python3-pip$delim"
32
+ seed="${seed}pip3 install --upgrade pip --no-input$delim"
33
+ seed="${seed}pip3 install \"pandas<2.1\"$delim"
34
+ seed="${seed}pip3 install pillow$delim"
35
+ seed="${seed}pip3 install -e . --constraint ./bluer_ai/assets/no-pyarrow.txt$delim_section"
36
+
37
+ bluer_ai_seed add_repo repo=bluer-objects
38
+ seed="${seed}pip3 install -e .$delim_section"
39
+ seed="${seed}$(bluer_ai_seed add_file $abcli_path_git/bluer-objects/.env \$HOME/git/bluer-objects/.env)$delim_section"
40
+
41
+ bluer_ai_seed add_repo repo=bluer-sbc
42
+ seed="${seed}pip3 install -e .$delim_section"
43
+
44
+ seed="${seed}pip3 install opencv-python-headless$delim_section"
45
+ seed="${seed}sudo apt install -y libopenjp2-7 libavcodec58 libavformat58 libswscale5 libblas3 libatlas3-base$delim_section"
46
+
47
+ seed="${seed}cd; cd git; cd bluer-ai$delim"
48
+ seed="${seed}source ./bluer_ai/.abcli/bluer_ai.sh$delim_section"
49
+
50
+ seed="${seed}source ~/.bashrc$delim_section"
51
+ }
@@ -0,0 +1,38 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # internal function to bluer_ai_seed.
4
+ # seed is NOT local
5
+ function bluer_ai_seed_headless_rpi_64_bit() {
6
+ bluer_ai_seed add_kaggle
7
+
8
+ bluer_ai_seed add_ssh_key sudo
9
+
10
+ seed="${seed}sudo apt-get --yes --force-yes install git$delim_section"
11
+
12
+ bluer_ai_seed add_repo
13
+
14
+ seed="${seed}mkdir -pv ~/storage/temp/ignore$delim"
15
+ seed="${seed}touch ~/storage/temp/ignore/headless$delim_section"
16
+
17
+ bluer_ai_seed add_bluer_ai_env_ssp
18
+
19
+ local ssp="--break-system-packages"
20
+
21
+ seed="${seed}sudo apt update$delim"
22
+ seed="${seed}sudo apt install -y python3-pip$delim"
23
+ seed="${seed}pip3 install $ssp -e .$delim_section"
24
+
25
+ bluer_ai_seed add_repo repo=bluer-objects
26
+ seed="${seed}pip3 install $ssp -e .$delim_section"
27
+ seed="${seed}$(bluer_ai_seed add_file $abcli_path_git/bluer-objects/.env \$HOME/git/bluer-objects/.env)$delim_section"
28
+
29
+ bluer_ai_seed add_repo repo=bluer-sbc
30
+ seed="${seed}pip3 install $ssp -e .$delim_section"
31
+
32
+ seed="${seed}pip3 install $ssp opencv-python-headless$delim"
33
+ seed="${seed}sudo apt install -y python3-picamera2$delim"
34
+ seed="${seed}pip3 install --force-reinstall --no-cache-dir simplejpeg$delim_section"
35
+
36
+ seed="${seed}cd; cd git; cd bluer-ai$delim"
37
+ seed="${seed}source ./bluer_ai/.abcli/bluer_ai.sh$delim_section"
38
+ }
@@ -16,6 +16,8 @@ function bluer_ai_seed_headless_ubuntu_rpi() {
16
16
  seed="${seed}sudo apt install -y wireless-tools$delim"
17
17
  seed="${seed}sudo apt install -y gcc python3-dev$delim"
18
18
  seed="${seed}sudo apt install -y gcc-aarch64-linux-gnu$delim"
19
+ seed="${seed}sudo apt install -y v4l-utils$delim"
20
+ seed="${seed}sudo apt install -y ffmpeg$delim"
19
21
  seed="${seed}sudo apt install -y python3-venv$delim_section"
20
22
 
21
23
  seed="${seed}sudo mkdir -p /etc/systemd/system/getty@tty1.service.d$delim"
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # internal function to bluer_ai_seed.
4
+ # seed is NOT local
5
+ function bluer_ai_seed_jetson() {
6
+ bluer_ai_seed add_kaggle
7
+
8
+ bluer_ai_seed add_ssh_key sudo
9
+
10
+ seed="${seed}sudo apt-get --yes --force-yes install git$delim_section"
11
+
12
+ bluer_ai_seed add_repo
13
+
14
+ bluer_ai_seed add_bluer_ai_env
15
+
16
+ seed="${seed}sudo apt install -y python3-pip$delim"
17
+ seed="${seed}pip3 install --upgrade pip --no-input$delim"
18
+ seed="${seed}pip3 install -e .$delim_section"
19
+
20
+ bluer_ai_seed add_repo repo=bluer-objects
21
+ seed="${seed}pip3 install -e .$delim_section"
22
+ seed="${seed}$(bluer_ai_seed add_file $abcli_path_git/bluer-objects/.env \$HOME/git/bluer-objects/.env)$delim_section"
23
+
24
+ bluer_ai_seed add_repo repo=bluer-sbc
25
+ seed="${seed}pip3 install -e .$delim_section"
26
+
27
+ seed="${seed}cd; cd git; cd bluer-ai$delim"
28
+ seed="${seed}source ./bluer_ai/.abcli/bluer_ai.sh$delim_section"
29
+
30
+ seed="${seed}source ~/.bashrc$delim_section"
31
+ }
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # internal function to bluer_ai_seed.
4
+ # seed is NOT local
5
+ function bluer_ai_seed_rpi() {
6
+ bluer_ai_seed add_kaggle
7
+
8
+ bluer_ai_seed add_ssh_key sudo
9
+
10
+ seed="${seed}sudo apt-get --yes --force-yes install git$delim_section"
11
+
12
+ bluer_ai_seed add_repo
13
+
14
+ bluer_ai_seed add_bluer_ai_env
15
+
16
+ seed="${seed}sudo apt install -y python3-pip$delim"
17
+ seed="${seed}pip3 install --upgrade pip --no-input$delim"
18
+ seed="${seed}pip3 install -e .$delim_section"
19
+
20
+ bluer_ai_seed add_repo repo=bluer-objects
21
+ seed="${seed}pip3 install -e .$delim_section"
22
+ seed="${seed}$(bluer_ai_seed add_file $abcli_path_git/bluer-objects/.env \$HOME/git/bluer-objects/.env)$delim_section"
23
+
24
+ bluer_ai_seed add_repo repo=bluer-sbc
25
+ seed="${seed}pip3 install -e .$delim_section"
26
+
27
+ seed="${seed}cd; cd git; cd bluer-ai$delim"
28
+ seed="${seed}source ./bluer_ai/.abcli/bluer_ai.sh$delim_section"
29
+
30
+ seed="${seed}source ~/.bashrc$delim_section"
31
+ }
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # internal function to bluer_ai_seed.
4
+ # seed is NOT local
5
+ function bluer_ai_seed_swallow_raspbian() {
6
+ local ssp="--break-system-packages"
7
+
8
+ bluer_ai_seed add_repo repo=bluer-ugv
9
+ seed="${seed}pip3 install $ssp -e .$delim_section"
10
+
11
+ bluer_ai_seed add_repo repo=bluer-algo
12
+ seed="${seed}pip3 install $ssp -e .$delim_section"
13
+ }
bluer_sbc/.abcli/seed.sh CHANGED
@@ -1,52 +1,3 @@
1
1
  #! /usr/bin/env bash
2
2
 
3
- # internal function to bluer_ai_seed.
4
- # seed is NOT local
5
- function bluer_ai_seed_headless_rpi() {
6
- bluer_sbc_seed "$@"
7
- }
8
- function bluer_ai_seed_jetson() {
9
- bluer_sbc_seed "$@"
10
- }
11
- function bluer_ai_seed_rpi() {
12
- bluer_sbc_seed "$@"
13
- }
14
-
15
- function bluer_sbc_seed() {
16
- local target=$1
17
-
18
- bluer_ai_seed add_kaggle
19
-
20
- bluer_ai_seed add_ssh_key
21
-
22
- seed="${seed}ssh-keyscan github.com | sudo tee -a ~/.ssh/known_hosts$delim_section"
23
-
24
- # https://serverfault.com/a/1093530
25
- # https://packages.ubuntu.com/bionic/all/ca-certificates/download
26
- local certificate_name="ca-certificates_20211016ubuntu0.18.04.1_all"
27
- seed="${seed}wget --no-check-certificate http://security.ubuntu.com/ubuntu/pool/main/c/ca-certificates/$certificate_name.deb$delim"
28
- seed="${seed}sudo dpkg -i $certificate_name.deb$delim_section"
29
- seed="${seed}sudo apt-get update --allow-releaseinfo-change$delim"
30
- seed="${seed}sudo apt-get install -y ca-certificates libgnutls30$delim"
31
-
32
- seed="${seed}sudo apt-get --yes --force-yes install git$delim_section"
33
-
34
- bluer_ai_seed add_repo
35
-
36
- [[ "$target" == "headless_rpi" ]] &&
37
- seed="${seed}touch ~/storage/temp/ignore/headless$delim_section"
38
-
39
- bluer_ai_seed add_bluer_ai_env
40
-
41
- seed="${seed}pip install --upgrade pip --no-input$delim"
42
- seed="${seed}pip3 install -e .$delim_section"
43
-
44
- seed="${seed}source ./bluer_ai/.abcli/bluer_ai.sh$delim_section"
45
-
46
- seed="${seed}source ~/.bashrc$delim_section"
47
-
48
- if [[ ! -z "$env_name" ]]; then
49
- seed="${seed}bluer_ai_env dot copy $env_name$delim"
50
- seed="${seed}bluer_ai init$delim_section"
51
- fi
52
- }
3
+ bluer_ai_source_caller_suffix_path /seed
@@ -6,9 +6,11 @@ function test_bluer_sbc_seed() {
6
6
  local target
7
7
  for target in \
8
8
  headless_rpi \
9
+ headless_rpi_64_bit \
9
10
  headless_ubuntu_rpi \
10
11
  jetson \
11
- rpi; do
12
+ rpi \
13
+ swallow_raspbian; do
12
14
  bluer_ai_eval ,$options \
13
15
  bluer_ai_seed $target screen
14
16
  [[ $? -ne 0 ]] && return 1
bluer_sbc/__init__.py CHANGED
@@ -4,7 +4,7 @@ ICON = "🌀"
4
4
 
5
5
  DESCRIPTION = f"{ICON} AI for single board computers."
6
6
 
7
- VERSION = "8.121.1"
7
+ VERSION = "8.151.1"
8
8
 
9
9
  REPO_NAME = "bluer-sbc"
10
10
 
bluer_sbc/config.env CHANGED
@@ -2,6 +2,7 @@ BLUER_SBC_CAMERA_HI_RES=1
2
2
  BLUER_SBC_CAMERA_WIDTH=728
3
3
  BLUER_SBC_CAMERA_HEIGHT=600
4
4
  BLUER_SBC_CAMERA_ROTATION=0
5
+ BLUER_SBC_CAMERA_KEEP_OPEN=0
5
6
 
6
7
  BLUER_SBC_DISPLAY_FULLSCREEN=1
7
8
 
bluer_sbc/env.py CHANGED
@@ -7,6 +7,7 @@ BLUER_SBC_CAMERA_HI_RES = get_env("BLUER_SBC_CAMERA_HI_RES", True)
7
7
  BLUER_SBC_CAMERA_WIDTH = get_env("BLUER_SBC_CAMERA_WIDTH", 728)
8
8
  BLUER_SBC_CAMERA_HEIGHT = get_env("BLUER_SBC_CAMERA_HEIGHT", 600)
9
9
  BLUER_SBC_CAMERA_ROTATION = get_env("BLUER_SBC_CAMERA_ROTATION", 0)
10
+ BLUER_SBC_CAMERA_KEEP_OPEN = get_env("BLUER_SBC_CAMERA_KEEP_OPEN", 0)
10
11
 
11
12
  BLUER_SBC_DISPLAY_FULLSCREEN = get_env("BLUER_SBC_DISPLAY_FULLSCREEN", True)
12
13
 
@@ -1,3 +1,11 @@
1
- from bluer_sbc.imager.camera.classes import Camera
1
+ from bluer_options import host
2
+
3
+ if host.is_rpi():
4
+ if host.is_64bit():
5
+ from bluer_sbc.imager.camera.rpi_64_bit import RPI_64_bit_Camera as Camera
6
+ else:
7
+ from bluer_sbc.imager.camera.rpi import RPI_Camera as Camera
8
+ else:
9
+ from bluer_sbc.imager.camera.generic import Camera
2
10
 
3
11
  instance = Camera()
@@ -0,0 +1,208 @@
1
+ import cv2
2
+ from typing import Tuple, List, Union
3
+ import numpy as np
4
+
5
+ from blueness import module
6
+ from bluer_options import string
7
+ from bluer_options import host
8
+ from bluer_options.timer import Timer
9
+ from bluer_options.logger import crash_report
10
+ from bluer_objects import file, objects
11
+
12
+ from bluer_sbc import env
13
+ from bluer_sbc.hardware import hardware
14
+ from bluer_sbc.imager.classes import Imager
15
+ from bluer_sbc.logger import logger
16
+
17
+
18
+ class Camera(Imager):
19
+ def __init__(self):
20
+ self.device = None
21
+ self.resolution = []
22
+
23
+ def capture(
24
+ self,
25
+ close_after: bool = True,
26
+ log: bool = True,
27
+ open_before: bool = True,
28
+ filename: str = "",
29
+ object_name: str = "",
30
+ ) -> Tuple[bool, np.ndarray]:
31
+ success = False
32
+ image = np.ones((1, 1, 3), dtype=np.uint8) * 127
33
+
34
+ if open_before:
35
+ if not self.open():
36
+ return success, image
37
+
38
+ if self.device is None:
39
+ return success, image
40
+
41
+ success, image = self.capture_function()
42
+ if not success:
43
+ logger.warning("capture failed.")
44
+ elif log:
45
+ logger.info(
46
+ "{}.capture(): {}".format(
47
+ self.__class__.__name__,
48
+ string.pretty_shape_of_matrix(image),
49
+ )
50
+ )
51
+
52
+ if close_after:
53
+ self.close()
54
+
55
+ if success and filename:
56
+ success = file.save_image(
57
+ filename=objects.path_of(
58
+ object_name=object_name,
59
+ filename=filename,
60
+ ),
61
+ image=image,
62
+ log=log,
63
+ )
64
+
65
+ return success, image
66
+
67
+ def capture_function(self) -> Tuple[bool, np.ndarray]:
68
+ success = False
69
+ image = np.ones((1, 1, 3), dtype=np.uint8) * 127
70
+
71
+ try:
72
+ success, image = self.device.read()
73
+
74
+ if success:
75
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
76
+
77
+ except Exception as e:
78
+ crash_report(e)
79
+
80
+ return success, image
81
+
82
+ # https://projects.raspberrypi.org/en/projects/getting-started-with-picamera/6
83
+ def capture_video(
84
+ self,
85
+ filename: str,
86
+ object_name: str,
87
+ length: int = 10, # in seconds
88
+ preview: bool = True,
89
+ pulse: bool = True,
90
+ resolution=None,
91
+ ) -> bool:
92
+ logger.error(f"{self.__class__.__name__}.capture_video(): not implemented.")
93
+ return False
94
+
95
+ def close(self, log: bool = True) -> bool:
96
+ if self.device is None:
97
+ logger.warning(
98
+ "{}.close(): device is {}, failed.".format(
99
+ self.__class__.__name__,
100
+ self.device,
101
+ )
102
+ )
103
+ return False
104
+
105
+ try:
106
+ self.close_function()
107
+ except Exception as e:
108
+ crash_report(e)
109
+ return False
110
+
111
+ self.device = None
112
+
113
+ if log:
114
+ logger.info(f"{self.__class__.__name__}.close().")
115
+
116
+ return True
117
+
118
+ def close_function(self):
119
+ self.device.release()
120
+
121
+ def get_resolution(self) -> List[int]:
122
+ try:
123
+ resolution = self.get_resolution_function()
124
+ except Exception as e:
125
+ crash_report(e)
126
+ return []
127
+
128
+ return resolution
129
+
130
+ def get_resolution_function(self) -> Tuple[int, int]:
131
+ return [
132
+ int(self.device.get(const))
133
+ for const in [cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FRAME_WIDTH]
134
+ ]
135
+
136
+ def open(
137
+ self,
138
+ log: bool = True,
139
+ resolution: Union[List[int], None] = None,
140
+ ) -> bool:
141
+ try:
142
+ self.open_function(resolution=resolution)
143
+
144
+ self.resolution = self.get_resolution()
145
+
146
+ if log:
147
+ logger.info(
148
+ "{}.open({})".format(
149
+ self.__class__.__name__,
150
+ string.pretty_shape(self.resolution),
151
+ )
152
+ )
153
+
154
+ return True
155
+ except Exception as e:
156
+ crash_report(e)
157
+ return False
158
+
159
+ def open_function(
160
+ self,
161
+ resolution=Union[List[int], None],
162
+ ):
163
+ self.device = cv2.VideoCapture(0)
164
+
165
+ # https://stackoverflow.com/a/31464688
166
+ self.device.set(cv2.CAP_PROP_FRAME_WIDTH, env.BLUER_SBC_CAMERA_WIDTH)
167
+ self.device.set(cv2.CAP_PROP_FRAME_HEIGHT, env.BLUER_SBC_CAMERA_HEIGHT)
168
+
169
+ def preview(
170
+ self,
171
+ length: float = -1,
172
+ ) -> bool:
173
+ logger.info(
174
+ "{}.preview{} ... | press q or e to quit ...".format(
175
+ self.__class__.__name__,
176
+ "[{}]".format("" if length == -1 else string.pretty_duration(length)),
177
+ )
178
+ )
179
+
180
+ hardware.sign_images = False
181
+ timer = Timer(length, "preview")
182
+ try:
183
+ self.open(
184
+ log=True,
185
+ resolution=(320, 240),
186
+ )
187
+
188
+ while not hardware.pressed("qe"):
189
+ _, image = self.capture(
190
+ close_after=False,
191
+ log=False,
192
+ open_before=False,
193
+ )
194
+ hardware.update_screen(image, None, [])
195
+
196
+ if timer.tick(wait=True):
197
+ logger.info(
198
+ "{} is up, quitting.".format(string.pretty_duration(length))
199
+ )
200
+ break
201
+
202
+ except KeyboardInterrupt:
203
+ logger.info("Ctrl+C, stopping.")
204
+
205
+ finally:
206
+ self.close(log=True)
207
+
208
+ return True
@@ -0,0 +1,112 @@
1
+ from typing import Tuple, Union, List
2
+ import numpy as np
3
+ from time import sleep
4
+
5
+ from bluer_options.logger import crash_report
6
+ from bluer_options import string
7
+ from bluer_objects import file, objects
8
+
9
+ from bluer_sbc.imager.camera.generic import Camera
10
+ from bluer_sbc.hardware import hardware
11
+ from bluer_sbc import env
12
+ from bluer_sbc.logger import logger
13
+
14
+
15
+ class RPI_Camera(Camera):
16
+ def capture_function(self) -> Tuple[bool, np.ndarray]:
17
+ success = False
18
+ image = np.ones((1, 1, 3), dtype=np.uint8) * 127
19
+
20
+ temp = file.auxiliary("camera", "png")
21
+ try:
22
+ self.device.capture(temp)
23
+ success = True
24
+ except Exception as e:
25
+ crash_report(e)
26
+
27
+ if success:
28
+ success, image = file.load_image(temp)
29
+
30
+ return success, image
31
+
32
+ # https://projects.raspberrypi.org/en/projects/getting-started-with-picamera/6
33
+ def capture_video(
34
+ self,
35
+ filename: str,
36
+ object_name: str,
37
+ length: int = 10, # in seconds
38
+ preview: bool = True,
39
+ pulse: bool = True,
40
+ resolution=None,
41
+ ) -> bool:
42
+ if not self.open(resolution=resolution):
43
+ return False
44
+
45
+ full_filename = objects.path_of(
46
+ object_name=object_name,
47
+ filename=filename,
48
+ )
49
+
50
+ success = True
51
+ try:
52
+ if preview:
53
+ self.device.start_preview()
54
+
55
+ self.device.start_recording(full_filename)
56
+ if pulse:
57
+ for _ in range(int(10 * length)):
58
+ hardware.pulse("outputs")
59
+ sleep(0.1)
60
+ else:
61
+ sleep(length)
62
+ self.device.stop_recording()
63
+
64
+ if preview:
65
+ self.device.stop_preview()
66
+ except Exception as e:
67
+ crash_report(e)
68
+ success = False
69
+
70
+ if not self.close():
71
+ return False
72
+
73
+ if success:
74
+ logger.info(
75
+ "{}.capture_video(): {} -{}-> {}".format(
76
+ self.__class__.__name__,
77
+ string.pretty_duration(length),
78
+ string.pretty_bytes(file.size(full_filename)),
79
+ filename,
80
+ )
81
+ )
82
+
83
+ return success
84
+
85
+ def close_function(self):
86
+ self.device.close()
87
+
88
+ def get_resolution_function(self) -> Tuple[int, int]:
89
+ return [value for value in self.device.resolution]
90
+
91
+ def open_function(
92
+ self,
93
+ resolution=Union[List[int], None],
94
+ ):
95
+ from picamera import PiCamera
96
+
97
+ self.device = PiCamera()
98
+ self.device.rotation = env.BLUER_SBC_CAMERA_ROTATION
99
+
100
+ # https://projects.raspberrypi.org/en/projects/getting-started-with-picamera/7
101
+ self.device.resolution = (
102
+ (
103
+ (2592, 1944)
104
+ if env.BLUER_SBC_CAMERA_HI_RES
105
+ else (
106
+ env.BLUER_SBC_CAMERA_WIDTH,
107
+ env.BLUER_SBC_CAMERA_HEIGHT,
108
+ )
109
+ )
110
+ if resolution is None
111
+ else resolution
112
+ )
@@ -0,0 +1,49 @@
1
+ from typing import Tuple, Union, List
2
+ import numpy as np
3
+
4
+ from bluer_options.logger import crash_report
5
+
6
+ from bluer_sbc.imager.camera.generic import Camera
7
+ from bluer_sbc import env
8
+
9
+
10
+ class RPI_64_bit_Camera(Camera):
11
+ def capture_function(self) -> Tuple[bool, np.ndarray]:
12
+ success = False
13
+ image = np.ones((1, 1, 3), dtype=np.uint8) * 127
14
+
15
+ try:
16
+ image = self.device.capture_array()
17
+ success = True
18
+ except Exception as e:
19
+ crash_report(e)
20
+
21
+ return success, image
22
+
23
+ def close_function(self):
24
+ self.device.stop()
25
+ del self.device
26
+
27
+ def get_resolution_function(self) -> Tuple[int, int]:
28
+ width, height = self.device.stream_configuration("main")["size"]
29
+ return [height, width]
30
+
31
+ def open_function(
32
+ self,
33
+ resolution=Union[List[int], None],
34
+ ):
35
+ from picamera2 import Picamera2
36
+
37
+ self.device = Picamera2()
38
+
39
+ config = self.device.create_still_configuration(
40
+ main={
41
+ "size": (
42
+ env.BLUER_SBC_CAMERA_WIDTH,
43
+ env.BLUER_SBC_CAMERA_HEIGHT,
44
+ )
45
+ }
46
+ )
47
+ self.device.configure(config)
48
+
49
+ self.device.start()
@@ -90,7 +90,15 @@ class Session:
90
90
  return
91
91
  self.capture_requested = False
92
92
 
93
- success, image = imager.capture()
93
+ if env.BLUER_SBC_CAMERA_KEEP_OPEN:
94
+ if imager.device is None:
95
+ if not imager.open(log=True):
96
+ return
97
+
98
+ success, image = imager.capture( # pylint: disable=unexpected-keyword-arg
99
+ open_before=not bool(env.BLUER_SBC_CAMERA_KEEP_OPEN),
100
+ close_after=not bool(env.BLUER_SBC_CAMERA_KEEP_OPEN),
101
+ )
94
102
  if not success:
95
103
  return
96
104
 
@@ -178,6 +186,9 @@ class Session:
178
186
  def close(self):
179
187
  hardware.release()
180
188
 
189
+ if env.BLUER_SBC_CAMERA_KEEP_OPEN:
190
+ imager.close(log=True)
191
+
181
192
  def process_message(self, message):
182
193
  if (
183
194
  env.BLUER_SBC_SESSION_OUTBOUND_QUEUE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bluer_sbc
3
- Version: 8.121.1
3
+ Version: 8.151.1
4
4
  Summary: 🌀 AI for single board computers.
5
5
  Home-page: https://github.com/kamangir/bluer-sbc
6
6
  Author: Arash Abadpour (Kamangir)
@@ -50,7 +50,7 @@ pip install bluer_sbc
50
50
 
51
51
  [![pylint](https://github.com/kamangir/bluer-sbc/actions/workflows/pylint.yml/badge.svg)](https://github.com/kamangir/bluer-sbc/actions/workflows/pylint.yml) [![pytest](https://github.com/kamangir/bluer-sbc/actions/workflows/pytest.yml/badge.svg)](https://github.com/kamangir/bluer-sbc/actions/workflows/pytest.yml) [![bashtest](https://github.com/kamangir/bluer-sbc/actions/workflows/bashtest.yml/badge.svg)](https://github.com/kamangir/bluer-sbc/actions/workflows/bashtest.yml) [![PyPI version](https://img.shields.io/pypi/v/bluer-sbc.svg)](https://pypi.org/project/bluer-sbc/) [![PyPI - Downloads](https://img.shields.io/pypi/dd/bluer-sbc)](https://pypistats.org/packages/bluer-sbc)
52
52
 
53
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_sbc-8.121.1`](https://github.com/kamangir/bluer-sbc).
53
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_sbc-8.151.1`](https://github.com/kamangir/bluer-sbc).
54
54
 
55
55
 
56
56
  built by 🌀 [`blueness-3.118.1`](https://github.com/kamangir/blueness).
@@ -1,40 +1,43 @@
1
1
  bluer_sbc/README.py,sha256=p-zQD0mdeXyPxgy9MpqlTH8tNhP2HMLO6J7Ta2Gv4qQ,1115
2
- bluer_sbc/__init__.py,sha256=h3tRoy01zLGn4BL7CfKAIa1_O4N6jr1wZOC9syiV_Ps,292
2
+ bluer_sbc/__init__.py,sha256=aalP6JdbH9v9E0ZwkGFRmXqg-k5udZLi9TlI1vI2sJ0,292
3
3
  bluer_sbc/__main__.py,sha256=JV8oYpZDQbvcDpKJtbjU0hDeMJkzsDLGlhIWLmRpDQ4,348
4
- bluer_sbc/config.env,sha256=_0-DQI3JZ5lvC1750KepY4ug6apI0I5EhcbZ3JD1yZs,652
5
- bluer_sbc/env.py,sha256=w1kYRW06SUm4AzyrqWX1SDRahR8eHWmWHEV1WQ3k1rs,1554
4
+ bluer_sbc/config.env,sha256=1UOU7j1cP_hZEiJoRKrjxmsziWMkz92W-o9q_IOJx7Y,681
5
+ bluer_sbc/env.py,sha256=PP_KcbMStWVvKtw79PFNampTxCuEV7vQvhCiINtLwBA,1624
6
6
  bluer_sbc/host.py,sha256=RacmqxPRBQrL--JHx_Q-KyuEjEZ1kSFu4fa5pCA0CHQ,209
7
7
  bluer_sbc/logger.py,sha256=4euXgNprDpQSuR45RXy0kWQ1LvCL_dwOi2v37hVBWvk,99
8
8
  bluer_sbc/sample.env,sha256=mX86TGaZvbbGKbiXQdInSBu7sVvLs2IzqYaHNVl0g5M,50
9
9
  bluer_sbc/urls.py,sha256=Bjdewssljt0LIefjixBem9JN0kkghPvmrIETj3GdXbY,17
10
- bluer_sbc/.abcli/ROS.sh,sha256=n0zl46gYEwAQb7scfBYM9Jk9JCrX1PRH4jzmVrVfDxk,62
11
10
  bluer_sbc/.abcli/abcli.sh,sha256=Q_YRZUeFjN4UT9zT8lzrNIQSuORPie4Cp5CW5O2pX5w,290
12
11
  bluer_sbc/.abcli/actions.sh,sha256=P4d9lOzxdvkISZ0M3lZKH9JlmrcWTJ_HeEQAhIRLvC8,224
13
12
  bluer_sbc/.abcli/adafruit_rgb_matrix.sh,sha256=DwPJeuDXYa_F0r4nIWNeBYVtodyHYT2tV9JxPbWxhAM,382
14
- bluer_sbc/.abcli/alias.sh,sha256=0J8ChbWxoRSA-nkVpzweNaEKEqhT6X6ah32o5I69Hyk,72
13
+ bluer_sbc/.abcli/alias.sh,sha256=PsTwzDXyeSvXGY-0LRF3U8df3AQVvPU35MOKQ4lx7xo,104
15
14
  bluer_sbc/.abcli/blue_sbc.sh,sha256=4O_0C56Xj5P7FjSTet5k7hvaNa-SIKpBUsz4MkBUc84,198
16
15
  bluer_sbc/.abcli/camera.sh,sha256=cmDDqUoy-YaO-nwKoTcsgrX-KbZ1JtXiPA3RVBoUb3s,447
17
16
  bluer_sbc/.abcli/grove.sh,sha256=6Lf4TiQzZj9uStCY9ezd8djcqVthzbybkmgmZ8Kr9wE,1180
18
17
  bluer_sbc/.abcli/hat.sh,sha256=ggMb9XOFA3t3sBTGalQK4x7yNuAgK3jA6UkFDWAnndM,449
19
18
  bluer_sbc/.abcli/lepton.sh,sha256=e7bzeYC8JpZMTTWkIfIscPfsoGYPb1ONWaTdDrglfRc,327
20
19
  bluer_sbc/.abcli/scroll_phat_hd.sh,sha256=AUD38PfNMCA-88GjHa-xV4OM7IS8mg5ECNFjAzLJ8AQ,331
21
- bluer_sbc/.abcli/seed.sh,sha256=75cd8YCA7JGXgohVk-N9CjxCLjZpIoAWYGy_QJ9wHlA,1639
20
+ bluer_sbc/.abcli/seed.sh,sha256=9azGhOe8g9FEAsI87AkJfKpLp-tF4Ej1x2dgcJ0sa5I,63
22
21
  bluer_sbc/.abcli/session.sh,sha256=90Y-2pzZnM3YZO9sYeshS83oiLUE38WqCl-gA_RfWT0,1003
23
22
  bluer_sbc/.abcli/sparkfun_top_phat.sh,sha256=F8dV3MjghNU1MMzCXRnQ0kaorr2BOswLBt8Sry5Youo,686
24
23
  bluer_sbc/.abcli/unicorn_16x16.sh,sha256=_cvgK1tT51BqN12HxEx_9FXWTNvPISd4T7pPmA2Jxfo,330
25
- bluer_sbc/.abcli/ROS/seed.sh,sha256=8OVfgFjU6KDv0V6V_CaRSswa4lACs3pQbVV8oGGVNnY,2407
26
24
  bluer_sbc/.abcli/install/adafruit_rgb_matrix.sh,sha256=YwUKVwwNtmETTomaPUi5O01_Bhoo9IZGdkv3ohGYyTY,452
27
25
  bluer_sbc/.abcli/install/grove.sh,sha256=4ceAMdU62p-_Y3gSF_ZLjqZqCnZ3ka_mKQVKu-bvdPI,848
28
26
  bluer_sbc/.abcli/install/lepton.sh,sha256=ziLRm872Y-SIRSqXFdSPap596hWFNOSJGz6oFLY4nMw,1005
29
- bluer_sbc/.abcli/install/rpi.sh,sha256=JDiEdEgTgZ2HaGmu7H5ygzeBy9SHZrw20Jnay8EsKf4,2388
30
27
  bluer_sbc/.abcli/install/scroll_phat_hd.sh,sha256=CxMLLh34C1i9FRyaD9JTUI9chTik18LAJltiEIax_Xk,395
31
28
  bluer_sbc/.abcli/install/sparkfun_top_phat.sh,sha256=3kOMZXBafLm2RqHXXgTx2Ez5WwY5ebKx6hdIK2TN2V0,1298
32
29
  bluer_sbc/.abcli/install/template.sh,sha256=Qqj6JKZlaxAqUGbY88gkNn-v-_aTUtKzpyi-lw353aY,215
33
30
  bluer_sbc/.abcli/install/unicorn_16x16.sh,sha256=zt6VN6c6cLQ59m7GiUNdV7aPTfO8CRoYtSs4VIuEJFw,496
31
+ bluer_sbc/.abcli/seed/headless_rpi.sh,sha256=Sen1-Spg6lvBAzAqacLw42iJgME-v3yVs5T1qMuSO6c,2298
32
+ bluer_sbc/.abcli/seed/headless_rpi_64_bit.sh,sha256=EsK30ungz2sDDrRBVVzNcqSTnMKKEcS6IBPVfRXt7N0,1315
33
+ bluer_sbc/.abcli/seed/headless_ubuntu_rpi.sh,sha256=QQRkOLstdWequW4eutQPimhKwT1yHtHNRUJNhKN3FZ0,2512
34
+ bluer_sbc/.abcli/seed/jetson.sh,sha256=QAvc-6aQwZ5oEhV5oruGfyFUwftsrPnO_d_7ryRQRkk,971
35
+ bluer_sbc/.abcli/seed/rpi.sh,sha256=HzCcPnuC2DneMtiHawD6tjcgLuyCstljl-A90kmpDeg,968
36
+ bluer_sbc/.abcli/seed/swallow_raspbian.sh,sha256=QK9YSkLA0_j5D_r8cp5DENLKhnczUj4a40O4w68ER98,363
34
37
  bluer_sbc/.abcli/tests/README.sh,sha256=0hp3y_URdsFtnYw5Ujty6xy5SNhNHGEVPqpQoYxu0WA,142
35
38
  bluer_sbc/.abcli/tests/camera.sh,sha256=NRr-RbyNORMSHYxNu6VUpVzHIJ2Qy-5NQr2qh54kqUg,1013
36
39
  bluer_sbc/.abcli/tests/help.sh,sha256=sfbx43OBqXwviy4yjVYTz38eTRijbWKWJlH2v4HvdSA,1359
37
- bluer_sbc/.abcli/tests/seed.sh,sha256=2FxgOe2WxSGKqKaigqxl28LCG4psIPVWE6I7oh9XjR4,335
40
+ bluer_sbc/.abcli/tests/seed.sh,sha256=NQUQzgHQZITgaq2aFkiZkaLT0VKmIsrl3aTqSkr8670,392
38
41
  bluer_sbc/.abcli/tests/version.sh,sha256=odDOmAFlzH7KtsAYWOmyLsQ6GAws6XadNlZ6H-NZuzc,147
39
42
  bluer_sbc/ROS/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
40
43
  bluer_sbc/algo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -71,20 +74,22 @@ bluer_sbc/help/sparkfun_top_phat.py,sha256=4JQMqzapnx5PBtzfw8RqpqgXtnF0HqDWxuTss
71
74
  bluer_sbc/help/unicorn_16x16.py,sha256=0uKABkkY7VGfmUj2U8g0fA0AvXDBlloVzGQXbx_mPO8,378
72
75
  bluer_sbc/imager/__init__.py,sha256=THkQ_yCpArJKfP7u_oeR-W7vGzCmXFDOa102FTDPAT4,419
73
76
  bluer_sbc/imager/classes.py,sha256=ikfQuazosqVHx-NEXArDvvCCbrOw8YJmRG6yPmiOijo,519
74
- bluer_sbc/imager/camera/__init__.py,sha256=n3jSl-WtSgP0DN9Qbl4cbs12tUmsmftxsJx7HXlHeeo,72
77
+ bluer_sbc/imager/camera/__init__.py,sha256=rkye_7_RosR6q5X8ceWJi-SsGrW23oi761j-_BYu_3w,318
75
78
  bluer_sbc/imager/camera/__main__.py,sha256=KIS6lH8jWhE8_8vamQVhM-xd78BQ0GxRBHf7s8BQXFw,1588
76
- bluer_sbc/imager/camera/classes.py,sha256=9i3nXO4Rb6k9mugz3HT_5Vqg2dHKVlmekgEhmIYaUPs,7200
77
79
  bluer_sbc/imager/camera/constants.py,sha256=bcQ9-iz0OeKII_uFFQYDMZnTxPkh1C--9IsdUFb1qsY,606
80
+ bluer_sbc/imager/camera/generic.py,sha256=TXqcdlcQWn_CUiOOai8Uh7xcyyfk0pg_02KIoiug9so,5622
81
+ bluer_sbc/imager/camera/rpi.py,sha256=IF1iHoZQiXX3edpqPLc9sGtTyMH2suEnIck_vHST46U,3110
82
+ bluer_sbc/imager/camera/rpi_64_bit.py,sha256=zRmdsUjsGfhdbAQroRoWmwuJ0rG_6fMM0-glSlXxEms,1253
78
83
  bluer_sbc/imager/lepton/__init__.py,sha256=qHzzDoYLe-RxMjIul-HTxT7sRt3O-sVC44vZJQZ9VBU,72
79
84
  bluer_sbc/imager/lepton/__main__.py,sha256=AUurRrU64bqLDKoiMeMPbHyIu53Rz4426ihzsPX6Juk,1081
80
85
  bluer_sbc/imager/lepton/classes.py,sha256=CnWEwaBZC2hAFuYkv32SAu7GaIK1A-PiLEppAgL7z4M,963
81
86
  bluer_sbc/imager/lepton/python2.py,sha256=1jAHHzmda_bmqKj0b0X-2KONW5s9umxKaTY4ZieoaCI,1600
82
87
  bluer_sbc/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
88
  bluer_sbc/session/__main__.py,sha256=O2Tv6HgE8Bos7ASIViYludpWVi6EEc9XRoP8jYC2-2Q,534
84
- bluer_sbc/session/classes.py,sha256=WrfFBXf6Shz4PGyw1Xpr5nAnWbhfHXzabLnW393zbsE,8938
89
+ bluer_sbc/session/classes.py,sha256=vap_vDWwZtecBY2G65IYPee0PQX7OlNcjLzfFu4rW-8,9355
85
90
  bluer_sbc/session/functions.py,sha256=eRJKSczRjKn3Fo2jv8_4EMAZwfJBj5cIPg2WqHkC2Q8,481
86
- bluer_sbc-8.121.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
87
- bluer_sbc-8.121.1.dist-info/METADATA,sha256=i5ZH8iMkwj1cYKqjgkFEL_RBmL-pymZ-zK0gk0pX0x4,3552
88
- bluer_sbc-8.121.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
89
- bluer_sbc-8.121.1.dist-info/top_level.txt,sha256=DsLDHFiTeAj2mctGVmCSgWUhzCznWSQoUmQ1VyEmnT0,10
90
- bluer_sbc-8.121.1.dist-info/RECORD,,
91
+ bluer_sbc-8.151.1.dist-info/licenses/LICENSE,sha256=ogEPNDSH0_dhiv_lT3ifVIdgIzHAqNA_SemnxUfPBJk,7048
92
+ bluer_sbc-8.151.1.dist-info/METADATA,sha256=5RCgOUDvGkW3NfA7OZPjpkOOHkoBhc3ChOoHJDohvtc,3552
93
+ bluer_sbc-8.151.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
+ bluer_sbc-8.151.1.dist-info/top_level.txt,sha256=DsLDHFiTeAj2mctGVmCSgWUhzCznWSQoUmQ1VyEmnT0,10
95
+ bluer_sbc-8.151.1.dist-info/RECORD,,
bluer_sbc/.abcli/ROS.sh DELETED
@@ -1,3 +0,0 @@
1
- #! /usr/bin/env bash
2
-
3
- bluer_ai_source_caller_suffix_path /ROS
@@ -1,65 +0,0 @@
1
- #! /usr/bin/env bash
2
-
3
- function bluer_ai_install_rpi() {
4
- pushd $abcli_path_git >/dev/null
5
-
6
- # https://docs.donkeycar.com/guide/robot_sbc/setup_raspberry_pi/
7
- sudo apt-get update
8
- sudo apt-get -y upgrade
9
-
10
- sudo apt-get --yes --force-yes install build-essential python3 python3-dev python3-pip \
11
- python3-virtualenv python3-numpy python3-picamera python3-pandas python3-rpi.gpio \
12
- i2c-tools avahi-utils joystick libopenjp2-7-dev libtiff5-dev gfortran libatlas-base-dev \
13
- libopenblas-dev libhdf5-serial-dev libgeos-dev git ntp
14
-
15
- sudo apt-get --yes --force-yes install libilmbase-dev libopenexr-dev libgstreamer1.0-dev \
16
- libjasper-dev libwebp-dev libatlas-base-dev libavcodec-dev libavformat-dev libswscale-dev \
17
- libqtgui4 libqt4-test
18
-
19
- # https://rtcbot.readthedocs.io/en/latest/installing.html
20
- sudo apt-get --yes --force-yes install python3-numpy python3-cffi python3-aiohttp \
21
- libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev \
22
- libswscale-dev libswresample-dev libavfilter-dev libopus-dev \
23
- libvpx-dev pkg-config libsrtp2-dev python3-opencv pulseaudio
24
-
25
- cd
26
- python3 -m virtualenv -p python3 env --system-site-packages
27
- echo "source env/bin/activate" >>~/.bashrc
28
- source env/bin/activate
29
-
30
- cd git
31
- git clone https://github.com/autorope/donkeycar
32
- cd donkeycar
33
- git checkout master
34
- pip3 install -e .[pi]
35
-
36
- pip3 install numpy --upgrade
37
-
38
- cd
39
- curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1DCfoSwlsdX9X4E3pLClE1z0fvw8tFESP" >/dev/null
40
- CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
41
- curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1DCfoSwlsdX9X4E3pLClE1z0fvw8tFESP" -o tensorflow-2.2.0-cp37-cp37m-linux_armv7l.whl
42
- pip3 install tensorflow-2.2.0-cp37-cp37m-linux_armv7l.whl
43
-
44
- sudo apt --yes --force-yes install python3-opencv
45
-
46
- pip3 install PyMySQL==0.10.1
47
- pip3 install tqdm
48
- pip3 install boto3
49
- pip3 install dill
50
- pip3 install imutils
51
-
52
- # https://rtcbot.readthedocs.io/en/latest/installing.html
53
- # pip install rtcbot
54
-
55
- pip3 install awscli --upgrade
56
- if [[ $PATH != *"/home/pi/.local/bin"* ]]; then
57
- export PATH=/home/pi/.local/bin:$PATH
58
- fi
59
-
60
- popd >/dev/null
61
- }
62
-
63
- if [ "$abcli_is_rpi" == true ]; then
64
- bluer_ai_install_module rpi 109
65
- fi
@@ -1,259 +0,0 @@
1
- import cv2
2
- from typing import Tuple
3
- import numpy as np
4
- from time import sleep
5
-
6
- from blueness import module
7
- from bluer_options import string
8
- from bluer_options import host
9
- from bluer_options.timer import Timer
10
- from bluer_options.logger import crash_report
11
- from bluer_objects import file, objects
12
-
13
- from bluer_sbc import env
14
- from bluer_sbc import NAME
15
- from bluer_sbc.hardware import hardware
16
- from bluer_sbc.imager.classes import Imager
17
- from bluer_sbc.logger import logger
18
-
19
- NAME = module.name(__file__, NAME)
20
-
21
-
22
- class Camera(Imager):
23
- def __init__(self):
24
- self.device = None
25
- self.resolution = []
26
-
27
- def capture(
28
- self,
29
- close_after: bool = True,
30
- log: bool = True,
31
- open_before: bool = True,
32
- filename: str = "",
33
- object_name: str = "",
34
- ) -> Tuple[bool, np.ndarray]:
35
- success = False
36
- image = np.ones((1, 1, 3), dtype=np.uint8) * 127
37
-
38
- if open_before:
39
- if not self.open():
40
- return success, image
41
-
42
- if self.device is None:
43
- return success, image
44
-
45
- if host.is_rpi():
46
- temp = file.auxiliary("camera", "png")
47
- try:
48
- self.device.capture(temp)
49
- success = True
50
- except Exception as e:
51
- crash_report(e)
52
-
53
- if success:
54
- success, image = file.load_image(temp)
55
- else:
56
- try:
57
- success, image = self.device.read()
58
-
59
- if success:
60
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
61
-
62
- except Exception as e:
63
- crash_report(e)
64
-
65
- if close_after:
66
- self.close()
67
-
68
- if success and log:
69
- logger.info(f"{NAME}.capture(): {string.pretty_shape_of_matrix(image)}")
70
-
71
- if success and filename:
72
- success = file.save_image(
73
- filename=objects.path_of(
74
- object_name=object_name,
75
- filename=filename,
76
- ),
77
- image=image,
78
- log=log,
79
- )
80
-
81
- return success, image
82
-
83
- # https://projects.raspberrypi.org/en/projects/getting-started-with-picamera/6
84
- def capture_video(
85
- self,
86
- filename: str,
87
- object_name: str,
88
- length: int = 10, # in seconds
89
- preview: bool = True,
90
- pulse: bool = True,
91
- resolution=None,
92
- ) -> bool:
93
- if not host.is_rpi():
94
- logger.error(f"{NAME}.capture_video() only works on rpi.")
95
- return False
96
-
97
- if not self.open(resolution=resolution):
98
- return False
99
-
100
- full_filename = objects.path_of(
101
- object_name=object_name,
102
- filename=filename,
103
- )
104
-
105
- success = True
106
- try:
107
- if preview:
108
- self.device.start_preview()
109
-
110
- self.device.start_recording(full_filename)
111
- if pulse:
112
- for _ in range(int(10 * length)):
113
- hardware.pulse("outputs")
114
- sleep(0.1)
115
- else:
116
- sleep(length)
117
- self.device.stop_recording()
118
-
119
- if preview:
120
- self.device.stop_preview()
121
- except Exception as e:
122
- crash_report(e)
123
- success = False
124
-
125
- if not self.close():
126
- return False
127
-
128
- if success:
129
- logger.info(
130
- "{}.capture_video(): {} -{}-> {}".format(
131
- NAME,
132
- string.pretty_duration(length),
133
- string.pretty_bytes(file.size(full_filename)),
134
- filename,
135
- )
136
- )
137
-
138
- return success
139
-
140
- def close(self, log: bool = True) -> bool:
141
- if self.device is None:
142
- logger.warning(f"{NAME}.close(): device is {self.device}, failed.")
143
- return False
144
-
145
- success = False
146
- try:
147
- if host.is_rpi():
148
- self.device.close()
149
- else:
150
- self.device.release()
151
- success = True
152
- except Exception as e:
153
- crash_report(e)
154
- return False
155
-
156
- self.device = None
157
-
158
- if log:
159
- logger.info(f"{NAME}.close().")
160
-
161
- return success
162
-
163
- def get_resolution(self):
164
- try:
165
- if host.is_rpi():
166
- from picamera import PiCamera
167
-
168
- return [value for value in self.device.resolution]
169
- else:
170
- return [
171
- int(self.device.get(const))
172
- for const in [cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FRAME_WIDTH]
173
- ]
174
- except Exception as e:
175
- crash_report(e)
176
- return []
177
-
178
- def open(
179
- self,
180
- log: bool = True,
181
- resolution=None,
182
- ) -> bool:
183
- try:
184
- if host.is_rpi():
185
- from picamera import PiCamera
186
-
187
- self.device = PiCamera()
188
- self.device.rotation = env.BLUER_SBC_CAMERA_ROTATION
189
-
190
- # https://projects.raspberrypi.org/en/projects/getting-started-with-picamera/7
191
- self.device.resolution = (
192
- (
193
- (2592, 1944)
194
- if env.BLUER_SBC_CAMERA_HI_RES
195
- else (
196
- env.BLUER_SBC_CAMERA_WIDTH,
197
- env.BLUER_SBC_CAMERA_HEIGHT,
198
- )
199
- )
200
- if resolution is None
201
- else resolution
202
- )
203
- else:
204
- self.device = cv2.VideoCapture(0)
205
-
206
- # https://stackoverflow.com/a/31464688
207
- self.device.set(cv2.CAP_PROP_FRAME_WIDTH, 10000)
208
- self.device.set(cv2.CAP_PROP_FRAME_HEIGHT, 10000)
209
-
210
- self.resolution = self.get_resolution()
211
-
212
- if log:
213
- logger.info(f"{NAME}.open({string.pretty_shape(self.resolution)})")
214
-
215
- return True
216
- except Exception as e:
217
- crash_report(e)
218
- return False
219
-
220
- def preview(
221
- self,
222
- length: float = -1,
223
- ) -> bool:
224
- logger.info(
225
- "{}.preview{} ... | press q or e to quit ...".format(
226
- NAME,
227
- "[{}]".format("" if length == -1 else string.pretty_duration(length)),
228
- )
229
- )
230
-
231
- hardware.sign_images = False
232
- timer = Timer(length, "preview")
233
- try:
234
- self.open(
235
- log=True,
236
- resolution=(320, 240),
237
- )
238
-
239
- while not hardware.pressed("qe"):
240
- _, image = self.capture(
241
- close_after=False,
242
- log=False,
243
- open_before=False,
244
- )
245
- hardware.update_screen(image, None, [])
246
-
247
- if timer.tick(wait=True):
248
- logger.info(
249
- "{} is up, quitting.".format(string.pretty_duration(length))
250
- )
251
- break
252
-
253
- except KeyboardInterrupt:
254
- logger.info("Ctrl+C, stopping.")
255
-
256
- finally:
257
- self.close(log=True)
258
-
259
- return True