//  [python]
def matching_v3(tracklets: Dict[str, Tracklet], min_cluster, scene_camera):
    """
    Matching tracklets using DBSCAN
    """
    TRACKLET_LENGTH, Method, k1 = get_param(scene_camera)
    print(TRACKLET_LENGTH, Method, k1)
    label_match = {}

    track_uuid = []
    features = []

    pending_tracklets = {}
    for uuid in tracklets:
        if len(tracklets[uuid]) < TRACKLET_LENGTH:
            pending_tracklets[uuid] = tracklets[uuid]
            continue
        feat = torch.stack(tracklets[uuid])
        feat = torch.mean(feat, 0)
        features.append(feat.cpu().detach().numpy())
        track_uuid.append(uuid)
    features = np.asarray(features)

    if Method == "GMM":
        gm = GaussianMixture(
            n_components=min_cluster,
            covariance_type="full",
            max_iter=100000,
            random_state=0,
        ).fit(features)
        labels = gm.predict(features)

    elif Method == "Agglomerative":
        ag = AgglomerativeClustering(
            n_clusters=min_cluster, affinity="euclidean", linkage="average"
        ).fit(features)
        labels = ag.labels_

    label_match = {}
    for i in range(len(track_uuid)):
        label_match[track_uuid[i]] = int(labels[i])

    if len(pending_tracklets) == 0:
        debug_result = {}
        for uuid in label_match:
            if label_match[uuid] not in debug_result:
                debug_result[label_match[uuid]] = []
            debug_result[label_match[uuid]].append(int(uuid))
        with open(
            f"outputs/matching_tracklet/{scene_camera}_debug_result.json", "w"
        ) as f:
            json.dump(debug_result, f)
        return label_match, tracklets

    print("Handle pending tracklets")
    cluster_features = merge_label(label_match, tracklets)

    query_features_list = []
    query_tracks_id = []
    for uuid in pending_tracklets:
        feat = torch.stack(tracklets[uuid])
        feat = torch.mean(feat, 0)
        query_features_list.append(feat.cpu().detach().numpy())
        query_tracks_id.append(uuid)

    gallery_features_list = []
    gallery_tracks_id = []

    for uuid in cluster_features:
        gallery_features_list.append(cluster_features[uuid])
        gallery_tracks_id.append(uuid)

    query_features_list = np.asarray(query_features_list)
    gallery_features_list = np.asarray(gallery_features_list)
    query_features_list = torch.from_numpy(query_features_list).cuda()
    gallery_features_list = torch.from_numpy(gallery_features_list).cuda()

    distmat = re_ranking(
        query_features_list, gallery_features_list, k1=k1, k2=6, lambda_value=0.3
    )
    for i in range(len(query_tracks_id)):
        query_track_id = query_tracks_id[i]
        dist = distmat[i]
        # min_dist = np.min(dist)
        min_index = np.argmin(dist)
        gallery_track_id = gallery_tracks_id[min_index]
        label_match[query_track_id] = int(gallery_track_id)

    # Visualiing debug the result
    debug_result = {}
    for uuid in label_match:
        if label_match[uuid] not in debug_result:
            debug_result[label_match[uuid]] = []
        debug_result[label_match[uuid]].append(int(uuid))

    print(
        "Saving relabel debug at",
        f"outputs/matching_tracklet/{scene_camera}_debug_result.json",
    )
    with open(f"outputs/matching_tracklet/{scene_camera}_debug_result.json", "w") as f:
        json.dump(debug_result, f)

    return label_match, tracklets