File size: 3,928 Bytes
5492757
745d6a0
 
 
 
 
6800efc
745d6a0
 
 
 
 
6800efc
745d6a0
 
 
 
 
 
6800efc
745d6a0
 
 
 
 
 
 
 
 
5492757
745d6a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6800efc
745d6a0
 
 
 
 
 
 
 
 
 
 
5492757
 
 
 
1ed363b
 
 
5492757
 
 
 
 
 
 
745d6a0
 
5492757
745d6a0
 
5492757
 
 
745d6a0
 
 
 
 
 
1ed363b
 
 
 
 
 
5492757
1ed363b
 
 
 
 
 
 
 
 
 
5492757
 
 
1ed363b
5492757
 
1ed363b
5492757
 
 
 
 
 
 
 
 
 
 
6800efc
5492757
 
 
 
 
6800efc
5492757
 
 
6800efc
5492757
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from PIL import Image
import gradio as gr
from utils import get_patch_embeddings, compute_patch_similarity, overlay_similarity, device

selected_patch = {"row": 0, "col": 0}  

def init_states(img, alpha):
    if img is None:
        return gr.update(value=None), None
    patch_embs, patch_embs_norm, rows, cols = get_patch_embeddings(img, ps=16, device=device)
    
    sim_map = compute_patch_similarity(patch_embs, patch_embs_norm, 0, 0)
    result_img = overlay_similarity(img, sim_map, alpha=alpha, cmap="hot")

    state = {
        "img": img,
        "patch_embs": patch_embs,
        "patch_embs_norm": patch_embs_norm,
        "grid_size": rows,
        "alpha": alpha,
        "overlay_img":result_img,
    }

    return state, result_img

def store_patch(evt, state):
    if state is None or evt is None:
        return state

    rows = state["grid_size"]  
    cols = rows
    overlay_img = state["overlay_img"]
    overlay_W, overlay_H = overlay_img.size
    x_click, y_click = evt.index     # coordinates from click event

    # Map click coordinates to original patch grid
    col = int(x_click / overlay_W * cols)
    row = int(y_click / overlay_H * rows)

    # Clamp to valid range
    col = min(max(col, 0), cols - 1)
    row = min(max(row, 0), rows - 1)

    # Store in global or state dictionary
    selected_patch["row"] = row
    selected_patch["col"] = col


    return state


def reload_overlay(evt: gr.SelectData,state,alpha):
    if state is None:
        return None
    store_patch(evt, state)
    row, col = selected_patch["row"], selected_patch["col"]
    img = state["img"]
    patch_embs = state["patch_embs"]
    patch_embs_norm = state["patch_embs_norm"]
    sim_map = compute_patch_similarity(patch_embs, patch_embs_norm, row, col)
    result_img = overlay_similarity(img, sim_map, alpha=alpha, cmap="hot")
    return result_img

SAMPLE_IMAGES = {
    "Dog": "dog.jpg",
    "Cats": "cats.png",
    "Fruits": "fruits.png",
    "Brick Kiln": "brick-kiln.png",
    "People crossing street": "people.png",
    "Medical scan": "brain-tumor.png",
}

def load_sample(choice):
    if choice and choice in SAMPLE_IMAGES:
        return Image.open(SAMPLE_IMAGES[choice])
    return None

with gr.Blocks() as demo:
    state_store = gr.State()

    gr.Markdown("""
    <h1 style="font-size:36px; font-weight:bold;">Patch Similarity Visualizer</h1>
    <p style="font-size:18px;"> This tool visualizes similarity between image patches using DINOv3 embeddings. To use: <br>
     <ul style="font-size:18px;">
        <li>Upload an image in the <strong>left box</strong> or choose a sample image.</li>
        <li>Click anywhere in the <strong>right box</strong> to select a patch.</li>
        <li>View the similarity of the selected patch with all other patches in the image.</li>
    </ul>
    """)

    with gr.Row():
        img_choice = gr.Dropdown(
            choices=list(SAMPLE_IMAGES.keys()),
            label="Choose a sample image",
            value=None,
            interactive=True
        )

        alpha_slider = gr.Slider(
            minimum=0.0,
            maximum=1.0,
            value=0.5,
            step=0.05,
            label="Overlay Transparency (alpha)",
            interactive=True
        )
    with gr.Row():
        img_input = gr.Image(
                type="pil",
                label="Or upload your own image"
            )
    
        output_img = gr.Image(
            type="pil",
            label="Similarity Overlay",
            interactive=True
        )

    img_choice.change(
        fn=load_sample,
        inputs=[img_choice],
        outputs=[img_input]
    )

    img_input.change(
        fn=init_states,
        inputs=[img_input, alpha_slider],
        outputs=[state_store, output_img]
    )

    output_img.select(
        fn=reload_overlay,
        inputs=[state_store, alpha_slider],
        outputs=[output_img]
    )


demo.launch()