rein0421 commited on
Commit
51d2d8c
·
verified ·
1 Parent(s): afba240

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -0
app.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import tempfile
3
+ import cv2
4
+ import json
5
+
6
+ class PrivacyProtector:
7
+ def __init__(self, moondream_api_key, deepseek_api_key):
8
+ # Moondream初期化
9
+ self.moon_model = md.vl(api_key=moondream_api_key)
10
+
11
+ # DeepSeekクライアント初期化
12
+ self.deepseek_client = OpenAI(
13
+ api_key=deepseek_api_key,
14
+ base_url="https://api.deepseek.com"
15
+ )
16
+
17
+ def analyze_risk(self, image_path):
18
+ """画像のリスク分析を行う"""
19
+ # 画像読み込みとエンコード
20
+ pil_image = Image.open(image_path)
21
+ cv_image = cv2.imread(image_path)
22
+ encoded_image = self.moon_model.encode_image(pil_image)
23
+
24
+ # 画像キャプション生成
25
+ caption = self.moon_model.caption(encoded_image)["caption"]
26
+ print(caption)
27
+ # リスク分析プロンプト
28
+ analysis_prompt = f"""
29
+ 以下の画像説明を基に個人情報漏洩リスクを分析し、厳密にJSON形式で返答してください:
30
+ {{
31
+ "risk_level": "high|medium|low",
32
+ "risk_reason": "リスクの具体的理由",
33
+ "objects_to_remove": ["消去すべきオブジェクトリスト"]
34
+ }}
35
+
36
+ 画像説明: {caption}
37
+ """
38
+
39
+ # DeepSeek API呼び出し
40
+ response = self.deepseek_client.chat.completions.create(
41
+ model="deepseek-chat",
42
+ messages=[
43
+ {"role": "system", "content": "あなたは優秀なセキュリティ分析AIです。"},
44
+ {"role": "user", "content": analysis_prompt}
45
+ ],
46
+ temperature=0.3,
47
+ response_format={"type": "json_object"}
48
+ )
49
+
50
+ # 結果パース
51
+ result = json.loads(response.choices[0].message.content)
52
+ return pil_image, cv_image, result
53
+
54
+ def remove_objects(self, pil_image, cv_image, objects_to_remove):
55
+ """オブジェクト検出と消去処理"""
56
+ # マスク作成
57
+ mask = np.zeros(cv_image.shape[:2], dtype=np.uint8)
58
+ h, w = cv_image.shape[:2]
59
+
60
+ for obj_name in objects_to_remove:
61
+ # オブジェクト検出
62
+ detection = self.moon_model.detect(pil_image, obj_name)
63
+ print(detection)
64
+ for obj in detection["objects"]:
65
+ # 正規化座標→絶対座標変換
66
+ x_min = int(obj['x_min'] * w)
67
+ y_min = int(obj['y_min'] * h)
68
+ x_max = int(obj['x_max'] * w)
69
+ y_max = int(obj['y_max'] * h)
70
+
71
+ # マスク領域を矩形で追加
72
+ cv2.rectangle(mask, (x_min, y_min), (x_max, y_max), 255, -1)
73
+
74
+ # インペイント処理
75
+ inpainted = cv2.inpaint(cv_image, mask, 3, cv2.INPAINT_TELEA)
76
+ return inpainted
77
+
78
+ def process_image(self, image_path, output_path):
79
+ """画像処理フロー全体"""
80
+ pil_img, cv_img, result = self.analyze_risk(image_path)
81
+ print(f"リスクレベル: {result['risk_level']}")
82
+ print(f"理由: {result['risk_reason']}")
83
+
84
+ if result['risk_level'] != 'low':
85
+ print( result['objects_to_remove'])
86
+ cleaned = self.remove_objects(pil_img, cv_img, result['objects_to_remove'])
87
+ cv2.imwrite(output_path, cleaned)
88
+ print(f"処理済み画像を保存: {output_path}")
89
+ return True
90
+ print("リスク対象なし")
91
+ return False
92
+
93
+ def gradio_process(input_image):
94
+ with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp_file:
95
+ input_path = tmp_file.name
96
+ output_path = "/content/output.jpg"
97
+
98
+ cv2.imwrite(input_path, cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR))
99
+
100
+ protector = PrivacyProtector(
101
+ moondream_api_key="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXlfaWQiOiI4NmI0NTUxMi01NWZlLTQ0YzItYTA2Ni1hMTE1NDBlM2EzZTMiLCJpYXQiOjE3Mzc4NTMzMzJ9.8dc3xo_z7nYApJwaOCI2ayYX9pTKpo8QHkoH96ykEcg",
102
+ deepseek_api_key="sk-61418a466189492c916ec7bcc873b142"
103
+ )
104
+
105
+
106
+ # 分析結果を含めて取得
107
+ pil_img, cv_img, result = protector.analyze_risk(input_path)
108
+ processed = protector.process_image(input_path, output_path)
109
+
110
+ # 出力画像
111
+ output = cv2.cvtColor(cv2.imread(output_path), cv2.COLOR_BGR2RGB) if processed else None
112
+
113
+ # 表示用情報の整形
114
+ info_html = f"""
115
+ <div style="padding:20px; background:#f0f0f0; border-radius:10px;">
116
+ <h3>分析結果</h3>
117
+ <p><strong>生成キャプション:</strong> {result.get('caption', '')}</p>
118
+ <p><strong>リスクレベル:</strong> <span style="color:{'red' if result['risk_level'] == 'high' else 'orange' if result['risk_level'] == 'medium' else 'green'}">{result['risk_level'].upper()}</span></p>
119
+ <p><strong>理由:</strong> {result['risk_reason']}</p>
120
+ <p><strong>消去対象:</strong> {', '.join(result['objects_to_remove'])}</p>
121
+ </div>
122
+ """
123
+
124
+ return input_image, output, info_html
125
+
126
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
127
+ gr.Markdown("# 🛡️ プライバシー保護画像処理ツール")
128
+
129
+ with gr.Row():
130
+ with gr.Column(scale=2):
131
+ input_img = gr.Image(label="入力画像", type="numpy")
132
+ submit_btn = gr.Button("画像を分析・処理", variant="primary")
133
+
134
+ with gr.Column(scale=2):
135
+ output_img = gr.Image(label="処理後の画像")
136
+ info_output = gr.HTML(label="分析結果")
137
+
138
+ with gr.Accordion("処理の詳細", open=False):
139
+ gr.Markdown("""
140
+ **処理フロー:**
141
+ 1. 画像キャプション生成 (Moondream)
142
+ 2. リスク分析 (DeepSeek)
143
+ 3. オブジェクト検出・消去 (Moondream + OpenCV)
144
+ """)
145
+
146
+ submit_btn.click(
147
+ fn=gradio_process,
148
+ inputs=input_img,
149
+ outputs=[input_img, output_img, info_output]
150
+ )
151
+
152
+ if __name__ == "__main__":
153
+ demo.launch()