bluer-sbc 8.3.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/abcli.sh +12 -0
- bluer_sbc/.abcli/actions.sh +11 -0
- bluer_sbc/.abcli/adafruit_rgb_matrix.sh +14 -0
- bluer_sbc/.abcli/alias.sh +5 -0
- bluer_sbc/.abcli/blue_sbc.sh +11 -0
- bluer_sbc/.abcli/camera.sh +20 -0
- bluer_sbc/.abcli/grove.sh +43 -0
- bluer_sbc/.abcli/hat.sh +22 -0
- bluer_sbc/.abcli/install/adafruit_rgb_matrix.sh +15 -0
- bluer_sbc/.abcli/install/grove.sh +29 -0
- bluer_sbc/.abcli/install/lepton.sh +33 -0
- bluer_sbc/.abcli/install/rpi.sh +65 -0
- bluer_sbc/.abcli/install/scroll_phat_hd.sh +14 -0
- bluer_sbc/.abcli/install/sparkfun_top_phat.sh +33 -0
- bluer_sbc/.abcli/install/template.sh +9 -0
- bluer_sbc/.abcli/install/unicorn_16x16.sh +16 -0
- bluer_sbc/.abcli/lepton.sh +15 -0
- bluer_sbc/.abcli/scroll_phat_hd.sh +14 -0
- bluer_sbc/.abcli/session.sh +39 -0
- bluer_sbc/.abcli/sparkfun_top_phat.sh +27 -0
- bluer_sbc/.abcli/tests/README.sh +8 -0
- bluer_sbc/.abcli/tests/camera.sh +47 -0
- bluer_sbc/.abcli/tests/help.sh +65 -0
- bluer_sbc/.abcli/tests/version.sh +8 -0
- bluer_sbc/.abcli/unicorn_16x16.sh +14 -0
- bluer_sbc/README.py +51 -0
- bluer_sbc/__init__.py +17 -0
- bluer_sbc/__main__.py +16 -0
- bluer_sbc/algo/__init__.py +0 -0
- bluer_sbc/algo/diff.py +81 -0
- bluer_sbc/config.env +30 -0
- bluer_sbc/env.py +35 -0
- bluer_sbc/hardware/__init__.py +38 -0
- bluer_sbc/hardware/adafruit_rgb_matrix.py +30 -0
- bluer_sbc/hardware/display.py +112 -0
- bluer_sbc/hardware/grove.py +104 -0
- bluer_sbc/hardware/hardware.py +58 -0
- bluer_sbc/hardware/hat/__init__.py +0 -0
- bluer_sbc/hardware/hat/__main__.py +91 -0
- bluer_sbc/hardware/hat/abstract.py +136 -0
- bluer_sbc/hardware/hat/prototype.py +161 -0
- bluer_sbc/hardware/screen.py +17 -0
- bluer_sbc/hardware/scroll_phat_hd.py +35 -0
- bluer_sbc/hardware/sparkfun_top_phat/__init__.py +0 -0
- bluer_sbc/hardware/sparkfun_top_phat/__main__.py +51 -0
- bluer_sbc/hardware/sparkfun_top_phat/classes.py +104 -0
- bluer_sbc/hardware/unicorn_16x16.py +44 -0
- bluer_sbc/help/__init__.py +0 -0
- bluer_sbc/help/__main__.py +10 -0
- bluer_sbc/help/adafruit_rgb_matrix.py +23 -0
- bluer_sbc/help/camera.py +71 -0
- bluer_sbc/help/functions.py +52 -0
- bluer_sbc/help/grove.py +59 -0
- bluer_sbc/help/hat.py +56 -0
- bluer_sbc/help/lepton.py +39 -0
- bluer_sbc/help/scroll_phat_hd.py +23 -0
- bluer_sbc/help/session.py +26 -0
- bluer_sbc/help/sparkfun_top_phat.py +26 -0
- bluer_sbc/help/unicorn_16x16.py +23 -0
- bluer_sbc/host.py +11 -0
- bluer_sbc/imager/__init__.py +16 -0
- bluer_sbc/imager/camera/__init__.py +3 -0
- bluer_sbc/imager/camera/__main__.py +69 -0
- bluer_sbc/imager/camera/classes.py +259 -0
- bluer_sbc/imager/camera/constants.py +30 -0
- bluer_sbc/imager/classes.py +25 -0
- bluer_sbc/imager/lepton/__init__.py +3 -0
- bluer_sbc/imager/lepton/__main__.py +51 -0
- bluer_sbc/imager/lepton/classes.py +35 -0
- bluer_sbc/imager/lepton/python2.py +70 -0
- bluer_sbc/logger.py +5 -0
- bluer_sbc/sample.env +1 -0
- bluer_sbc/session/__init__.py +0 -0
- bluer_sbc/session/__main__.py +27 -0
- bluer_sbc/session/classes.py +318 -0
- bluer_sbc/session/functions.py +22 -0
- bluer_sbc/urls.py +1 -0
- bluer_sbc-8.3.1.dist-info/METADATA +58 -0
- bluer_sbc-8.3.1.dist-info/RECORD +82 -0
- bluer_sbc-8.3.1.dist-info/WHEEL +5 -0
- bluer_sbc-8.3.1.dist-info/licenses/LICENSE +121 -0
- bluer_sbc-8.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from bluer_options.terminal import show_usage
|
|
4
|
+
from bluer_ai.help.generic import help_functions as generic_help_functions
|
|
5
|
+
|
|
6
|
+
from bluer_sbc.help.adafruit_rgb_matrix import (
|
|
7
|
+
help_functions as help_adafruit_rgb_matrix,
|
|
8
|
+
)
|
|
9
|
+
from bluer_sbc.help.camera import help_functions as help_camera
|
|
10
|
+
from bluer_sbc.help.grove import help_functions as help_grove
|
|
11
|
+
from bluer_sbc.help.hat import help_functions as help_hat
|
|
12
|
+
from bluer_sbc.help.lepton import help_functions as help_lepton
|
|
13
|
+
from bluer_sbc.help.scroll_phat_hd import help_functions as help_scroll_phat_hd
|
|
14
|
+
from bluer_sbc.help.sparkfun_top_phat import help_functions as help_sparkfun_top_phat
|
|
15
|
+
from bluer_sbc.help.session import help_functions as help_session
|
|
16
|
+
from bluer_sbc.help.unicorn_16x16 import help_functions as help_unicorn_16x16
|
|
17
|
+
from bluer_sbc import ALIAS
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def help_browse(
|
|
21
|
+
tokens: List[str],
|
|
22
|
+
mono: bool,
|
|
23
|
+
) -> str:
|
|
24
|
+
options = "actions|repo"
|
|
25
|
+
|
|
26
|
+
return show_usage(
|
|
27
|
+
[
|
|
28
|
+
"@plugin",
|
|
29
|
+
"browse",
|
|
30
|
+
f"[{options}]",
|
|
31
|
+
],
|
|
32
|
+
"browse bluer_sbc.",
|
|
33
|
+
mono=mono,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
help_functions = generic_help_functions(plugin_name=ALIAS)
|
|
38
|
+
|
|
39
|
+
help_functions.update(
|
|
40
|
+
{
|
|
41
|
+
"adafruit_rgb_matrix": help_adafruit_rgb_matrix,
|
|
42
|
+
"browse": help_browse,
|
|
43
|
+
"camera": help_camera,
|
|
44
|
+
"grove": help_grove,
|
|
45
|
+
"hat": help_hat,
|
|
46
|
+
"lepton": help_lepton,
|
|
47
|
+
"scroll_phat_hd": help_scroll_phat_hd,
|
|
48
|
+
"session": help_session,
|
|
49
|
+
"sparkfun_top_phat": help_sparkfun_top_phat,
|
|
50
|
+
"unicorn_16x16": help_unicorn_16x16,
|
|
51
|
+
}
|
|
52
|
+
)
|
bluer_sbc/help/grove.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_info(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
return show_usage(
|
|
11
|
+
[
|
|
12
|
+
"grove",
|
|
13
|
+
"info",
|
|
14
|
+
],
|
|
15
|
+
"show grove info.",
|
|
16
|
+
mono=mono,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def help_validate(
|
|
21
|
+
tokens: List[str],
|
|
22
|
+
mono: bool,
|
|
23
|
+
) -> str:
|
|
24
|
+
options = "adc | button"
|
|
25
|
+
|
|
26
|
+
return show_usage(
|
|
27
|
+
[
|
|
28
|
+
"grove",
|
|
29
|
+
"validate",
|
|
30
|
+
f"[{options}]",
|
|
31
|
+
],
|
|
32
|
+
"validate grove.",
|
|
33
|
+
mono=mono,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def help_validate_oled_128x64(
|
|
38
|
+
tokens: List[str],
|
|
39
|
+
mono: bool,
|
|
40
|
+
) -> str:
|
|
41
|
+
options = "animate | buttons | image | shapes | stats"
|
|
42
|
+
|
|
43
|
+
return show_usage(
|
|
44
|
+
[
|
|
45
|
+
"grove",
|
|
46
|
+
"validate",
|
|
47
|
+
"oled_128x64",
|
|
48
|
+
f"[{options}]",
|
|
49
|
+
],
|
|
50
|
+
"validate grove oled_128x64.",
|
|
51
|
+
mono=mono,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
help_functions = {
|
|
56
|
+
"info": help_info,
|
|
57
|
+
"validate": help_validate,
|
|
58
|
+
"validate_oled_128x64": help_validate_oled_128x64,
|
|
59
|
+
}
|
bluer_sbc/help/hat.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_input(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
return show_usage(
|
|
11
|
+
[
|
|
12
|
+
"@sbc",
|
|
13
|
+
"hat",
|
|
14
|
+
"input",
|
|
15
|
+
],
|
|
16
|
+
"read hat inputs.",
|
|
17
|
+
mono=mono,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def help_output(
|
|
22
|
+
tokens: List[str],
|
|
23
|
+
mono: bool,
|
|
24
|
+
) -> str:
|
|
25
|
+
return show_usage(
|
|
26
|
+
[
|
|
27
|
+
"@sbc",
|
|
28
|
+
"hat",
|
|
29
|
+
"output",
|
|
30
|
+
"<10101010>",
|
|
31
|
+
],
|
|
32
|
+
"activate hat outputs.",
|
|
33
|
+
mono=mono,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def help_validate(
|
|
38
|
+
tokens: List[str],
|
|
39
|
+
mono: bool,
|
|
40
|
+
) -> str:
|
|
41
|
+
return show_usage(
|
|
42
|
+
[
|
|
43
|
+
"@sbc",
|
|
44
|
+
"hat",
|
|
45
|
+
"validate",
|
|
46
|
+
],
|
|
47
|
+
"validate hat.",
|
|
48
|
+
mono=mono,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
help_functions = {
|
|
53
|
+
"input": help_input,
|
|
54
|
+
"output": help_output,
|
|
55
|
+
"validate": help_validate,
|
|
56
|
+
}
|
bluer_sbc/help/lepton.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage, xtra
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_capture(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
return show_usage(
|
|
11
|
+
[
|
|
12
|
+
"@sbc",
|
|
13
|
+
"lepton",
|
|
14
|
+
"capture",
|
|
15
|
+
],
|
|
16
|
+
"lepton.capture.",
|
|
17
|
+
mono=mono,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def help_preview(
|
|
22
|
+
tokens: List[str],
|
|
23
|
+
mono: bool,
|
|
24
|
+
) -> str:
|
|
25
|
+
return show_usage(
|
|
26
|
+
[
|
|
27
|
+
"@sbc",
|
|
28
|
+
"lepton",
|
|
29
|
+
"preview",
|
|
30
|
+
],
|
|
31
|
+
"lepton.preview.",
|
|
32
|
+
mono=mono,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
help_functions = {
|
|
37
|
+
"capture": help_capture,
|
|
38
|
+
"preview": help_preview,
|
|
39
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_validate(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
return show_usage(
|
|
11
|
+
[
|
|
12
|
+
"@sbc",
|
|
13
|
+
"scroll_phat_hd",
|
|
14
|
+
"validate",
|
|
15
|
+
],
|
|
16
|
+
"validate scroll_phat_hd.",
|
|
17
|
+
mono=mono,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
help_functions = {
|
|
22
|
+
"validate": help_validate,
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage, xtra
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_session_start(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
options = xtra("dryrun,sudo,~upload", mono=mono)
|
|
11
|
+
|
|
12
|
+
return show_usage(
|
|
13
|
+
[
|
|
14
|
+
"@sbc",
|
|
15
|
+
"session",
|
|
16
|
+
"start",
|
|
17
|
+
f"[{options}]",
|
|
18
|
+
],
|
|
19
|
+
"start an @sbc session.",
|
|
20
|
+
mono=mono,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
help_functions = {
|
|
25
|
+
"start": help_session_start,
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage, xtra
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_validate(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
options = "button | leds"
|
|
11
|
+
|
|
12
|
+
return show_usage(
|
|
13
|
+
[
|
|
14
|
+
"@sbc",
|
|
15
|
+
"sparkfun_top_phat",
|
|
16
|
+
"validate",
|
|
17
|
+
f"[{options}]",
|
|
18
|
+
],
|
|
19
|
+
"validate sparkfun_top_phat.",
|
|
20
|
+
mono=mono,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
help_functions = {
|
|
25
|
+
"validate": help_validate,
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from blue_options.terminal import show_usage, xtra
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def help_validate(
|
|
7
|
+
tokens: List[str],
|
|
8
|
+
mono: bool,
|
|
9
|
+
) -> str:
|
|
10
|
+
return show_usage(
|
|
11
|
+
[
|
|
12
|
+
"@sbc",
|
|
13
|
+
"unicorn_16x16",
|
|
14
|
+
"validate",
|
|
15
|
+
],
|
|
16
|
+
"validate unicorn_16x16.",
|
|
17
|
+
mono=mono,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
help_functions = {
|
|
22
|
+
"validate": help_validate,
|
|
23
|
+
}
|
bluer_sbc/host.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from blueness import module
|
|
2
|
+
|
|
3
|
+
from bluer_sbc import NAME
|
|
4
|
+
from bluer_sbc import env
|
|
5
|
+
from bluer_sbc.logger import logger
|
|
6
|
+
|
|
7
|
+
NAME = module.name(__file__, NAME)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
imager_name = env.BLUER_SBC_SESSION_IMAGER
|
|
11
|
+
if imager_name == "lepton":
|
|
12
|
+
from bluer_sbc.imager.lepton import instance as imager
|
|
13
|
+
else:
|
|
14
|
+
from bluer_sbc.imager.camera import instance as imager
|
|
15
|
+
|
|
16
|
+
logger.info(f"{NAME}: {imager_name}: {imager.__class__.__name__}")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
from bluer_options import string
|
|
5
|
+
from bluer_objects.env import abcli_object_name
|
|
6
|
+
|
|
7
|
+
from bluer_sbc import NAME
|
|
8
|
+
from bluer_sbc.imager.camera import instance as camera
|
|
9
|
+
from bluer_sbc.logger import logger
|
|
10
|
+
|
|
11
|
+
NAME = module.name(__file__, NAME)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
parser = argparse.ArgumentParser(NAME)
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"task",
|
|
17
|
+
type=str,
|
|
18
|
+
help="capture | capture_video | preview",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"--object_name",
|
|
22
|
+
type=str,
|
|
23
|
+
default=abcli_object_name,
|
|
24
|
+
)
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--filename",
|
|
27
|
+
type=str,
|
|
28
|
+
default="",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--length",
|
|
32
|
+
type=int,
|
|
33
|
+
default=0,
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--output_path",
|
|
37
|
+
type=str,
|
|
38
|
+
default="",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--preview",
|
|
42
|
+
type=int,
|
|
43
|
+
default=1,
|
|
44
|
+
help="0 | 1",
|
|
45
|
+
)
|
|
46
|
+
args = parser.parse_args()
|
|
47
|
+
|
|
48
|
+
success = False
|
|
49
|
+
if args.task == "capture":
|
|
50
|
+
success, image = camera.capture(
|
|
51
|
+
filename=args.filename if args.filename else f"{string.timestamp()}.png",
|
|
52
|
+
object_name=args.object_name,
|
|
53
|
+
)
|
|
54
|
+
elif args.task == "capture_video":
|
|
55
|
+
success = camera.capture_video(
|
|
56
|
+
filename=args.filename if args.filename else f"{string.timestamp()}.h264",
|
|
57
|
+
object_name=args.object_name,
|
|
58
|
+
length=args.length if args.length else 10,
|
|
59
|
+
preview=args.preview,
|
|
60
|
+
resolution=(728, 600),
|
|
61
|
+
)
|
|
62
|
+
elif args.task == "preview":
|
|
63
|
+
success = camera.preview(length=args.length if args.length else -1)
|
|
64
|
+
|
|
65
|
+
else:
|
|
66
|
+
logger.error(f"-{NAME}: {args.task}: command not found.")
|
|
67
|
+
|
|
68
|
+
if not success:
|
|
69
|
+
logger.error(f"-{NAME}: {args.task}: failed.")
|
|
@@ -0,0 +1,259 @@
|
|
|
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 blue_options import string
|
|
8
|
+
from blue_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
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
specifications = {
|
|
2
|
+
"rpi-ir": {
|
|
3
|
+
"height": 1944,
|
|
4
|
+
"width": 2592,
|
|
5
|
+
"diagonal": 3240,
|
|
6
|
+
"fov": {
|
|
7
|
+
"diagonal": 80,
|
|
8
|
+
"horizontal": 64,
|
|
9
|
+
"vertical": 48,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
"rpi-noir": {
|
|
13
|
+
"height": 1944,
|
|
14
|
+
"width": 2592,
|
|
15
|
+
"diagonal": 3240,
|
|
16
|
+
"fov": {
|
|
17
|
+
"horizontal": 62.2,
|
|
18
|
+
"vertical": 48.8,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
"rpi-rgb": {
|
|
22
|
+
"height": 1944,
|
|
23
|
+
"width": 2592,
|
|
24
|
+
"diagonal": 3240,
|
|
25
|
+
"fov": {
|
|
26
|
+
"horizontal": 62.2,
|
|
27
|
+
"vertical": 48.8,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}
|