diff --git a/.gitignore b/.gitignore index b475da3..40ff91e 100644 --- a/.gitignore +++ b/.gitignore @@ -166,4 +166,5 @@ cython_debug/ #.idea/ .DS_Store output/svg -*.mp4 \ No newline at end of file +*.mp4 +output \ No newline at end of file diff --git a/cali.py b/cali.py index f067b4c..e17400e 100644 --- a/cali.py +++ b/cali.py @@ -9,9 +9,6 @@ from itertools import chain from typing import Optional, Sequence, TypedDict, cast import awkward as ak -from matplotlib.pyplot import stem -from numpy import ndarray - class ArucoDictionary(Enum): Dict_4X4_50 = aruco.DICT_4X4_50 @@ -37,10 +34,10 @@ class ArucoDictionary(Enum): Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL -IMAGE_FOLDER = Path("dumped/batch_two/b") +IMAGE_FOLDER = Path("dumped/batch_three/c") OUTPUT_FOLDER = Path("output") DICTIONARY = ArucoDictionary.Dict_4X4_50 -CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "af_03.parquet" +CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "c-af_03.parquet" class CameraParams(TypedDict): diff --git a/compute_3d_maybe.ipynb b/compute_3d_maybe.ipynb new file mode 100644 index 0000000..dbcd9a7 --- /dev/null +++ b/compute_3d_maybe.ipynb @@ -0,0 +1,157 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "import awkward as ak\n", + "from awkward import Array as AwakwardArray, Record as AwkwardRecord\n", + "from typing import cast\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[{prediction: None, trackings: [], frame_num: 0, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 1, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 2, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 3, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 4, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 5, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 6, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 7, ...},\n",
+ " {prediction: None, trackings: [], frame_num: 8, ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " ...,\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...},\n",
+ " {prediction: {Akeypoints: [[...]], ...}, trackings: [{...}], ...}]\n",
+ "-------------------------------------------------------------------\n",
+ "type: 808 * {\n",
+ " prediction: ?{\n",
+ " Akeypoints: var * var * var * float64,\n",
+ " bboxes: var * var * float64,\n",
+ " scores: var * var * var * float64,\n",
+ " frame_number: int64,\n",
+ " reference_frame_size: {\n",
+ " "0": int64,\n",
+ " "1": int64\n",
+ " }\n",
+ " },\n",
+ " trackings: var * {\n",
+ " id: int64,\n",
+ " bounding_boxes: var * var * float64\n",
+ " },\n",
+ " frame_num: int64,\n",
+ " reference_frame_size: {\n",
+ " height: int64,\n",
+ " width: int64\n",
+ " }\n",
+ "}"
+ ],
+ "text/plain": [
+ "{Akeypoints: [[[893, 417], [898, 408], [...], ..., [782, 596], [785, 599]]],\n",
+ " bboxes: [[756, 341, 940, 597]],\n",
+ " scores: [[[0.907], [0.896], [0.916], [0.341], ..., [0.811], [0.835], [0.802]]],\n",
+ " frame_number: 5,\n",
+ " reference_frame_size: {'0': 1080, '1': 1920}}\n",
+ "--------------------------------------------------------------------------------\n",
+ "type: {\n",
+ " Akeypoints: var * var * var * float64,\n",
+ " bboxes: var * var * float64,\n",
+ " scores: var * var * var * float64,\n",
+ " frame_number: int64,\n",
+ " reference_frame_size: {\n",
+ " "0": int64,\n",
+ " "1": int64\n",
+ " }\n",
+ "}"
+ ],
+ "text/plain": [
+ "[{name: 'a', rvec: [[-1.04], ..., [-2.95]], tvec: [...], ...},\n",
- " {name: 'b', rvec: [[0.948], ..., [2.97]], tvec: [...], ...}]\n",
- "--------------------------------------------------------------\n",
- "type: 2 * {\n",
+ "[{name: 'a-ae_08', rvec: [[-0.602], ..., [-3.05]], tvec: [...], ...},\n",
+ " {name: 'b-ae_09', rvec: [[0.572], ..., [3.02]], tvec: [...], ...},\n",
+ " {name: 'c-af_03', rvec: [[-1.98], ..., [-2.4]], tvec: [...], ...},\n",
+ " {name: 'c-prime-af_03', rvec: [[-1.99], ...], tvec: [...], ...}]\n",
+ "---------------------------------------------------------------------\n",
+ "type: 4 * {\n",
" name: string,\n",
" rvec: var * var * float64,\n",
" tvec: var * var * float64,\n",
@@ -304,7 +267,7 @@
"}"
],
"text/plain": [
- ""
+ ""
]
},
"metadata": {},
@@ -313,16 +276,16 @@
{
"data": {
"text/plain": [
- "\n",
+ "\n",
" created_by: parquet-cpp-arrow version 14.0.1\n",
" num_columns: 5\n",
- " num_rows: 2\n",
+ " num_rows: 4\n",
" num_row_groups: 1\n",
" format_version: 2.6\n",
" serialized_size: 0"
]
},
- "execution_count": 8,
+ "execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
@@ -331,19 +294,33 @@
"params = AwkwardArray(\n",
" [\n",
" {\n",
- " \"name\": \"a\",\n",
+ " \"name\": \"a-ae_08\",\n",
" \"rvec\": a_rvec,\n",
" \"tvec\": a_tvec,\n",
" \"camera_matrix\": a_mtx,\n",
" \"distortion_coefficients\": a_dist,\n",
" },\n",
" {\n",
- " \"name\": \"b\",\n",
+ " \"name\": \"b-ae_09\",\n",
" \"rvec\": b_rvec,\n",
" \"tvec\": b_tvec,\n",
- " \"camera_matrix\": b_camera_matrix,\n",
- " \"distortion_coefficients\": b_distortion_coefficients,\n",
+ " \"camera_matrix\": b_mtx,\n",
+ " \"distortion_coefficients\": b_dist,\n",
" },\n",
+ " {\n",
+ " \"name\": \"c-af_03\",\n",
+ " \"rvec\": c_rvec,\n",
+ " \"tvec\": c_tvec,\n",
+ " \"camera_matrix\": c_mtx,\n",
+ " \"distortion_coefficients\": c_dist\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"c-prime-af_03\",\n",
+ " \"rvec\": c_prime_rvec,\n",
+ " \"tvec\": c_prime_tvec,\n",
+ " \"camera_matrix\": c_mtx,\n",
+ " \"distortion_coefficients\": c_dist\n",
+ " }\n",
" ]\n",
")\n",
"display(\"params\", params)\n",
@@ -352,7 +329,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 47,
"metadata": {},
"outputs": [
{
@@ -361,14 +338,16 @@
"True"
]
},
- "execution_count": 9,
+ "execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cv2.imwrite(\"output/a_result_img.png\", a_result_img)\n",
- "cv2.imwrite(\"output/b_result_img.png\", b_result_img)"
+ "cv2.imwrite(\"output/b_result_img.png\", b_result_img)\n",
+ "cv2.imwrite(\"output/c_result_img.png\", c_result_img)\n",
+ "cv2.imwrite(\"output/c_prime_result_img.png\", c_prime_result_img)"
]
}
],
diff --git a/output/b-af_03.parquet b/output/b-af_03.parquet
deleted file mode 100644
index 4807c1f..0000000
--- a/output/b-af_03.parquet
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1ba58c40d4594ad0fe79e5365b10a4fac5f91c0851a7b4f07f18075aa66aa5c3
-size 57927
diff --git a/output/params.parquet b/output/params.parquet
index 3a900f1..db8e83c 100644
--- a/output/params.parquet
+++ b/output/params.parquet
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:09ff6b97fac9c1e99fb617032d7af878630fa7dd491bc452b94e353aeeaf2842
-size 7955
+oid sha256:ccd7afa8e7527afb54419a3a00a4c61d42827037e71c6811505398d569a475f9
+size 8255
diff --git a/pose/a.parquet b/pose/a.parquet
new file mode 100644
index 0000000..7bde762
--- /dev/null
+++ b/pose/a.parquet
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9bb05c507a4562bcc5221d0bb8c99c7c7f626b11a40076bf0d669682e3a7a35e
+size 1560075
diff --git a/pose/b.parquet b/pose/b.parquet
new file mode 100644
index 0000000..9fa0645
--- /dev/null
+++ b/pose/b.parquet
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:de75d374f57d0ce505a4d74bd6de94cabdc2b074d6a507312bb06f1d08163068
+size 1885737
diff --git a/run_capture.py b/run_capture.py
new file mode 100644
index 0000000..1d0ed40
--- /dev/null
+++ b/run_capture.py
@@ -0,0 +1,132 @@
+from datetime import datetime
+from os import PathLike
+from pathlib import Path
+import signal
+from subprocess import Popen, TimeoutExpired
+from typing import Any, Literal
+from loguru import logger
+import click
+import loguru
+
+# pacman -S python-loguru
+# pacman -S python-click
+
+Mode = Literal["preview", "save", "save_preview"]
+MODE_LIST: list[Mode] = ["preview", "save", "save_preview"]
+MULTICAST_ADDR = "224.0.0.123"
+
+
+class DumpCommand:
+ port: int
+ output_path: str
+
+ def __init__(self, port: int, output_path: PathLike | str):
+ self.port = port
+ self.output_path = str(output_path)
+
+ def save_and_decode_nv_pipeline(self):
+ # note that capabilties SHOULD NOT have spaces in between
+ # `gst-launch-1.0` could tolerate that, but not the API itself
+ return f"""gst-launch-1.0 -e udpsrc port={self.port} \
+ ! 'application/x-rtp,encoding-name=H265,payload=96' \
+ ! rtph265depay \
+ ! h265parse \
+ ! tee name=t \
+ t. ! queue ! nvh265dec ! videoconvert ! autovideosink \
+ t. ! queue ! mp4mux ! filesink location={self.output_path}
+ """
+
+ def save_and_decode_nv_pipeline_multicast(self):
+ return f"""gst-launch-1.0 -e udpsrc port={self.port} \
+ auto-multicast=true \
+ multicast-group={MULTICAST_ADDR} \
+ ! 'application/x-rtp,encoding-name=H265,payload=96' \
+ ! rtph265depay \
+ ! h265parse \
+ ! tee name=t \
+ t. ! queue ! vtdec_hw ! videoconvert ! autovideosink \
+ t. ! queue ! mp4mux ! filesink location={self.output_path}
+ """
+ # `vtdec_hw` for macos
+ # `nvh265dec` for nv
+
+ def save_pipeline(self):
+ return f"""gst-launch-1.0 -e udpsrc port={self.port} \
+ ! 'application/x-rtp, encoding-name=H265, payload=96' \
+ ! rtph265depay \
+ ! queue ! h265parse ! mp4mux ! filesink location={self.output_path}
+ """
+
+ def decode_cv_only(self):
+ return f"""gst-launch-1.0 -e udpsrc port={self.port} \
+ ! 'application/x-rtp,encoding-name=H265,payload=96' \
+ ! rtph265depay \
+ ! h265parse \
+ ! nvh265dec \
+ ! videoconvert \
+ ! autovideosink
+ """
+
+ def get_pipeline_from_mode(self, mode: Mode):
+ if mode == "save":
+ return self.save_pipeline()
+ elif mode == "save_preview":
+ return self.save_and_decode_nv_pipeline_multicast()
+ elif mode == "preview":
+ return self.decode_cv_only()
+ raise ValueError(f"Unknown mode: {mode}")
+
+
+def test_filename(
+ port: int,
+ output_dir: PathLike | str,
+ date: datetime,
+ prefix="video_",
+ suffix=".mp4",
+):
+ date_str = date.strftime("%Y-%m-%d_%H-%M-%S")
+ assert suffix.startswith("."), "suffix should start with a dot"
+ file_name = f"{prefix}{date_str}_{port}{suffix}"
+ return Path(output_dir) / file_name
+
+
+# nmap -sS --open -p 22 192.168.2.0/24
+
+
+@click.command()
+@click.option("-o", "--output", type=click.Path(exists=True), default="output")
+@click.option("-m", "--mode", type=click.Choice(MODE_LIST), default="save_preview")
+def main(output: str, mode: Mode):
+ ports = [5601, 5602, 5603, 5604, 5605, 5606]
+ output_dir = Path(output)
+ now = datetime.now()
+ commands = [
+ DumpCommand(port, test_filename(port, output_dir, now)) for port in ports
+ ]
+ ps: list[Popen] = []
+ run_flag: bool = True
+
+ def handle_sigint(signum: int, frame: Any):
+ nonlocal run_flag
+ run_flag = False
+ logger.info("Received SIGINT, stopping all processes")
+
+ for command in commands:
+ p = Popen(command.get_pipeline_from_mode(mode), shell=True)
+ ps.append(p)
+
+ signal.signal(signal.SIGINT, handle_sigint)
+ while run_flag:
+ pass
+
+ for p in ps:
+ p.send_signal(signal.SIGINT)
+ for p in ps:
+ try:
+ p.wait(3)
+ except TimeoutExpired:
+ logger.warning("Command `{}` timeout", p.args)
+
+
+if __name__ == "__main__":
+ main() # pylint: disable=no-value-for-parameter