Views
No views yet
TableDetector. We will demonstrate how to detect keypoints, filter them using an auxiliary model, and finally use them to calibrate the camera (obtaining intrinsic and extrinsic matrices).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
5
6# Define the repository (replace with your actual repo path if different)
7repo = 'KieDani/UpliftingTableTennis'
8
9# 1. Download example images using the helper function defined in hubconf.py
10image_folder = torch.hub.load(repo, 'download_example_images', local_folder='example_images', trust_repo=True)
11
12# 2. Load the sequence of images (00.png to 34.png)
13images = [cv2.imread(os.path.join(image_folder, f'{i:02d}.png')) for i in range(35)]
14
15print(f"Loaded {len(images)} images.")1# 1. Load the primary Table Detection model
2# Available models: 'segformerpp_b2', 'segformerpp_b0', 'hrnet'
3table_model = torch.hub.load(repo, 'table_detection', model_name='segformerpp_b2', trust_repo=True)
4
5# 2. Run Inference
6# The predict function takes a list of single images
7print("Running inference with SegFormer++...")
8keypoints_main, heatmaps = table_model.predict(images)
9
10# keypoints_main is an array of shape (N, 13, 3) -> [x, y, visibility]
11# visibility: 1 = visible, 0 = invisible
12print(f"Detected keypoints for {len(keypoints_main)} frames.")1# Visualize on the first frame
2frame_idx = 0
3img_vis = images[frame_idx].copy()
4
5# Iterate over the 13 keypoints
6for i, (x, y, v) in enumerate(keypoints_main[frame_idx]):
7 if v == table_model.KEYPOINT_VISIBLE:
8 # Draw green circle
9 cv2.circle(img_vis, (int(x), int(y)), 8, (0, 255, 0), -1)
10 # Draw keypoint index
11 cv2.putText(img_vis, str(i+1), (int(x)+5, int(y)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
12
13plt.figure(figsize=(12, 8))
14plt.title("Detected Table Keypoints (Single Model)")
15plt.imshow(cv2.cvtColor(img_vis, cv2.COLOR_BGR2RGB))
16plt.axis('off')
17plt.show()1# 1. Load the auxiliary model
2aux_model = torch.hub.load(repo, 'table_detection', model_name='hrnet', trust_repo=True)
3
4# 2. Run Inference with the auxiliary model
5print("Running inference with HRNet (Auxiliary)...")
6keypoints_aux, _ = aux_model.predict(images)
7
8# 3. Filter the trajectory
9# This combines predictions from both models to create a stable result
10filtered_keypoints = table_model.filter_trajectory(keypoints_main, keypoints_aux)
11
12print(f"Shape of filtered keypoints: {filtered_keypoints.shape}")
13# The result is a single set of stable keypoints (13, 3) representing the table state1# Visualize Filtered Keypoints
2# We plot the single set of stable keypoints on the first frame
3if frame_idx < len(images):
4 img_vis_filtered = images[frame_idx].copy()
5 for i, (x, y, v) in enumerate(filtered_keypoints):
6 if v == table_model.KEYPOINT_VISIBLE:
7 # Plot in blue to distinguish from raw detections
8 cv2.circle(img_vis_filtered, (int(x), int(y)), 8, (255, 0, 0), -1)
9 cv2.putText(img_vis_filtered, str(i+1), (int(x)+5, int(y)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
10
11 plt.figure(figsize=(12, 8))
12 plt.title("Filtered Table Keypoints (Stable)")
13 plt.imshow(cv2.cvtColor(img_vis_filtered, cv2.COLOR_BGR2RGB))
14 plt.axis('off')
15 print("Displaying filtered keypoints plot...")
16 plt.show()1# Calculate Camera Matrices
2Mint, Mext = table_model.calibrate_camera(filtered_keypoints)
3
4print("\n--- Camera Calibration Results ---")
5print("Intrinsic Matrix (K):")
6print(Mint)
7print("\nExtrinsic Matrix (RT):")
8print(Mext)@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}
}
@article{kienzlemipr2024,
author = {Daniel Kienzle and Marco Kantonis and Robin Schön and Rainer Lienhart},
title = {Segformer++: Efficient Token-Merging Strategies for High-Resolution Semantic Segmentation},
journal = {Proceedings of the 7th International Conference on Multimedia Information Processing and Retrieval (MIPR)},
year = {2024},
}