### Configure Dockerfile: Install Dependencies Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/refrence_algorithm_submission/README.md Install all Python dependencies listed in the requirements.txt file. Ensure all dependencies and their versions are accurately specified in requirements.txt. ```dockerfile RUN python -m pip install --user -rrequirements.txt ``` -------------------------------- ### JSON Example for Tooth Labels and Instances Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/README.md This JSON structure represents ground truth tooth labels and instances for a 3D scan. The 'labels' and 'instances' arrays correspond to vertices in the 3D model. Label '0' and instance '0' are for gingiva. Unique instance numbers indicate different teeth. ```python { "id_patient": "6X24ILNE", "jaw": "upper", "labels": [0, 0, 44, 33, 34, 0, 0, 45, 0, .. ,41, 0, 0, 37, 0, 34, 45, 0, 31, 36], "instances": [0, 0, 10, 2, 12, 0, 0, 9, 0, 0, .. , 10, 0, 0, 8, 0, 0, 9, 0, 1, 8, 13], } ``` -------------------------------- ### Example Output JSON Structure Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/refrence_algorithm_submission/README.md This JSON structure represents the expected output format for dental labels, including patient ID, jaw information, point labels in FDI format, and instance segmentation for each tooth. ```json { "id_patient": "", "jaw": "upper", #or "lower", extracted from input "labels": [0, 0, 44, 33, 34, 0, 0, 45, 0, .. ,41, 0, 0, 37, 0, 34, 45, 0, 31, 36], # label of each 3D point in FDI format (label 0 correspond to gingiva) "instances": [0, 0, 10, 2, 12, 0, 0, 9, 0, 0, .. , 10, 0, 0, 8, 0, 0, 9, 0, 1, 8, 13], # each 3D point with same instance correspond only to one tooth # all points with the same instance (correpond exactly to one tooth) should have the same label # preferably tooth instance is in [1,2, .. , number_of_tooth_detected] # by default 0 is attributed to gingiva instance } ``` -------------------------------- ### Load and Process Dataset Split Files (Python) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Shows how to read dataset split files (e.g., for training or testing) and construct file paths for scan data. Assumes the dataset has been downloaded and the `data_root` path is correctly set. ```python # Reading and using the dataset split files split_files = { "challenge_train_1": "dataset/3DTeethSeg_challenge_split/public-training-set-1.txt", "challenge_train_2": "dataset/3DTeethSeg_challenge_split/public-training-set-2.txt", "challenge_test": "dataset/3DTeethSeg_challenge_split/private-testing-set.txt", "teeth3ds_train_lower": "dataset/Teeth3DS_split/training_lower.txt", "teeth3ds_test_upper": "dataset/Teeth3DS_split/testing_upper.txt", } def load_split(filepath): with open(filepath) as f: return [line.strip() for line in f if line.strip()] train_ids = load_split("dataset/3DTeethSeg_challenge_split/public-training-set-1.txt") print("Training samples:", len(train_ids)) # Build full paths to .obj and .json files data_root = "/path/to/downloaded/dataset" for scan_id in train_ids[:3]: obj_path = f"{data_root}/{scan_id}.obj" json_path = f"{data_root}/{scan_id}.json" print(obj_path, json_path) ``` -------------------------------- ### Build Docker Image Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/evaluation/useful_cmd.txt Builds the Docker image using the provided Dockerfile. Use this to create the evaluation environment. ```bash docker build -f Dockerfile -t evaluation:0.1 . ``` -------------------------------- ### Docker Build, Test, and Export Workflow for Submission Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Scripts for building the Docker image, running local tests on a sample dataset, and exporting the results for Grand-Challenge submission. These scripts automate the Docker lifecycle. ```bash # ── 1. Build the Docker image ────────────────────────────────────────── cd refrence_algorithm_submission/ bash build.sh # Equivalent to: # docker build -f Dockerfile -t algorithm:latest . # ── 2. Local test (runs container on test/0EJBIPTC_lower.obj) ────────── bash test.sh ``` -------------------------------- ### Configure Dockerfile: Copy Files Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/refrence_algorithm_submission/README.md Copy necessary files into the Docker container, including model weights, requirements.txt, and any custom Python scripts. ```dockerfile COPY --chown=algorithm:algorithm requirements.txt /opt/algorithm/ COPY --chown=algorithm:algorithm model /opt/algorithm/model COPY --chown=algorithm:algorithm model.pth /opt/algorithm/checkpoints ``` -------------------------------- ### Configure Dockerfile: Base Image Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/refrence_algorithm_submission/README.md Specify the base Docker image for your algorithm. It's recommended to use official base images for your chosen deep learning library (e.g., PyTorch, TensorFlow). ```dockerfile FROM pytorch/pytorch:1.9.0-cuda11.1-cudnn8-runtime ``` -------------------------------- ### Run Evaluation Docker Container Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Build and run the evaluation Docker image locally. Mount a directory for predictions to generate metrics.json. ```bash cd ../evaluation/ docker build -f Dockerfile -t evaluation:0.1 . docker run --rm \ -v /path/to/predictions:/predicted \ evaluation:0.1 ``` -------------------------------- ### Test Docker Run Command Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/evaluation/useful_cmd.txt Runs the Docker container and mounts a volume for predictions. This command is used to test the evaluation process. ```bash docker run --rm -v /media/oussama/60d0458f-2f1f-4c73-bfe4-93757a0b94c5/home/oussama/workspace/SegLab_challenge_submission/out:/predicted evaluation:0.1 ``` -------------------------------- ### Load and Parse Ground Truth JSON for 3D Teeth Scans (Python) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Demonstrates how to load and parse the ground truth JSON file for a 3D teeth scan. This file contains per-vertex labels and instance IDs. Ensure the JSON file path is correct. ```python import json # Ground truth JSON structure for a single jaw scan with open("0EJBIPTC_lower.json", "r") as f: gt = json.load(f) # gt structure: # { # "id_patient": "0EJBIPTC", # "jaw": "lower", # "labels": [0, 0, 44, 33, 34, 0, 45, 41, 37, 34, 31, 36, ...], # FDI tooth labels per vertex # "instances": [0, 0, 10, 2, 12, 0, 9, 10, 8, 9, 1, 8, ...] # instance ID per vertex (0 = gingiva) # } print("Patient:", gt["id_patient"]) print("Jaw:", gt["jaw"]) print("Vertices:", len(gt["labels"])) import numpy as np labels = np.array(gt["labels"]) instances = np.array(gt["instances"]) # Count unique teeth (exclude gingiva = 0) unique_teeth = np.unique(instances[instances != 0]) print("Number of teeth detected:", len(unique_teeth)) # Get all vertices belonging to tooth instance #2 tooth2_vertex_mask = (instances == 2) toot h2_fdi_label = np.unique(labels[tooth2_vertex_mask]) print("FDI label for instance 2:", tooth2_fdi_label) ``` -------------------------------- ### Export Container as tar.gz Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Use this script to save the Docker image to a tar.gz archive for upload. ```bash bash export.sh ``` -------------------------------- ### Export Labeled 3D Scan with FDI Colors Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Utility to colorize a 3D mesh based on FDI tooth labels and export it as a .obj file for visual inspection. Uses a predefined palette mapping FDI labels to RGB colors. ```python import trimesh, json from colormap import hex2rgb # FDI color palette (subset shown) fdi_colors = { "11": "#ff0000", "21": "#0000ff", # upper central incisors "31": "#00ff00", "41": "#f0e2ff", # lower central incisors "0": "#000000" # gingiva = black } obj_path = "0EJBIPTC_lower.obj" json_path = "0EJBIPTC_lower.json" export_path = "./test/0EJBIPTC_lower_colored.obj" mesh = trimesh.load(obj_path, process=False) with open(json_path, "r") as fp: json_data = json.load(fp) # Apply per-vertex colors based on FDI label for i, lbl in enumerate(json_data["labels"]): if lbl != 0: # skip gingiva color = list(hex2rgb(fdi_colors[str(lbl)])) color.append(255) # add alpha mesh.visual.vertex_colors[i] = color mesh.export(export_path) print(f"Exported colorized mesh to {export_path}") ``` -------------------------------- ### ScanSegmentation Class for Algorithm Submission Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Implement the `ScanSegmentation` class to process 3D dental scans, run inference, and write predictions. Load your trained model in the `__init__` method and replace the dummy inference in the `predict` method with your actual model logic. The `process` method orchestrates the end-to-end pipeline. ```python import trimesh, json, os, glob, numpy as np class ScanSegmentation(): def __init__(self): # Load your trained model here # self.model = torch.load("checkpoints/model.pth") pass @staticmethod def load_input(input_dir): """Returns list of .obj file paths found in input_dir.""" inputs = glob.glob(f'{input_dir}/*.obj') assert len(inputs) == 1, f"Expected 1 .obj, found {len(inputs)}" return inputs @staticmethod def get_jaw(scan_path): """Extracts jaw type ('upper'/'lower') from filename or .obj header.""" try: _, jaw = os.path.basename(scan_path).split('.')[0].split('_') except: with open(scan_path, 'r') as f: jaw = f.readline()[2:-1] if jaw not in ["upper", "lower"]: return None return jaw def predict(self, inputs): """ Core inference: load mesh, run model, return per-vertex labels + instances. labels[i] = FDI tooth number for vertex i (0 = gingiva) instances[i] = instance ID for vertex i (0 = gingiva) """ scan_path = inputs[0] mesh = trimesh.load(scan_path, process=False) jaw = self.get_jaw(scan_path) nb_vertices = mesh.vertices.shape[0] # ---- Replace with real model inference ---- # labels, instances = self.model(mesh.vertices, jaw=jaw) labels = [43] * nb_vertices # dummy: all vertices labeled tooth #43 instances = [2] * nb_vertices # dummy: all vertices belong to instance 2 # ------------------------------------------- assert len(labels) == len(instances) == nb_vertices, \ "Output length must match number of vertices" return labels, instances, jaw @staticmethod def write_output(labels, instances, jaw): """Writes prediction to /output/dental-labels.json.""" import numpy as np class NpEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.integer): return int(obj) if isinstance(obj, np.floating): return float(obj) if isinstance(obj, np.ndarray): return obj.tolist() return super().default(obj) output = {"id_patient": "", "jaw": jaw, "labels": labels, "instances": instances} with open('/output/dental-labels.json', 'w') as fp: json.dump(output, fp, cls=NpEncoder) def process(self): """End-to-end pipeline: read → predict → write.""" inputs = self.load_input('/input') labels, instances, jaw = self.predict(inputs) self.write_output(labels=labels, instances=instances, jaw=jaw) if __name__ == "__main__": ScanSegmentation().process() ``` -------------------------------- ### BibTeX Citation for Teeth3DS Dataset Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/README.md Use this BibTeX entry to cite the Teeth3DS benchmark paper, which is related to the 3D teeth segmentation challenge. ```bibtex @article{ben2022teeth3ds, title={Teeth3DS: a benchmark for teeth segmentation and labeling from intra-oral 3D scans}, author={Ben-Hamadou, Achraf and Smaoui, Oussama and Chaabouni-Chouayakh, Houda and Rekik, Ahmed and Pujades, Sergi and Boyer, Edmond and Strippoli, Julien and Thollot, Aurélien and Setbon, Hugo and Trosset, Cyril and others}, journal={arXiv preprint arXiv:2210.06094}, year={2022} } ``` -------------------------------- ### Docker Save Image Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/evaluation/useful_cmd.txt Saves the Docker image to a tar archive. This is useful for transferring or backing up the image. ```bash docker save evaluation:0.1 > 3DTeethSeg_evaluationv0.1.tar ``` -------------------------------- ### Calculate Full Per-jaw Metrics (TLA, TSA, TIR) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt High-level function to compute TLA, TSA, and TIR for a jaw. It loads data, builds necessary structures, runs matching, and returns all three metrics. Requires ground truth and prediction dictionaries. ```python import json, numpy as np from evaluation import calculate_metrics # Load ground truth (must include "mesh_vertices" key added by evaluation pipeline) with open("0EJBIPTC_lower.json") as f: gt_dict = json.load(f) # Attach mesh vertices (evaluation pipeline does this via pickle of pre-processed data) import trimesh mesh = trimesh.load("0EJBIPTC_lower.obj", process=False) gt_dict["mesh_vertices"] = np.array(mesh.vertices) # Load algorithm prediction with open("/output/dental-labels.json") as f: pred_dict = json.load(f) jaw_TLA, jaw_TSA, jaw_TIR = calculate_metrics(gt_dict, pred_dict) import math print(f"Exp(-TLA): {math.exp(-jaw_TLA):.4f}") print(f"TSA: {jaw_TSA:.4f}") print(f"TIR: {jaw_TIR:.4f}") print(f"Score: {(math.exp(-jaw_TLA) + jaw_TSA + jaw_TIR) / 3:.4f}") # Score: mean of the three metrics, target ≥ 0.95 (top leaderboard) ``` -------------------------------- ### BibTeX Citation for 3DTeethSeg'22 Source: https://github.com/abenhamadou/3dteethseg22_challenge/blob/main/README.md Use this BibTeX entry to cite the 3DTeethSeg'22 challenge paper in your academic work. ```bibtex @article{ben20233dteethseg, title={3DTeethSeg'22: 3D Teeth Scan Segmentation and Labeling Challenge}, author={Achraf Ben-Hamadou and Oussama Smaoui and Ahmed Rekik and Sergi Pujades and Edmond Boyer and Hoyeon Lim and Minchang Kim and Minkyung Lee and Minyoung Chung and Yeong-Gil Shin and Mathieu Leclercq and Lucia Cevidanes and Juan Carlos Prieto and Shaojie Zhuang and Guangshun Wei and Zhiming Cui and Yuanfeng Zhou and Tudor Dascalu and Bulat Ibragimov and Tae-Hoon Yong and Hong-Gi Ahn and Wan Kim and Jae-Hwan Han and Byungsun Choi and Niels van Nistelrooij and Steven Kempers and Shankeeth Vinayahalingam and Julien Strippoli and Aurélien Thollot and Hugo Setbon and Cyril Trosset and Edouard Ladroit}, journal={arXiv preprint arXiv:2305.18277}, year={2023} } ``` -------------------------------- ### Calculate Jaw Teeth Identification Rate (TIR) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Computes the fraction of GT teeth whose matched prediction is both close enough (distance < 0.5 × tooth size) and has the correct FDI label. Returns a value in [0, 1]. ```python import numpy as np from evaluation import calculate_jaw_TIR, centroids_pred_to_gt_attribution gt_dict = { "1": {"label": 11, "centroid": np.array([0.0, 0.0, 0.0]), "tooth_size": np.array([2.0, 2.0, 2.0])}, "2": {"label": 21, "centroid": np.array([5.0, 0.0, 0.0]), "tooth_size": np.array([2.0, 2.0, 2.0])}, } pred_dict = { "a": {"label": 11, "centroid": np.array([0.3, 0.0, 0.0])}, # correct label, close "b": {"label": 22, "centroid": np.array([5.1, 0.0, 0.0])}, # wrong label (22 ≠ 21) } matching = centroids_pred_to_gt_attribution(gt_dict, pred_dict) tir = calculate_jaw_TIR(gt_dict, pred_dict, matching, threshold=0.5) print(f"TIR: {tir:.4f}") # 0.5000 (1 of 2 teeth correctly identified) ``` -------------------------------- ### Parse Grand-Challenge Prediction Manifest Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Use `load_predictions_json` to parse the `predictions.json` manifest generated by Grand-Challenge. This function maps scan names to their corresponding output file paths, enabling easy access to prediction results for evaluation. ```python from pathlib import Path from jsonloader import load_predictions_json # predictions.json is the manifest from Grand-Challenge # It contains a list of job entries with inputs/outputs per scan mapping = load_predictions_json(Path("predictions.json")) # Returns: {"0EJBIPTC_lower": "path/to/output/dental-labels.json", ...} print(mapping["0EJBIPTC_lower"]) # e.g. "abc123-uuid/output/dental-labels.json" # Use in evaluation loop: import json for scan_name, output_file in mapping.items(): with open(f"/input/{output_file}") as f: pred = json.load(f) print(scan_name, "→ jaw:", pred["jaw"], "vertices:", len(pred["labels"])) ``` -------------------------------- ### Calculate Jaw Teeth Localization Accuracy (TLA) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt Computes the mean normalized Euclidean distance between ground truth and predicted tooth centroids. Distance is normalized by GT tooth size, with a penalty for missing predictions. Lower TLA is better. ```python import numpy as np from evaluation import calculate_jaw_TLA, centroids_pred_to_gt_attribution # Build instance-label dicts with centroid and tooth_size gt_dict = { "1": {"label": 11, "centroid": np.array([0.0, 0.0, 0.0]), "tooth_size": np.array([1.0, 1.0, 1.0])}, "2": {"label": 21, "centroid": np.array([5.0, 0.0, 0.0]), "tooth_size": np.array([1.0, 1.0, 1.0])}, } pred_dict = { "1": {"label": 11, "centroid": np.array([0.1, 0.0, 0.0])}, "2": {"label": 21, "centroid": np.array([5.2, 0.0, 0.0])}, } matching = centroids_pred_to_gt_attribution(gt_dict, pred_dict) # matching: {"1": "1", "2": "2"} (Hungarian algorithm optimal assignment) tla = calculate_jaw_TLA(gt_dict, pred_dict, matching) print(f"TLA (lower is better): {tla:.4f}") # ~0.15 (small centroid offsets) print(f"Exp(-TLA) score: {np.exp(-tla):.4f}") # ~0.86 ``` -------------------------------- ### Calculate Teeth Segmentation Accuracy (TSA) Source: https://context7.com/abenhamadou/3dteethseg22_challenge/llms.txt The `calculate_jaw_TSA` function computes the per-jaw F1-score between predicted and ground truth instance masks. This metric evaluates how well the predicted point cloud covers the actual tooth surfaces, with 0 representing gingiva and non-zero values representing tooth instances. ```python import numpy as np from evaluation import calculate_jaw_TSA # gt_instances and pred_instances are per-vertex instance arrays # 0 = gingiva, non-zero = a tooth instance gt_instances = np.array([0, 0, 1, 1, 2, 2, 0, 3, 3]) pred_instances = np.array([0, 1, 1, 1, 2, 0, 0, 3, 3]) tsa = calculate_jaw_TSA(gt_instances.copy(), pred_instances.copy()) print(f"TSA (F1): {tsa:.4f}") # TSA (F1): 0.7778 (binary tooth/gingiva F1-score) # Perfect prediction: tsa_perfect = calculate_jaw_TSA( np.array([0, 1, 1, 2, 2]), np.array([0, 1, 1, 2, 2]) ) print(f"Perfect TSA: {tsa_perfect:.4f}") # 1.0000 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.