oggata commited on
Commit
e147828
·
verified ·
1 Parent(s): 9f7a81c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -0
app.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gradio版 DINOv2セグメンテーション
2
+
3
+ # 必要なライブラリのインストール
4
+ !pip install torch torchvision
5
+ !pip install git+https://github.com/facebookresearch/dinov2.git
6
+ !pip install scikit-learn matplotlib Pillow numpy gradio
7
+
8
+ import torch
9
+ import torchvision.transforms as transforms
10
+ from PIL import Image
11
+ import matplotlib.pyplot as plt
12
+ import numpy as np
13
+ from sklearn.cluster import KMeans
14
+ import gradio as gr
15
+
16
+ # デバイスの設定
17
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
18
+ print(f"使用デバイス: {device}")
19
+
20
+ # DINOv2モデルのロード
21
+ print("モデルを読み込んでいます...")
22
+ model = torch.hub.load('facebookresearch/dinov2', 'dinov2_vits14')
23
+ model = model.to(device)
24
+ model.eval()
25
+ print("モデルの読み込み完了!")
26
+
27
+ # 画像の前処理
28
+ transform = transforms.Compose([
29
+ transforms.Resize((518, 518)),
30
+ transforms.ToTensor(),
31
+ transforms.Normalize(mean=[0.485, 0.456, 0.406],
32
+ std=[0.229, 0.224, 0.225])
33
+ ])
34
+
35
+ def segment_image_gradio(image, n_segments, show_overlay):
36
+ """
37
+ Gradio用のセグメンテーション関数
38
+
39
+ Args:
40
+ image: PIL Image
41
+ n_segments: セグメント数
42
+ show_overlay: オーバーレイ表示するかどうか
43
+
44
+ Returns:
45
+ セグメンテーション結果の画像
46
+ """
47
+ if image is None:
48
+ return None
49
+
50
+ # PIL Imageに変換
51
+ if not isinstance(image, Image.Image):
52
+ image = Image.fromarray(image).convert('RGB')
53
+
54
+ original_size = image.size
55
+
56
+ # 画像の前処理
57
+ img_tensor = transform(image).unsqueeze(0).to(device)
58
+
59
+ # 特徴量の抽出
60
+ with torch.no_grad():
61
+ features = model.forward_features(img_tensor)
62
+ patch_features = features['x_norm_patchtokens']
63
+
64
+ # 特徴量を整形
65
+ patch_h = patch_w = 518 // 14
66
+ patch_features = patch_features.reshape(patch_h, patch_w, -1)
67
+ patch_features = patch_features.cpu().numpy()
68
+
69
+ # K-meansクラスタリング
70
+ features_flat = patch_features.reshape(-1, patch_features.shape[-1])
71
+ kmeans = KMeans(n_clusters=n_segments, random_state=42, n_init=10)
72
+ segments = kmeans.fit_predict(features_flat)
73
+ segments = segments.reshape(patch_h, patch_w)
74
+
75
+ # 元の画像サイズにリサイズ
76
+ segments_resized = Image.fromarray(segments.astype(np.uint8))
77
+ segments_resized = segments_resized.resize(original_size, Image.NEAREST)
78
+ segments_final = np.array(segments_resized)
79
+
80
+ # カラーマップを適用
81
+ cmap = plt.cm.get_cmap('tab20')
82
+ segments_colored = cmap(segments_final / n_segments)
83
+ segments_colored = (segments_colored[:, :, :3] * 255).astype(np.uint8)
84
+
85
+ # オーバーレイ表示
86
+ if show_overlay:
87
+ # 元の画像とセグメンテーションをブレンド
88
+ image_array = np.array(image)
89
+ result = (image_array * 0.6 + segments_colored * 0.4).astype(np.uint8)
90
+ else:
91
+ result = segments_colored
92
+
93
+ return result
94
+
95
+ # Gradioインターフェース
96
+ with gr.Blocks(title="DINOv2 Image Segmentation") as demo:
97
+ gr.Markdown(
98
+ """
99
+ # 🎨 DINOv2 画像セグメンテーション
100
+
101
+ DINOv2を使った画像のセマンティックセグメンテーションツールです。
102
+ 画像をアップロードして、セグメント数を調整してみてください。
103
+ """
104
+ )
105
+
106
+ with gr.Row():
107
+ with gr.Column():
108
+ input_image = gr.Image(
109
+ label="入力画像",
110
+ type="pil",
111
+ height=400
112
+ )
113
+
114
+ n_segments = gr.Slider(
115
+ minimum=2,
116
+ maximum=20,
117
+ value=8,
118
+ step=1,
119
+ label="セグメント数",
120
+ info="画像を分割する領域の数"
121
+ )
122
+
123
+ show_overlay = gr.Checkbox(
124
+ label="オリジナル画像とオーバーレイ表示",
125
+ value=True
126
+ )
127
+
128
+ segment_btn = gr.Button("セグメンテーション実行", variant="primary")
129
+
130
+ with gr.Column():
131
+ output_image = gr.Image(
132
+ label="セグメンテーション結果",
133
+ height=400
134
+ )
135
+
136
+ # 例を追加
137
+ gr.Examples(
138
+ examples=[
139
+ ["https://images.unsplash.com/photo-1506905925346-21bda4d32df4", 8, True],
140
+ ["https://images.unsplash.com/photo-1441974231531-c6227db76b6e", 6, True],
141
+ ["https://images.unsplash.com/photo-1472214103451-9374bd1c798e", 10, False],
142
+ ],
143
+ inputs=[input_image, n_segments, show_overlay],
144
+ outputs=output_image,
145
+ fn=segment_image_gradio,
146
+ cache_examples=False,
147
+ )
148
+
149
+ gr.Markdown(
150
+ """
151
+ ### 使い方
152
+ 1. 画像をアップロードまたはドラッ���&ドロップ
153
+ 2. セグメント数を調整(2〜20)
154
+ 3. オーバーレイ表示のオン/オフを選択
155
+ 4. 「セグメンテーション実行」ボタンをクリック
156
+
157
+ ### ヒント
158
+ - セグメント数が少ないほど大きな領域に分割されます
159
+ - オーバーレイ表示で元の画像と結果を比較できます
160
+ - 処理には数秒かかる場合があります(GPU使用時は高速)
161
+ """
162
+ )
163
+
164
+ # ボタンクリック時のイベント
165
+ segment_btn.click(
166
+ fn=segment_image_gradio,
167
+ inputs=[input_image, n_segments, show_overlay],
168
+ outputs=output_image
169
+ )
170
+
171
+ # スライダー変更時のリアルタイム更新(オプション)
172
+ # n_segments.change(
173
+ # fn=segment_image_gradio,
174
+ # inputs=[input_image, n_segments, show_overlay],
175
+ # outputs=output_image
176
+ # )
177
+
178
+ # アプリの起動
179
+ demo.launch(share=True, debug=True)