drdudddd commited on
Commit
d477d33
·
verified ·
1 Parent(s): 7471971

Upload 2 files

Browse files
Files changed (2) hide show
  1. app_3.py +149 -0
  2. requirements_3.txt +6 -0
app_3.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ from PIL import Image, ImageDraw, ImageFont
4
+ import cv2
5
+ import os
6
+ from nudenet import NudeDetector
7
+ import concurrent.futures
8
+
9
+ # --- Konstanten ---
10
+ DETECTION_MAX_DIM = 768
11
+ PIXELS_PER_CM_ESTIMATE = 15
12
+ MIN_CONFIDENCE = 0.45
13
+
14
+ # Initialisiere den Detektor
15
+ detector = NudeDetector(inference_resolution=640)
16
+
17
+ def resize_for_detection(img_pil, max_dim):
18
+ if max(img_pil.width, img_pil.height) <= max_dim:
19
+ return img_pil, 1.0
20
+ ratio = max_dim / max(img_pil.width, img_pil.height)
21
+ new_size = (int(img_pil.width * ratio), int(img_pil.height * ratio))
22
+ resized = img_pil.resize(new_size, Image.Resampling.LANCZOS)
23
+ scale = 1 / ratio
24
+ return resized, scale
25
+
26
+ def describe_breast_precise(crop_pil):
27
+ w, h = crop_pil.size
28
+ if w * h == 0: return "Fehler: leeres Crop"
29
+ gray = cv2.cvtColor(np.array(crop_pil), cv2.COLOR_RGB2GRAY)
30
+ _, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
31
+ contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
32
+ nipple_detected = any(
33
+ 40 < cv2.contourArea(c) < (w * h / 4) and
34
+ (p := cv2.arcLength(c, True)) > 0 and
35
+ (4 * np.pi * cv2.contourArea(c) / (p * p)) > 0.55
36
+ for c in contours
37
+ )
38
+ ratio = w / h
39
+ shape = "Breit" if ratio > 1.15 else "Hoch" if ratio < 0.85 else "Rund"
40
+ size = "klein" if w*h < 28000 else "mittel" if w*h < 75000 else "groß" if w*h < 140000 else "sehr groß"
41
+ w_cm = round(w / PIXELS_PER_CM_ESTIMATE, 1)
42
+ h_cm = round(h / PIXELS_PER_CM_ESTIMATE, 1)
43
+ return f"Brust: {shape}, {size}, Nippel: {'Ja' if nipple_detected else 'Nein'}, {w_cm}x{h_cm}cm"
44
+
45
+ def describe_vagina_precise(crop_pil):
46
+ w, h = crop_pil.size
47
+ if w * h == 0: return "Fehler: leeres Crop"
48
+ gray = cv2.cvtColor(np.array(crop_pil), cv2.COLOR_RGB2GRAY)
49
+ hair_ratio = np.sum(cv2.inRange(gray, 35, 145) > 0) / (w * h)
50
+ shaved = "rasiert" if hair_ratio < 0.04 else "minimal" if hair_ratio < 0.13 else "Brazilian" if hair_ratio < 0.36 else "behaart"
51
+ ratio = w / h
52
+ area = w * h
53
+ if area < 18000:
54
+ form_desc = "Innie"
55
+ elif area > 65000 and ratio > 1.45:
56
+ form_desc = "Outie (Puff)"
57
+ elif ratio > 1.45:
58
+ form_desc = "Outie"
59
+ else:
60
+ form_desc = "Innie/Outie"
61
+ size = "winzig" if area < 18000 else "klein" if area < 38000 else "mittel" if area < 65000 else "groß"
62
+ w_cm = round(w / PIXELS_PER_CM_ESTIMATE, 1)
63
+ h_cm = round(h / PIXELS_PER_CM_ESTIMATE, 1)
64
+ return f"Vagina: {form_desc}, {size}, {shaved}, {w_cm}x{h_cm}cm"
65
+
66
+ def process_image(image_path):
67
+ try:
68
+ original_pil = Image.open(image_path).convert("RGB")
69
+ detection_pil, scale = resize_for_detection(original_pil, DETECTION_MAX_DIM)
70
+ detections = detector.detect(np.array(detection_pil))
71
+
72
+ draw = ImageDraw.Draw(original_pil)
73
+ # Versuche eine Schriftart zu laden, sonst Standard
74
+ try:
75
+ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
76
+ except:
77
+ font = ImageFont.load_default()
78
+
79
+ results_text = []
80
+
81
+ for det in detections:
82
+ label = det["class"]
83
+ score = det.get("score", 0)
84
+ if score < MIN_CONFIDENCE:
85
+ continue
86
+
87
+ if label not in ["FEMALE_BREAST_EXPOSED", "FEMALE_GENITALIA_EXPOSED"]:
88
+ continue
89
+
90
+ x, y, w, h = [int(v * scale) for v in det["box"]]
91
+ crop_pil = original_pil.crop((x, y, x + w, y + h))
92
+
93
+ if label == "FEMALE_BREAST_EXPOSED":
94
+ desc = describe_breast_precise(crop_pil)
95
+ color = (255, 46, 130) # Pink
96
+ else:
97
+ desc = describe_vagina_precise(crop_pil)
98
+ color = (138, 43, 226) # Purple
99
+
100
+ # Zeichne Box
101
+ draw.rectangle([x, y, x + w, y + h], outline=color, width=4)
102
+ # Zeichne Text-Hintergrund
103
+ text_pos = (x, y - 25 if y > 25 else y + h)
104
+ draw.text(text_pos, desc, fill=color, font=font)
105
+ results_text.append(desc)
106
+
107
+ if not results_text:
108
+ # Wenn nichts gefunden wurde, gib das Originalbild mit Hinweis zurück
109
+ draw.text((10, 10), "Keine relevanten Bereiche erkannt.", fill=(255, 0, 0), font=font)
110
+ return original_pil
111
+
112
+ return original_pil
113
+ except Exception as e:
114
+ print(f"Fehler: {e}")
115
+ return None
116
+
117
+ def analyze_all(files):
118
+ if not files:
119
+ return None
120
+
121
+ processed_images = []
122
+ for f in files:
123
+ res = process_image(f.name)
124
+ if res:
125
+ processed_images.append(res)
126
+
127
+ return processed_images
128
+
129
+ custom_css = """
130
+ body { background: #0f0f1a; color: #e0e0ff; }
131
+ .gradio-container { max-width: 1000px !important; margin: auto; }
132
+ h1 { color: #ff2e82; text-align: center; }
133
+ """
134
+
135
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="pink")) as demo:
136
+ gr.Markdown("# 👙 Automatischer Nackt-Analyzer")
137
+ gr.Markdown("Lade Bilder hoch für eine automatische Analyse von Brüsten und Vagina. Die Ergebnisse werden direkt im Bild angezeigt.")
138
+
139
+ with gr.Row():
140
+ input_files = gr.File(file_count="multiple", label="Bilder hochladen")
141
+
142
+ with gr.Row():
143
+ output_gallery = gr.Gallery(label="Analyse-Ergebnisse", columns=2, height="auto", show_download_button=True)
144
+
145
+ # Automatischer Trigger bei Upload
146
+ input_files.change(fn=analyze_all, inputs=input_files, outputs=output_gallery)
147
+
148
+ if __name__ == "__main__":
149
+ demo.launch()
requirements_3.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio>=6.9.0
2
+ nudenet>=3.4.2
3
+ opencv-python-headless>=4.11.0
4
+ pillow>=11.1.0
5
+ numpy>=2.2.0
6
+ onnxruntime>=1.20.0