File size: 6,536 Bytes
0729074
 
 
75ded72
 
0729074
 
 
 
a56eca1
58ce0cc
 
 
 
0ec32fc
 
a00614f
b3a978a
65588a9
 
 
0729074
 
 
 
 
 
 
0ec32fc
0729074
 
0ec32fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0729074
 
0ec32fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0729074
0ec32fc
 
 
 
 
 
 
 
 
 
0729074
 
0ec32fc
 
 
 
 
0729074
86b2c3f
23590dd
86b2c3f
 
23590dd
0729074
0ec32fc
 
0729074
0ec32fc
 
0729074
 
 
 
 
 
 
 
 
 
 
0ec32fc
 
 
 
 
 
 
 
86b2c3f
0ec32fc
0729074
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import json
import numpy as np
from PIL import Image
import subprocess
import sys
import logging
import gradio as gr
from typing import Tuple, Dict, Optional
import tempfile
import os

def install(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

# 依存関係のインストール
install("opencv-python-headless")
install("moondream")
install("openai")
import cv2
import moondream as md
from openai import OpenAI
class PrivacyProtector:
    def __init__(self, moondream_api_key, deepseek_api_key):
        self.moon_model = md.vl(api_key=moondream_api_key)
        self.deepseek_client = OpenAI(
            api_key=deepseek_api_key,
            base_url="https://api.deepseek.com"
        )

    def analyze_risk(self, image_path):
        """画像のリスク分析を行う"""
        try:
            pil_image = Image.open(image_path)
            cv_image = cv2.imread(image_path)
            if cv_image is None:
                raise ValueError("画像の読み込みに失敗しました")

            encoded_image = self.moon_model.encode_image(pil_image)
            caption = self.moon_model.caption(encoded_image)["caption"]
            
            analysis_prompt = f"""
            以下の画像説明を基に個人情報漏洩リスクを分析し、厳密にJSON形式で返答してください:
            {{
                "risk_level": "high|medium|low",
                "risk_reason": "リスクの具体的理由",
                "objects_to_remove": ["消去すべきオブジェクトリスト"]
            }}
            
            画像説明: {caption}
            """
            
            response = self.deepseek_client.chat.completions.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "あなたは優秀なセキュリティ分析AIです。"},
                    {"role": "user", "content": analysis_prompt}
                ],
                temperature=0.3,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            return pil_image, cv_image, result
        
        except Exception as e:
            logging.error(f"リスク分析エラー: {str(e)}")
            raise

    def remove_objects(self, pil_image, cv_image, objects_to_remove):
        """オブジェクト検出と消去処理"""
        try:
            mask = np.zeros(cv_image.shape[:2], dtype=np.uint8)
            h, w = cv_image.shape[:2]
            
            for obj_name in objects_to_remove:
                detection = self.moon_model.detect(pil_image, obj_name)
                for obj in detection["objects"]:
                    x_min = int(obj['x_min'] * w)
                    y_min = int(obj['y_min'] * h)
                    x_max = int(obj['x_max'] * w)
                    y_max = int(obj['y_max'] * h)
                    cv2.rectangle(mask, (x_min, y_min), (x_max, y_max), 255, -1)
            
            inpainted = cv2.inpaint(cv_image, mask, 3, cv2.INPAINT_TELEA)
            return inpainted
        
        except Exception as e:
            logging.error(f"オブジェクト削除エラー: {str(e)}")
            raise

    def process_image(self, image_path):
        """画像処理フロー全体"""
        try:
            pil_img, cv_img, result = self.analyze_risk(image_path)
            if result['risk_level'] != 'low':
                cleaned = self.remove_objects(pil_img, cv_img, result['objects_to_remove'])
                return cleaned, result
            return cv_img, result
        
        except Exception as e:
            logging.error(f"画像処理エラー: {str(e)}")
            raise

def gradio_process(input_image):
    try:
        # 一時ファイルの処理
        with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_file:
            input_path = tmp_file.name
            cv2.imwrite(input_path, cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR))
        
        # 環境変数の安全な取得
        protector = PrivacyProtector(
            moondream_api_key=os.environ.get('MOONDREAM'),
            deepseek_api_key=os.environ.get('DEEPSEEK')
        )
        
        # 画像処理実行
        processed_image, result = protector.process_image(input_path)
        
        # 結果の整形
        output_image = cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB)
        
        info_html = f"""
        <div style="padding:20px; background:#f0f0f0; border-radius:10px;">
            <h3>分析結果</h3>
            <p><strong>生成キャプション:</strong> {result.get('caption', '')}</p>
            <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>
            <p><strong>理由:</strong> {result['risk_reason']}</p>
            <p><strong>消去対象:</strong> {', '.join(result['objects_to_remove'])}</p>
        </div>
        """
        
        return input_image, output_image, info_html
    
    except Exception as e:
        error_msg = f"処理中にエラーが発生しました: {str(e)}"
        return input_image, None, f'<div style="color:red;">{error_msg}</div>'
    
    finally:
        # 一時ファイルのクリーンアップ
        if 'input_path' in locals() and os.path.exists(input_path):
            os.remove(input_path)
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 🛡️ プライバシー保護画像処理ツール")
    
    with gr.Row():
        with gr.Column(scale=2):
            input_img = gr.Image(label="入力画像", type="numpy")
            submit_btn = gr.Button("画像を分析・処理", variant="primary")
        
        with gr.Column(scale=2):
            output_img = gr.Image(label="処理後の画像")
            info_output = gr.HTML(label="分析結果")
    
    with gr.Accordion("処理の詳細", open=False):
        gr.Markdown("""
        **処理フロー:**  
        1. 画像キャプション生成 (Moondream)  
        2. リスク分析 (DeepSeek)  
        3. オブジェクト検出・消去 (Moondream + OpenCV)  
        """)
    
    submit_btn.click(
        fn=gradio_process,
        inputs=input_img,
        outputs=[input_img, output_img, info_output]
    )

if __name__ == "__main__":
    demo.launch()