Spaces:
Sleeping
Sleeping
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() |