Network change
@@ -17,7 +17,10 @@ name: approbotwebcam
|
|||||||
# Portainer: Stack → Web editor → dieses YAML → Deploy.
|
# Portainer: Stack → Web editor → dieses YAML → Deploy.
|
||||||
# APP_PATH = /absoluter/pfad/zum/appRobotWebcam
|
# APP_PATH = /absoluter/pfad/zum/appRobotWebcam
|
||||||
#
|
#
|
||||||
# Firewall: TCP 8444 (Viewer + Stream + API)
|
# Netz: hängt am externen Bridge-Netz "approbot_default" → vom HTTPS-Proxy im
|
||||||
|
# selben Netz erreichbar als http://AppRobotWebcam:8444 (oder webcam:8444).
|
||||||
|
# Firewall: TCP 8444 am Host nur für direkten LAN-Zugriff (ports:-Mapping). Läuft
|
||||||
|
# alles über den Proxy → ports:-Zeile raus, dann ist am Host nichts offen.
|
||||||
#
|
#
|
||||||
# Zugriff:
|
# Zugriff:
|
||||||
# Viewer: http://<host>:8444/
|
# Viewer: http://<host>:8444/
|
||||||
@@ -42,7 +45,14 @@ services:
|
|||||||
image: approbotwebcam:latest
|
image: approbotwebcam:latest
|
||||||
container_name: AppRobotWebcam
|
container_name: AppRobotWebcam
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
network_mode: host
|
# Hängt am externen Netz approbot_default (statt host-Mode) → der HTTPS-Proxy im
|
||||||
|
# selben Netz erreicht den Container per Name (http://AppRobotWebcam:8444).
|
||||||
|
networks:
|
||||||
|
- approbot_default
|
||||||
|
# 8444 am Host veröffentlicht → direkter LAN-Zugriff (http://<host>:8444) bleibt.
|
||||||
|
# Wenn ALLES über den Proxy läuft, diesen ports-Block entfernen → proxy-only.
|
||||||
|
ports:
|
||||||
|
- "8444:8444"
|
||||||
command: sh -c "npm install --omit=dev && node server.js"
|
command: sh -c "npm install --omit=dev && node server.js"
|
||||||
volumes:
|
volumes:
|
||||||
- ${APP_PATH:-.}:/usr/src/app
|
- ${APP_PATH:-.}:/usr/src/app
|
||||||
@@ -68,6 +78,14 @@ services:
|
|||||||
# - ON_DEMAND=true # Live nur bei Zuschauern (Default); 'false' = dauerhaft an
|
# - ON_DEMAND=true # Live nur bei Zuschauern (Default); 'false' = dauerhaft an
|
||||||
# - IDLE_GRACE_MS=15000 # Karenz nach letztem Zuschauer vor dem Stop
|
# - IDLE_GRACE_MS=15000 # Karenz nach letztem Zuschauer vor dem Stop
|
||||||
|
|
||||||
|
# ── Netzwerk ────────────────────────────────────────────────────────────────────
|
||||||
|
# Externes, bereits existierendes Bridge-Netz (vom Stack "approbot"). Wird hier nur
|
||||||
|
# referenziert, nicht erstellt. Prüfen: docker network inspect approbot_default
|
||||||
|
networks:
|
||||||
|
approbot_default:
|
||||||
|
external: true
|
||||||
|
name: approbot_default
|
||||||
|
|
||||||
# ── Hinweise ────────────────────────────────────────────────────────────────────
|
# ── Hinweise ────────────────────────────────────────────────────────────────────
|
||||||
# • Neue oder geänderte Kamera: cameras.json anpassen + Redeploy (kein Code-Änderung).
|
# • Neue oder geänderte Kamera: cameras.json anpassen + Redeploy (kein Code-Änderung).
|
||||||
# by-id-Namen ermitteln: ls -la /dev/v4l/by-id/
|
# by-id-Namen ermitteln: ls -la /dev/v4l/by-id/
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 272 KiB |
BIN
test/files/cam0/20260606_145135_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
test/files/cam0/20260606_145223_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_145249_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_145310_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
test/files/cam0/20260606_145331_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
test/files/cam0/20260606_145404_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_145415_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_145444_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
test/files/cam0/20260606_145505_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
test/files/cam0/20260606_145528_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam0/20260606_145542_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam0/20260606_153744_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam0/20260606_153808_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
test/files/cam0/20260606_153845_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
test/files/cam0/20260606_153855_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
test/files/cam0/20260606_153918_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam0/20260606_153928_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam0/20260606_153949_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
test/files/cam0/20260606_154021_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
test/files/cam0/20260606_154050_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
test/files/cam0/20260606_154108_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
test/files/cam0/20260606_154127_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
test/files/cam0/20260606_154150_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
test/files/cam0/20260606_154220_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
test/files/cam0/20260606_154237_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
test/files/cam0/20260606_154303_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
test/files/cam0/20260606_160853_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
test/files/cam0/20260606_160926_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
test/files/cam0/20260606_161001_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_161026_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
test/files/cam0/20260606_161052_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
test/files/cam0/20260606_161119_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_161144_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_161207_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_161237_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
test/files/cam0/20260606_161259_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam0/20260606_161325_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
test/files/cam0/20260606_161352_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
test/files/cam0/20260606_161422_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
test/files/cam0/20260606_161449_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam0/20260606_161525_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
test/files/cam0/20260606_161552_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
test/files/cam0/20260606_161627_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
test/files/cam0/20260606_161650_cam0_front.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
test/files/cam0/calibration.npz
Normal file
99
test/files/cam0/callibriate.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import glob
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create calibration .npz from checkerboard images
|
||||||
|
#
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
CHECKERBOARD = (10, 7) # inner corners
|
||||||
|
square_size = 25.0 / 1000.0 # 25 mm -> meters
|
||||||
|
|
||||||
|
# Prepare object points
|
||||||
|
objp = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
|
||||||
|
objp[:, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
|
||||||
|
objp *= square_size
|
||||||
|
|
||||||
|
objpoints = [] # 3D points
|
||||||
|
imgpoints = [] # 2D points
|
||||||
|
|
||||||
|
# Load images
|
||||||
|
images = glob.glob("*.jpg")
|
||||||
|
print("Found images:", len(images))
|
||||||
|
|
||||||
|
img_size = None
|
||||||
|
|
||||||
|
for fname in images:
|
||||||
|
img = cv2.imread(fname)
|
||||||
|
|
||||||
|
print(f"Processing {fname}...")
|
||||||
|
if img is None:
|
||||||
|
print(f"Warning: could not read {fname}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
# Save image size once
|
||||||
|
if img_size is None:
|
||||||
|
img_size = gray.shape[::-1]
|
||||||
|
|
||||||
|
print(f" Gray")
|
||||||
|
ret, corners = cv2.findChessboardCorners(
|
||||||
|
gray,
|
||||||
|
CHECKERBOARD,
|
||||||
|
flags=cv2.CALIB_CB_ADAPTIVE_THRESH +
|
||||||
|
cv2.CALIB_CB_NORMALIZE_IMAGE +
|
||||||
|
cv2.CALIB_CB_FAST_CHECK
|
||||||
|
)
|
||||||
|
print(" Corners found")
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
corners2 = cv2.cornerSubPix(
|
||||||
|
gray,
|
||||||
|
corners,
|
||||||
|
(11, 11),
|
||||||
|
(-1, -1),
|
||||||
|
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
|
||||||
|
)
|
||||||
|
|
||||||
|
objpoints.append(objp)
|
||||||
|
imgpoints.append(corners2)
|
||||||
|
|
||||||
|
print(f"✅ Corners found in {fname}")
|
||||||
|
else:
|
||||||
|
print(f"❌ No corners found in {fname}")
|
||||||
|
|
||||||
|
print(f"\nTotal valid images: {len(objpoints)} / {len(images)}" )
|
||||||
|
# Sanity checks
|
||||||
|
if img_size is None:
|
||||||
|
raise RuntimeError("No images were successfully loaded.")
|
||||||
|
|
||||||
|
if len(objpoints) == 0:
|
||||||
|
raise RuntimeError("No chessboard corners detected in any image. Calibration failed.")
|
||||||
|
|
||||||
|
print("\n=== Sanity Checks Passed ===")
|
||||||
|
# Calibration
|
||||||
|
ret, K, D, rvecs, tvecs = cv2.calibrateCamera(
|
||||||
|
objpoints,
|
||||||
|
imgpoints,
|
||||||
|
img_size,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
print("\n=== Calibration Results ===")
|
||||||
|
print("RMS reprojection error:", ret)
|
||||||
|
print("Camera matrix:\n", K)
|
||||||
|
print("Distortion coefficients:\n", D)
|
||||||
|
|
||||||
|
# Save calibration
|
||||||
|
np.savez(
|
||||||
|
"calibration.npz",
|
||||||
|
camera_matrix=K,
|
||||||
|
dist_coeffs=D
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\n✅ Calibration saved to calibration_XPro2_16mm.npz")
|
||||||
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
BIN
test/files/cam1/20260606_145135_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
test/files/cam1/20260606_145404_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
test/files/cam1/20260606_145528_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam1/20260606_145605_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
test/files/cam1/20260606_153744_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
test/files/cam1/20260606_153918_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
test/files/cam1/20260606_153949_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
test/files/cam1/20260606_154050_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam1/20260606_154127_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
test/files/cam1/20260606_154220_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
test/files/cam1/20260606_154303_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/files/cam1/20260606_160853_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
test/files/cam1/20260606_161001_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
test/files/cam1/20260606_161052_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam1/20260606_161144_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam1/20260606_161237_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
test/files/cam1/20260606_161325_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
test/files/cam1/20260606_161422_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
test/files/cam1/20260606_161525_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
test/files/cam1/20260606_161627_cam1_left.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
test/files/cam1/calibration.npz
Normal file
99
test/files/cam1/callibriate.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import glob
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create calibration .npz from checkerboard images
|
||||||
|
#
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
CHECKERBOARD = (10, 7) # inner corners
|
||||||
|
square_size = 25.0 / 1000.0 # 25 mm -> meters
|
||||||
|
|
||||||
|
# Prepare object points
|
||||||
|
objp = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
|
||||||
|
objp[:, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
|
||||||
|
objp *= square_size
|
||||||
|
|
||||||
|
objpoints = [] # 3D points
|
||||||
|
imgpoints = [] # 2D points
|
||||||
|
|
||||||
|
# Load images
|
||||||
|
images = glob.glob("*.jpg")
|
||||||
|
print("Found images:", len(images))
|
||||||
|
|
||||||
|
img_size = None
|
||||||
|
|
||||||
|
for fname in images:
|
||||||
|
img = cv2.imread(fname)
|
||||||
|
|
||||||
|
print(f"Processing {fname}...")
|
||||||
|
if img is None:
|
||||||
|
print(f"Warning: could not read {fname}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
# Save image size once
|
||||||
|
if img_size is None:
|
||||||
|
img_size = gray.shape[::-1]
|
||||||
|
|
||||||
|
print(f" Gray")
|
||||||
|
ret, corners = cv2.findChessboardCorners(
|
||||||
|
gray,
|
||||||
|
CHECKERBOARD,
|
||||||
|
flags=cv2.CALIB_CB_ADAPTIVE_THRESH +
|
||||||
|
cv2.CALIB_CB_NORMALIZE_IMAGE +
|
||||||
|
cv2.CALIB_CB_FAST_CHECK
|
||||||
|
)
|
||||||
|
print(" Corners found")
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
corners2 = cv2.cornerSubPix(
|
||||||
|
gray,
|
||||||
|
corners,
|
||||||
|
(11, 11),
|
||||||
|
(-1, -1),
|
||||||
|
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
|
||||||
|
)
|
||||||
|
|
||||||
|
objpoints.append(objp)
|
||||||
|
imgpoints.append(corners2)
|
||||||
|
|
||||||
|
print(f"✅ Corners found in {fname}")
|
||||||
|
else:
|
||||||
|
print(f"❌ No corners found in {fname}")
|
||||||
|
|
||||||
|
print(f"\nTotal valid images: {len(objpoints)} / {len(images)}" )
|
||||||
|
# Sanity checks
|
||||||
|
if img_size is None:
|
||||||
|
raise RuntimeError("No images were successfully loaded.")
|
||||||
|
|
||||||
|
if len(objpoints) == 0:
|
||||||
|
raise RuntimeError("No chessboard corners detected in any image. Calibration failed.")
|
||||||
|
|
||||||
|
print("\n=== Sanity Checks Passed ===")
|
||||||
|
# Calibration
|
||||||
|
ret, K, D, rvecs, tvecs = cv2.calibrateCamera(
|
||||||
|
objpoints,
|
||||||
|
imgpoints,
|
||||||
|
img_size,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
print("\n=== Calibration Results ===")
|
||||||
|
print("RMS reprojection error:", ret)
|
||||||
|
print("Camera matrix:\n", K)
|
||||||
|
print("Distortion coefficients:\n", D)
|
||||||
|
|
||||||
|
# Save calibration
|
||||||
|
np.savez(
|
||||||
|
"calibration.npz",
|
||||||
|
camera_matrix=K,
|
||||||
|
dist_coeffs=D
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\n✅ Calibration saved to calibration_XPro2_16mm.npz")
|
||||||
BIN
test/files/cam2/20260606_145014_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 296 KiB |
BIN
test/files/cam2/20260606_145223_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
test/files/cam2/20260606_145249_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
test/files/cam2/20260606_145310_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
test/files/cam2/20260606_145331_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 290 KiB |
BIN
test/files/cam2/20260606_145404_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 294 KiB |
BIN
test/files/cam2/20260606_145415_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 294 KiB |
BIN
test/files/cam2/20260606_145444_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
test/files/cam2/20260606_145528_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
test/files/cam2/20260606_145542_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 290 KiB |
BIN
test/files/cam2/20260606_145605_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
test/files/cam2/20260606_153702_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
test/files/cam2/20260606_153744_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 287 KiB |
BIN
test/files/cam2/20260606_153808_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
test/files/cam2/20260606_153845_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 299 KiB |
BIN
test/files/cam2/20260606_153855_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 299 KiB |
BIN
test/files/cam2/20260606_153918_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 305 KiB |
BIN
test/files/cam2/20260606_153928_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
test/files/cam2/20260606_153949_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
test/files/cam2/20260606_154021_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
test/files/cam2/20260606_154050_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
test/files/cam2/20260606_154108_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 303 KiB |
BIN
test/files/cam2/20260606_154127_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 305 KiB |
BIN
test/files/cam2/20260606_160853_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
test/files/cam2/20260606_160926_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
test/files/cam2/20260606_161001_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
test/files/cam2/20260606_161052_cam2_right.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |