{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91249,"databundleVersionId":11294684,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":11150055,"sourceType":"datasetVersion","datasetId":6956339},{"sourceId":219146636,"sourceType":"kernelVersion"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import cv2\nimport skimage\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom skimage.feature import hog\nfrom skimage.feature import daisy\nfrom tqdm import tqdm\nimport copy\nfrom skimage import segmentation, color, filters\nfrom skimage.segmentation import slic,  mark_boundaries\nfrom skimage.measure import regionprops\nfrom skimage import img_as_float\nimport pydot\nimport networkx as nx\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.cluster import DBSCAN\n#import hdbscan","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.690844Z","iopub.execute_input":"2025-04-16T23:05:18.691178Z","iopub.status.idle":"2025-04-16T23:05:18.696945Z","shell.execute_reply.started":"2025-04-16T23:05:18.691152Z","shell.execute_reply":"2025-04-16T23:05:18.695928Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CFG:\n    img_size = (640, 640)\n    label_thr = 30\n    \n    #freak parameter\n    freak_thr = 40\n    max_kps = 1000\n    grid_size = 2\n    \n    #daisy parameter\n    patch_size = 64\n    step = 8\n    radius = 16","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.700156Z","iopub.execute_input":"2025-04-16T23:05:18.700448Z","iopub.status.idle":"2025-04-16T23:05:18.715464Z","shell.execute_reply.started":"2025-04-16T23:05:18.700422Z","shell.execute_reply":"2025-04-16T23:05:18.714532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calibrate_target(im, loc, size=(640, 640)):\n    H, W, C = im.shape\n    loc[1] = (loc[1]/H) * size[0]\n    loc[2] = (loc[2]/H) * size[1]\n    return loc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.716994Z","iopub.execute_input":"2025-04-16T23:05:18.717407Z","iopub.status.idle":"2025-04-16T23:05:18.730781Z","shell.execute_reply.started":"2025-04-16T23:05:18.717375Z","shell.execute_reply":"2025-04-16T23:05:18.729591Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def select_dense_keypoints(keypoints, max_keypoints=500, grid_size=8):\n    \"\"\"\n    Selects a dense set of keypoints while preventing excessive clustering.\n    Uses a soft clustering approach with grid-based binning.\n    \"\"\"\n    # Sort by response (strongest first)\n    keypoints = sorted(keypoints, key=lambda kp: kp.response, reverse=True)\n    \n    if len(keypoints) <= max_keypoints:\n        return keypoints  # If already within limit, return as is\n\n    # Image size (assume square)\n    img_size = 640  # Adjust if needed\n    cell_size = img_size // grid_size  # Grid divisions\n\n    # Organize keypoints into a grid\n    keypoint_grid = {}\n    \n    for kp in keypoints:\n        cell_x = int(kp.pt[0] // cell_size)\n        cell_y = int(kp.pt[1] // cell_size)\n        cell = (cell_x, cell_y)\n\n        if cell not in keypoint_grid:\n            keypoint_grid[cell] = []\n        keypoint_grid[cell].append(kp)\n\n    # Select a dense but controlled number of keypoints from each grid cell\n    selected_keypoints = []\n    per_cell_limit = max_keypoints // (grid_size * grid_size)  # Even distribution\n\n    for cell, kps in keypoint_grid.items():\n        # Keep the strongest ones from each grid cell\n        selected_keypoints.extend(kps[:per_cell_limit])\n\n    return selected_keypoints[:max_keypoints]  # Ensure total does not exceed max limit","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.732463Z","iopub.execute_input":"2025-04-16T23:05:18.732896Z","iopub.status.idle":"2025-04-16T23:05:18.747326Z","shell.execute_reply.started":"2025-04-16T23:05:18.732856Z","shell.execute_reply":"2025-04-16T23:05:18.746119Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_daisy_at_keypoints(image, keypoints, patch_size=64, step=4, radius=16):\n    '''\n    patch_size: expand a window through a point \n    step: Computes DAISY descriptors at every 4 pixels\n    '''\n    descriptors = []\n    keypoints_valid = []\n\n    for (y, x) in tqdm(keypoints):\n        y = int(y)\n        x = int(x)\n        half_size = patch_size // 2\n\n        # Ensure keypoint is within image boundaries\n        if x - half_size < 0 or y - half_size < 0 or x + half_size >= image.shape[1] or y + half_size >= image.shape[0]:\n            continue  # Skip keypoints too close to the edge\n\n        # Extract patch around keypoint\n        patch = image[y - half_size:y + half_size, x - half_size:x + half_size]\n\n        # Compute DAISY descriptor for the patch\n        daisy_desc = daisy(\n            patch[..., 0], step=step, radius=radius, rings=2, histograms=6, orientations=8)\n\n        # Flatten descriptor (single feature vector per keypoint)\n        descriptors.append(daisy_desc)\n        keypoints_valid.append((y, x))\n\n    descriptors = np.stack(descriptors, axis=0)\n    keypoints_valid = np.array(keypoints_valid)\n    return descriptors, keypoints_valid","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.748662Z","iopub.execute_input":"2025-04-16T23:05:18.748974Z","iopub.status.idle":"2025-04-16T23:05:18.763169Z","shell.execute_reply.started":"2025-04-16T23:05:18.748950Z","shell.execute_reply":"2025-04-16T23:05:18.761946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_dist(p1, p2):\n    p1 = np.array(p1)\n    p2 = np.array(p2)\n    return np.linalg.norm(p1-p2)\n\ndef determine_label(p1, p2, thr = 10):\n    #1000 A˚=100nm=10 pixels\n    dist = compute_dist(p1, p2)\n    return (dist<thr).astype('int32')\n\n\ndef labeling(loc, kp, thr=10, use_pt=True):\n    loc = loc[1:]\n    labels = []\n    for kp_ in kp:\n        if use_pt:\n            label = determine_label(kp_.pt, loc, thr)\n        else:\n            label = determine_label(kp_, loc, thr)\n        labels.append(label)\n    labels = np.array(labels)\n    return labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.764883Z","iopub.execute_input":"2025-04-16T23:05:18.765268Z","iopub.status.idle":"2025-04-16T23:05:18.784854Z","shell.execute_reply.started":"2025-04-16T23:05:18.765232Z","shell.execute_reply":"2025-04-16T23:05:18.783804Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a graph from superpixel regions for graph cuts refinement\ndef graph_cut_refinement(image, segments):\n    # Number of unique segments (superpixels)\n    num_segments = np.max(segments) + 1\n    \n    # Create a graph (networkx)\n    G = nx.Graph()\n    \n    # Add nodes: each superpixel is a node\n    for i in range(num_segments):\n        region_pixels = np.where(segments == i)\n        avg_color = np.mean(image[region_pixels], axis=0)\n        G.add_node(i, color=avg_color)  # Add average color as a feature\n\n    # Add edges: between neighboring superpixels\n    for i in range(num_segments):\n        region_pixels = np.where(segments == i)\n        neighbors = get_neighbors(segments, i)\n        \n        for neighbor in neighbors:\n            # Add edge between superpixel i and its neighbor\n            G.add_edge(i, neighbor, weight=calculate_edge_weight(image, i, neighbor))\n    \n    # Apply graph cuts or CRF refinement (simplified here, requires advanced technique)\n    refined_image = np.zeros_like(image, dtype=np.uint8)\n    for i in range(num_segments):\n        region_pixels = np.where(segments == i)\n        refined_image[region_pixels] = G.nodes[i]['color']\n\n    return refined_image\n\n# Function to get neighbors of a superpixel\ndef get_neighbors(segments, superpixel):\n    neighbors = set()\n    # Search 4-connected neighbors\n    # Here, a more advanced method would be needed to find real neighbors\n    return neighbors\n\n# Calculate edge weight between superpixels based on color difference\ndef calculate_edge_weight(image, superpixel1, superpixel2):\n    color1 = np.mean(image[np.where(segments == superpixel1)], axis=0)\n    color2 = np.mean(image[np.where(segments == superpixel2)], axis=0)\n    return np.linalg.norm(color1 - color2)  # Euclidean distance in color space\n\n\ndef increase_contrast(image):\n    image = image.astype('float32')\n    #image[image>200] *=10\n    image[image<64] *=0\n    return image.astype('uint8')\n\ndef GraphCutsCRF(im, n_segments=100, compactness=10, sigma=1):\n    im = increase_contrast(im)\n    im = cv2.GaussianBlur(im[...,0], (7, 7), 5)[..., None]\n    image = np.concatenate([im]*3, axis=-1)\n    segments = slic(image, n_segments=100, compactness=compactness, sigma=sigma)\n    plt.imshow(mark_boundaries(im.repeat(3, axis=-1), segments))\n    plt.show()\n    refined_image_graph_cut = graph_cut_refinement(image, segments)[..., :1]\n    plt.imshow(refined_image_graph_cut)\n    plt.show()\n    output = []\n    for i, region_idx in enumerate((np.unique(refined_image_graph_cut))):\n        output.append((refined_image_graph_cut==region_idx).astype('float32'))\n    output = np.concatenate(output, axis=-1)\n    return output.argmax(axis=-1, keepdims=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.882321Z","iopub.execute_input":"2025-04-16T23:05:18.882782Z","iopub.status.idle":"2025-04-16T23:05:18.894626Z","shell.execute_reply.started":"2025-04-16T23:05:18.882746Z","shell.execute_reply":"2025-04-16T23:05:18.893385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_patch(image, keypoints, patch_size=128):\n    H, W = image.shape[:2]  # Get image dimensions\n    half_size = patch_size // 2\n    patches = []\n    image_with_boxes = image.copy()\n    image = image.astype('float32')/255.\n    for x, y in keypoints:\n        x, y = int(x), int(y)\n        # Adjust x to keep patch inside image\n        x_start = max(0, x - half_size)\n        x_end = min(W, x + half_size)\n        if x_end - x_start < patch_size:\n            x_start = max(0, x_end - patch_size)\n            x_end = x_start + patch_size\n\n        # Adjust y to keep patch inside image\n        y_start = max(0, y - half_size)\n        y_end = min(H, y + half_size)\n        if y_end - y_start < patch_size:\n            y_start = max(0, y_end - patch_size)\n            y_end = y_start + patch_size\n        \n        # Extract the patch\n        patch = image[y_start:y_end, x_start:x_end, 0]\n        #patch = cv2.resize(patch, (half_size, half_size))\n        patches.append(patch)\n        cv2.rectangle(image_with_boxes, (x_start, y_start), (x_end, y_end), (0, 255, 0), 1)\n    patches = np.stack(patches, axis=0)\n    plt.imshow(image_with_boxes)\n    plt.show()\n    return patches","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.896072Z","iopub.execute_input":"2025-04-16T23:05:18.896449Z","iopub.status.idle":"2025-04-16T23:05:18.913604Z","shell.execute_reply.started":"2025-04-16T23:05:18.896406Z","shell.execute_reply":"2025-04-16T23:05:18.912141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def edge_keypoint(image):\n    edges = cv2.Canny(image, 300, 300)\n    fast = cv2.FastFeatureDetector_create()\n    keypoints = fast.detect(image, None)\n    edge_points = np.array([kp.pt for kp in keypoints if edges[int(kp.pt[1]), int(kp.pt[0])] > 0])\n    return edge_points\n\n\ndef point_feature_extractor(path, loc=None):\n    im = cv2.imread(path)\n    im = np.transpose(im, (1, 0, 2))\n\n    if loc is not None:\n        #calibrate location\n        loc =  calibrate_target(im, loc, CFG.img_size)\n        \n    #resize\n    im = cv2.resize(im, CFG.img_size)\n    im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)[..., None]\n\n    #mask generaton\n    mask =  GraphCutsCRF(im, 5, 10, 1)\n\n    #keypoint detection\n    fast = cv2.FastFeatureDetector_create(threshold=CFG.freak_thr, nonmaxSuppression=True)\n    kp = fast.detect(im, None)\n    kp = select_dense_keypoints(kp, max_keypoints=CFG.max_kps, grid_size=CFG.grid_size)\n    freak = cv2.xfeatures2d.FREAK_create()\n    kp, descriptors = freak.compute(im, kp)\n    kp = np.array([kp_.pt for kp_ in kp])\n    kp_filtered = filter_keypoint(kp, mask)\n\n\n    #extract patches\n    patches = extract_patch(im, kp_filtered, CFG.patch_size)\n\n    #labeling\n    if loc is not None:\n        #labeling\n        labels = labeling(loc, kp_filtered, CFG.label_thr, False)\n        return patches, kp_filtered, labels\n    return patches, kp_filtered","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.915723Z","iopub.execute_input":"2025-04-16T23:05:18.916045Z","iopub.status.idle":"2025-04-16T23:05:18.931199Z","shell.execute_reply.started":"2025-04-16T23:05:18.916002Z","shell.execute_reply":"2025-04-16T23:05:18.929752Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def determine_round(kp):\n    pipeline = Pipeline([\n        ('normalize', StandardScaler()),\n        ('dbscan', hdbscan.HDBSCAN(min_cluster_size=70, gen_min_span_tree=True))\n    ])\n    pipeline.fit(kp)\n    labels = pipeline[1].labels_\n    return 1 in np.unique(labels).tolist(), labels\n\n\ndef filter_keypoint(kp, mask):\n    plt.imshow(mask)\n    if np.unique(mask).shape[0]==1:\n        return kp\n    valid_kp = []\n    # round_flag, cluster_labels = determine_round(kp)\n    # n_rounds = 1 if round_flag else 2\n    # print(f'rounds: {n_rounds}')\n    for i in range(80):\n        mask_i = mask==i\n        for j, kp_ in enumerate(kp):\n            #is_outlier = cluster_labels[j]\n            x, y = int(kp_[0]), int(kp_[1])\n            is_valid = mask_i[y, x, 0]\n            if is_valid:\n                valid_kp.append(kp_)\n    return np.array(valid_kp)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.933203Z","iopub.execute_input":"2025-04-16T23:05:18.933638Z","iopub.status.idle":"2025-04-16T23:05:18.954275Z","shell.execute_reply.started":"2025-04-16T23:05:18.933586Z","shell.execute_reply":"2025-04-16T23:05:18.953199Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_01a877_z0148_y0638_x0286.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_00e463_z0218_y0379_x0144.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_08446f_z0239_y0740_x0054.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0fab19_z0163_y0516_x0681.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0eb994_z0157_y0835_x0630.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0da370_z0031_y0356_x0636.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0de3ee_z0201_y0642_x0801.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0f9df0_z0097_y0174_x0599.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_0fe63f_z0201_y0362_x0265.jpg'\n#path = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/train/tomo_1b82d1_z0204_y0697_x0680.jpg'\npath = '/kaggle/input/yolo-dataset-byu/yolo_dataset/images/val/tomo_05f919_z0125_y0471_x0845.jpg'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.955415Z","iopub.execute_input":"2025-04-16T23:05:18.955800Z","iopub.status.idle":"2025-04-16T23:05:18.976023Z","shell.execute_reply.started":"2025-04-16T23:05:18.955756Z","shell.execute_reply":"2025-04-16T23:05:18.974875Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"im = cv2.imread(path)\nim = np.transpose(im, (1, 0, 2))\n\n#calibrate\nloc = path.split('_')[3:]\nloc[-1] = int(loc[-1][1:-4])\nloc[0] = int(loc[0][1:])\nloc[1] = int(loc[1][1:])\n\n\n#resize\nim = cv2.resize(im, (640, 640))\nim = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)[..., None]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:18.977154Z","iopub.execute_input":"2025-04-16T23:05:18.977566Z","iopub.status.idle":"2025-04-16T23:05:19.015633Z","shell.execute_reply.started":"2025-04-16T23:05:18.977526Z","shell.execute_reply":"2025-04-16T23:05:19.014461Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patches, kp, labels = point_feature_extractor(path, loc)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:19.016616Z","iopub.execute_input":"2025-04-16T23:05:19.016897Z","iopub.status.idle":"2025-04-16T23:05:21.983248Z","shell.execute_reply.started":"2025-04-16T23:05:19.016874Z","shell.execute_reply":"2025-04-16T23:05:21.982400Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.scatter(kp[labels==0][:, 0], kp[labels==0][:, 1], s=5, alpha=1, c = 'blue', label = 'no motor')\nplt.scatter(kp[labels==1][:, 0], kp[labels==1][:, 1], s=5, alpha=1, c = 'red', label = 'motor')\nplt.imshow(im, cmap='gray')\nplt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:21.984140Z","iopub.execute_input":"2025-04-16T23:05:21.984411Z","iopub.status.idle":"2025-04-16T23:05:22.303429Z","shell.execute_reply.started":"2025-04-16T23:05:21.984389Z","shell.execute_reply":"2025-04-16T23:05:22.302216Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patches.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:22.306256Z","iopub.execute_input":"2025-04-16T23:05:22.306643Z","iopub.status.idle":"2025-04-16T23:05:22.312850Z","shell.execute_reply.started":"2025-04-16T23:05:22.306611Z","shell.execute_reply":"2025-04-16T23:05:22.311590Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.imshow(patches[labels==1][0], cmap='gray')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:22.314581Z","iopub.execute_input":"2025-04-16T23:05:22.314930Z","iopub.status.idle":"2025-04-16T23:05:22.524272Z","shell.execute_reply.started":"2025-04-16T23:05:22.314894Z","shell.execute_reply":"2025-04-16T23:05:22.523216Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"kp.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:22.525299Z","iopub.execute_input":"2025-04-16T23:05:22.525639Z","iopub.status.idle":"2025-04-16T23:05:22.532134Z","shell.execute_reply.started":"2025-04-16T23:05:22.525610Z","shell.execute_reply":"2025-04-16T23:05:22.530941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.imshow(im, cmap='gray')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:22.533628Z","iopub.execute_input":"2025-04-16T23:05:22.534011Z","iopub.status.idle":"2025-04-16T23:05:23.104319Z","shell.execute_reply.started":"2025-04-16T23:05:22.533979Z","shell.execute_reply":"2025-04-16T23:05:23.103176Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Graph Construction","metadata":{}},{"cell_type":"code","source":"!pip install /kaggle/input/pip-install-pyg/torch_spline_conv-1.2.2+pt25cu124-cp310-cp310-linux_x86_64.whl\n!pip install /kaggle/input/pip-install-pyg/torch_sparse-0.6.18+pt25cu124-cp310-cp310-linux_x86_64.whl\n!pip install /kaggle/input/pip-install-pyg/pyg_lib-0.4.0+pt25cu124-cp310-cp310-linux_x86_64.whl\n!pip install /kaggle/input/pip-install-pyg/torch_cluster-1.6.3+pt25cu124-cp310-cp310-linux_x86_64.whl\n!pip install /kaggle/input/pip-install-pyg/torch_geometric-2.6.1-py3-none-any.whl","metadata":{"trusted":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.105423Z","iopub.execute_input":"2025-04-16T23:05:23.105798Z","iopub.status.idle":"2025-04-16T23:05:23.110291Z","shell.execute_reply.started":"2025-04-16T23:05:23.105770Z","shell.execute_reply":"2025-04-16T23:05:23.108987Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch_geometric.nn import radius_graph\nfrom torch_geometric.utils import degree\nimport torch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.111364Z","iopub.execute_input":"2025-04-16T23:05:23.111771Z","iopub.status.idle":"2025-04-16T23:05:23.133694Z","shell.execute_reply.started":"2025-04-16T23:05:23.111726Z","shell.execute_reply":"2025-04-16T23:05:23.132620Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def normalize_kp(kp):\n    return kp/np.array(CFG.img_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.134790Z","iopub.execute_input":"2025-04-16T23:05:23.135164Z","iopub.status.idle":"2025-04-16T23:05:23.153011Z","shell.execute_reply.started":"2025-04-16T23:05:23.135136Z","shell.execute_reply":"2025-04-16T23:05:23.151826Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"kp_normalized = normalize_kp(kp)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.153995Z","iopub.execute_input":"2025-04-16T23:05:23.154276Z","iopub.status.idle":"2025-04-16T23:05:23.170507Z","shell.execute_reply.started":"2025-04-16T23:05:23.154252Z","shell.execute_reply":"2025-04-16T23:05:23.169117Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"edge_index = radius_graph(torch.from_numpy(kp_normalized), r=0.05, loop=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.171730Z","iopub.execute_input":"2025-04-16T23:05:23.172133Z","iopub.status.idle":"2025-04-16T23:05:23.188817Z","shell.execute_reply.started":"2025-04-16T23:05:23.172094Z","shell.execute_reply":"2025-04-16T23:05:23.187520Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"node_degrees = degree(edge_index[0], num_nodes=kp_normalized.shape[0])\n\n# Get max and average degree\nmax_degree = round(node_degrees.max().item(), 3)\navg_degree = node_degrees.mean().item()\nprint(\"Max Degree:\", max_degree)\nprint(\"Avg Degree:\", avg_degree)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.190026Z","iopub.execute_input":"2025-04-16T23:05:23.190368Z","iopub.status.idle":"2025-04-16T23:05:23.203172Z","shell.execute_reply.started":"2025-04-16T23:05:23.190338Z","shell.execute_reply":"2025-04-16T23:05:23.201999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"G = nx.Graph()\nG.add_edges_from(edge_index.t().tolist())\n\n# Extract node positions\npos = {i: kp[i].tolist() for i in range(kp_normalized.shape[0])}\n\ncolor_map = ['blue' if labels[i] == 0 else 'red' for i in range(kp_normalized.shape[0])]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.204152Z","iopub.execute_input":"2025-04-16T23:05:23.204573Z","iopub.status.idle":"2025-04-16T23:05:23.229806Z","shell.execute_reply.started":"2025-04-16T23:05:23.204532Z","shell.execute_reply":"2025-04-16T23:05:23.228518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize = (9, 9))\n#plt.imshow(im, cmap='gray')\nnx.draw(G, pos, with_labels=False, node_size=40, node_color=\"blue\", edge_color=\"black\", font_size=12, alpha=0.3)\nplt.title(f\"Radius Graph -- (Max_degr, Avg_degr) = {(max_degree, avg_degree)}\")\nplt.scatter(kp[labels==1][:, 0], kp[labels==1][:, 1], s=40, alpha=1, c = 'red', label = 'motor')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T23:05:23.230835Z","iopub.execute_input":"2025-04-16T23:05:23.231204Z","iopub.status.idle":"2025-04-16T23:05:23.587719Z","shell.execute_reply.started":"2025-04-16T23:05:23.231175Z","shell.execute_reply":"2025-04-16T23:05:23.586544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}