Views
No views yet
pip install torch torchvision numpy opencv-python-headless einops tqdm matplotlib scipy scikit-learn omegaconf tomesd pandas tensorboard rich yapf addictopencv-python package.1import torch
2import cv2
3import os
4import matplotlib.pyplot as plt
5import numpy as np
6
7# Define the repository (replace with your actual repo path if different)
8repo = 'KieDani/UpliftingTableTennis'
9
10# 1. Download example images using the helper function defined in hubconf.py
11image_folder = torch.hub.load(repo, 'download_example_images', local_folder='example_images', trust_repo=True)
12
13# 2. Load the sequence of images (00.png to 34.png)
14images = [cv2.imread(os.path.join(image_folder, f'{i:02d}.png')) for i in range(35)]
15fps = 60.0 # The framerate is required for physics calculations
16
17print(f"Loaded {len(images)} images.")1# 1. Load the Full Pipeline
2# This downloads and loads all necessary weights automatically
3pipeline = torch.hub.load(repo, 'full_pipeline', trust_repo=True)
4
5# 2. Run Inference
6# The pipeline handles ball detection, table detection, filtering,
7# normalization, and 3D uplifting internally.
8print("Running full pipeline (this may take a moment)...")
9pred_spin, pred_pos_3d = pipeline.predict(images, fps)
10
11print(f"Predicted 3D positions shape: {pred_pos_3d.shape}")
12print(f"Predicted Spin Vector (local coords): {pred_spin}")1# Identify Spin Type
2# In our local coordinate system, the y-axis corresponds to the top-backspin axis.
3spin_magnitude = pred_spin[1] / (2 * np.pi) # Convert rad/s to Hz
4if spin_magnitude > 2:
5 spin_type = "Topspin"
6elif spin_magnitude < -2:
7 spin_type = "Backspin"
8else:
9 spin_type = "No significant spin"
10
11print(f"Predicted Spin Class: {spin_type}")
12print(f"Spin Magnitude: {spin_magnitude:.1f} Hz")
13
14# 2. Reproject 3D points to 2D for visualization
15# We need the camera matrices to project 3D world points -> 2D image pixels.
16# The pipeline can calibrate the camera using the detected table keypoints.
17
18# (Note: We use the detections from the first image for calibration here)
19table_det_model = torch.hub.load(repo, 'table_detection', model_name='segformerpp_b2', trust_repo=True)
20kps, _ = table_det_model.predict(images)
21# We filter/smooth these internally in the pipeline, but for visualization
22# let's just use the raw keypoints from the first frame to get matrices.
23Mint, Mext = pipeline.calibrate_camera(kps[0])
24
25reprojected_2d = pipeline.reproject(pred_pos_3d, Mint, Mext)1# Plot on a sample frame
2frame_idx = 15
3img_vis = images[frame_idx].copy()
4
5# Draw reprojected 3D points in Cyan
6for x, y in reprojected_2d:
7 cv2.circle(img_vis, (int(x), int(y)), 5, (255, 255, 0), -1)
8
9plt.figure(figsize=(14, 8))
10plt.title(f"3D Uplifted Trajectory Reprojected (Spin: {spin_type})")
11plt.imshow(cv2.cvtColor(img_vis, cv2.COLOR_BGR2RGB))
12plt.axis('off')
13plt.show()@inproceedings{kienzle2026uplifting,
title={Uplifting Table Tennis: A Robust, Real-World Application for 3D Trajectory and Spin Estimation},
author={Kienzle, Daniel and Ludwig, Katja and Lorenz, Julian and Satoh, {Shin'ichi} and Lienhart, Rainer},
booktitle={Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision (WACV)},
year={2026}
}