cute box
This commit is contained in:
@@ -1 +1,5 @@
|
|||||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||||
|
charuco_400x400_3x3_s130_m100_no_24.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
charuco_1189x841_10x7_s115_m90.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
charuco_400x400_3x3_s130_m100_no_16.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
charuco_400x400_3x3_s130_m100_no_20.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
*.jpg
|
*.jpg
|
||||||
*.jpeg
|
*.jpeg
|
||||||
*.pdf
|
|
||||||
*.png
|
*.png
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|||||||
@@ -6,3 +6,13 @@ See also [gen.sh](gen.sh) (put it in the same directory as the pattern generator
|
|||||||
|
|
||||||
- A0 size, 10x7, square 115mm, marker 90mm
|
- A0 size, 10x7, square 115mm, marker 90mm
|
||||||
- 400mm x 400mm ArUco board (4x4, 0-5 id)
|
- 400mm x 400mm ArUco board (4x4, 0-5 id)
|
||||||
|
|
||||||
|
## Diamond
|
||||||
|
|
||||||
|
9.7cm (97mm) square for marker
|
||||||
|
12.7cm (127mm) square for diamond
|
||||||
|
9mm border (in average)
|
||||||
|
|
||||||
|
- [16, 17, 18, 19]
|
||||||
|
- [20, 21, 22, 23]
|
||||||
|
- [24, 25, 26, 27]
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ class ArucoDictionary(Enum):
|
|||||||
Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL
|
Dict_ArUco_ORIGINAL = aruco.DICT_ARUCO_ORIGINAL
|
||||||
|
|
||||||
|
|
||||||
IMAGE_FOLDER = Path("dumped/b")
|
IMAGE_FOLDER = Path("dumped/usbcam")
|
||||||
OUTPUT_FOLDER = Path("output")
|
OUTPUT_FOLDER = Path("output")
|
||||||
DICTIONARY = ArucoDictionary.Dict_4X4_50
|
DICTIONARY = ArucoDictionary.Dict_4X4_50
|
||||||
CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "calibration.parquet"
|
CALIBRATION_PARQUET: Optional[Path] = OUTPUT_FOLDER / "usbcam_cal.parquet"
|
||||||
|
|
||||||
|
|
||||||
class CameraParams(TypedDict):
|
class CameraParams(TypedDict):
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
import cv2
|
||||||
|
from datetime import datetime
|
||||||
|
from loguru import logger
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_PATH = Path("dumped/cam")
|
||||||
|
|
||||||
|
def gen():
|
||||||
|
API = cv2.CAP_AVFOUNDATION
|
||||||
|
cap = cv2.VideoCapture(0, API)
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
logger.warning("Failed to grab frame")
|
||||||
|
break
|
||||||
|
yield frame
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for frame in gen():
|
||||||
|
cv2.imshow("frame", frame)
|
||||||
|
k = cv2.waitKey(1)
|
||||||
|
if k == ord("q"):
|
||||||
|
break
|
||||||
|
elif k == ord("s"):
|
||||||
|
now = datetime.now()
|
||||||
|
filename = BASE_PATH / f"capture_{now.strftime('%Y%m%d%H%M%S')}.jpg"
|
||||||
|
logger.warning(f"Saving to {filename}")
|
||||||
|
cv2.imwrite(str(filename), frame)
|
||||||
|
else:
|
||||||
|
...
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,83 @@
|
|||||||
|
import cv2
|
||||||
|
from cv2 import aruco
|
||||||
|
from datetime import datetime
|
||||||
|
from loguru import logger
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import cast, Final
|
||||||
|
import awkward as ak
|
||||||
|
from cv2.typing import MatLike
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
NDArray = np.ndarray
|
||||||
|
CALIBRATION_PARQUET = Path("output") / "usbcam_cal.parquet"
|
||||||
|
DICTIONARY: Final[int] = aruco.DICT_4X4_50
|
||||||
|
# 400mm
|
||||||
|
MARKER_LENGTH: Final[float] = 0.4
|
||||||
|
|
||||||
|
|
||||||
|
def gen():
|
||||||
|
API = cv2.CAP_AVFOUNDATION
|
||||||
|
cap = cv2.VideoCapture(0, API)
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
logger.warning("Failed to grab frame")
|
||||||
|
break
|
||||||
|
yield frame
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
aruco_dict = aruco.getPredefinedDictionary(DICTIONARY)
|
||||||
|
cal = ak.from_parquet(CALIBRATION_PARQUET)[0]
|
||||||
|
camera_matrix = cast(MatLike, ak.to_numpy(cal["camera_matrix"]))
|
||||||
|
distortion_coefficients = cast(MatLike, ak.to_numpy(cal["distortion_coefficients"]))
|
||||||
|
detector = aruco.ArucoDetector(
|
||||||
|
dictionary=aruco_dict, detectorParams=aruco.DetectorParameters()
|
||||||
|
)
|
||||||
|
|
||||||
|
for frame in gen():
|
||||||
|
grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||||
|
# pylint: disable-next=unpacking-non-sequence
|
||||||
|
markers, ids, rejected = detector.detectMarkers(grey)
|
||||||
|
# `markers` is [N, 1, 4, 2]
|
||||||
|
# `ids` is [N, 1]
|
||||||
|
if ids is not None:
|
||||||
|
markers = np.reshape(markers, (-1, 4, 2))
|
||||||
|
ids = np.reshape(ids, (-1, 1))
|
||||||
|
# logger.info("markers={}, ids={}", np.array(markers).shape, np.array(ids).shape)
|
||||||
|
for m, i in zip(markers, ids):
|
||||||
|
center = np.mean(m, axis=0).astype(int)
|
||||||
|
GREY = (128, 128, 128)
|
||||||
|
logger.info("id={}, center={}", i, center)
|
||||||
|
cv2.circle(frame, tuple(center), 5, GREY, -1)
|
||||||
|
cv2.putText(
|
||||||
|
frame,
|
||||||
|
str(i),
|
||||||
|
tuple(center),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
1,
|
||||||
|
GREY,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
# BGR
|
||||||
|
RED = (0, 0, 255)
|
||||||
|
GREEN = (0, 255, 0)
|
||||||
|
BLUE = (255, 0, 0)
|
||||||
|
YELLOW = (0, 255, 255)
|
||||||
|
color_map = [RED, GREEN, BLUE, YELLOW]
|
||||||
|
for color, corners in zip(color_map, m):
|
||||||
|
corners = corners.astype(int)
|
||||||
|
frame = cv2.circle(frame, corners, 5, color, -1)
|
||||||
|
cv2.imshow("frame", frame)
|
||||||
|
if (k := cv2.waitKey(1)) == ord("q"):
|
||||||
|
logger.info("Exiting")
|
||||||
|
break
|
||||||
|
elif k == ord("s"):
|
||||||
|
now = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
file_name = f"aruco_{now}.png"
|
||||||
|
logger.info("Saving to {}", file_name)
|
||||||
|
cv2.imwrite(file_name, frame)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
BIN
Binary file not shown.
+261
-51
File diff suppressed because one or more lines are too long
+39
@@ -0,0 +1,39 @@
|
|||||||
|
[cameras.a]
|
||||||
|
name = "three-four-right"
|
||||||
|
videos = [
|
||||||
|
"video-20241206-161501.mp4",
|
||||||
|
"video-20241206-162615.mp4",
|
||||||
|
"video-20241206-163043.mp4",
|
||||||
|
"video-20241206-164116.mp4",
|
||||||
|
"video-20241206-164541.mp4",
|
||||||
|
"video-20241206-164956.mp4",
|
||||||
|
]
|
||||||
|
[cameras.b]
|
||||||
|
name = "right"
|
||||||
|
videos = [
|
||||||
|
"video-20241206-162045.mp4",
|
||||||
|
"video-20241206-163050.mp4",
|
||||||
|
"video-20241206-164124.mp4",
|
||||||
|
"video-20241206-164536.mp4",
|
||||||
|
"video-20241206-164952.mp4",
|
||||||
|
"video-20241206-165800.mp4",
|
||||||
|
]
|
||||||
|
[cameras.c]
|
||||||
|
name = "bottom"
|
||||||
|
videos = [
|
||||||
|
"video-20241206-162055.mp4",
|
||||||
|
"video-20241206-163037.mp4",
|
||||||
|
"video-20241206-164107.mp4",
|
||||||
|
"video-20241206-164548.mp4",
|
||||||
|
"video-20241206-165818.mp4",
|
||||||
|
]
|
||||||
|
[cameras.d]
|
||||||
|
name = "hk"
|
||||||
|
videos = [
|
||||||
|
"Video_20241206163609771.avi",
|
||||||
|
"Video_20241206164041621.avi",
|
||||||
|
"Video_20241206164534460.avi",
|
||||||
|
"Video_20241206165004982.avi",
|
||||||
|
"Video_20241206165831395.avi",
|
||||||
|
]
|
||||||
|
# https://superuser.com/questions/650291/how-to-get-video-duration-in-seconds
|
||||||
Reference in New Issue
Block a user