Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -5,25 +5,13 @@ import numpy as np
|
|
5 |
import cv2
|
6 |
from transformers import AutoImageProcessor, AutoModelForImageClassification
|
7 |
|
8 |
-
#
|
9 |
models = {
|
10 |
"model1": {
|
11 |
"name": "umm-maybe/AI-image-detector",
|
12 |
"processor": None,
|
13 |
"model": None,
|
14 |
-
"weight": 0
|
15 |
-
},
|
16 |
-
"model2": {
|
17 |
-
"name": "microsoft/resnet-50", # 通用图像分类模型
|
18 |
-
"processor": None,
|
19 |
-
"model": None,
|
20 |
-
"weight": 0.25
|
21 |
-
},
|
22 |
-
"model3": {
|
23 |
-
"name": "google/vit-base-patch16-224", # Vision Transformer模型
|
24 |
-
"processor": None,
|
25 |
-
"model": None,
|
26 |
-
"weight": 0.25
|
27 |
}
|
28 |
}
|
29 |
|
@@ -38,74 +26,6 @@ for key in models:
|
|
38 |
models[key]["processor"] = None
|
39 |
models[key]["model"] = None
|
40 |
|
41 |
-
def process_model_output(model_info, outputs, probabilities):
|
42 |
-
"""处理不同模型的输出,统一返回AI生成概率"""
|
43 |
-
model_name = model_info["name"].lower()
|
44 |
-
|
45 |
-
# 针对不同模型的特殊处理
|
46 |
-
if "ai-image-detector" in model_name:
|
47 |
-
# umm-maybe/AI-image-detector模型特殊处理
|
48 |
-
# 检查标签
|
49 |
-
ai_label_idx = None
|
50 |
-
human_label_idx = None
|
51 |
-
|
52 |
-
for idx, label in model_info["model"].config.id2label.items():
|
53 |
-
label_lower = label.lower()
|
54 |
-
if "ai" in label_lower or "generated" in label_lower or "fake" in label_lower:
|
55 |
-
ai_label_idx = idx
|
56 |
-
if "human" in label_lower or "real" in label_lower:
|
57 |
-
human_label_idx = idx
|
58 |
-
|
59 |
-
# 根据标签确定AI概率
|
60 |
-
if human_label_idx is not None:
|
61 |
-
# 如果有human标签,AI概率是1减去human概率
|
62 |
-
return 1 - float(probabilities[0][human_label_idx].item())
|
63 |
-
elif ai_label_idx is not None:
|
64 |
-
# 如果有AI标签
|
65 |
-
return float(probabilities[0][ai_label_idx].item())
|
66 |
-
else:
|
67 |
-
# 默认使用索引1作为AI标签
|
68 |
-
return float(probabilities[0][1].item())
|
69 |
-
|
70 |
-
elif "resnet" in model_name:
|
71 |
-
# 通用图像分类模型,使用简单启发式方法
|
72 |
-
predicted_class_idx = outputs.logits.argmax(-1).item()
|
73 |
-
# 检查是否有与AI相关的类别
|
74 |
-
predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
|
75 |
-
|
76 |
-
# 简单启发式:检查类别名称是否包含与AI生成相关的关键词
|
77 |
-
ai_keywords = ["artificial", "generated", "synthetic", "fake", "computer"]
|
78 |
-
for keyword in ai_keywords:
|
79 |
-
if keyword in predicted_class:
|
80 |
-
return float(probabilities[0][predicted_class_idx].item())
|
81 |
-
|
82 |
-
# 如果没有明确的AI类别,返回中等概率
|
83 |
-
return 0.5
|
84 |
-
|
85 |
-
elif "vit" in model_name:
|
86 |
-
# Vision Transformer模型
|
87 |
-
predicted_class_idx = outputs.logits.argmax(-1).item()
|
88 |
-
# 同样检查类别名称
|
89 |
-
predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
|
90 |
-
|
91 |
-
# 简单启发式:检查类别名称是否包含与AI生成相关的关键词
|
92 |
-
ai_keywords = ["artificial", "generated", "synthetic", "fake", "computer"]
|
93 |
-
for keyword in ai_keywords:
|
94 |
-
if keyword in predicted_class:
|
95 |
-
return float(probabilities[0][predicted_class_idx].item())
|
96 |
-
|
97 |
-
# 如果没有明确的AI类别,返回中等概率
|
98 |
-
return 0.5
|
99 |
-
|
100 |
-
# 默认处理
|
101 |
-
predicted_class_idx = outputs.logits.argmax(-1).item()
|
102 |
-
predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
|
103 |
-
|
104 |
-
if "ai" in predicted_class or "generated" in predicted_class or "fake" in predicted_class:
|
105 |
-
return float(probabilities[0][predicted_class_idx].item())
|
106 |
-
else:
|
107 |
-
return 1 - float(probabilities[0][predicted_class_idx].item())
|
108 |
-
|
109 |
def analyze_image_features(image):
|
110 |
# 转换为OpenCV格式
|
111 |
img_array = np.array(image)
|
@@ -151,54 +71,7 @@ def analyze_image_features(image):
|
|
151 |
noise = cv2.absdiff(img_cv, blurred)
|
152 |
features["noise_level"] = float(np.mean(noise))
|
153 |
|
154 |
-
|
155 |
-
# 水平对称性
|
156 |
-
if img_cv.shape[1] % 2 == 0: # 确保宽度是偶数
|
157 |
-
left_half = img_cv[:, :img_cv.shape[1]//2]
|
158 |
-
right_half = cv2.flip(img_cv[:, img_cv.shape[1]//2:], 1)
|
159 |
-
if left_half.shape == right_half.shape:
|
160 |
-
h_symmetry = 1 - float(np.mean(cv2.absdiff(left_half, right_half)) / 255)
|
161 |
-
features["horizontal_symmetry"] = h_symmetry
|
162 |
-
|
163 |
-
# 垂直对称性
|
164 |
-
if img_cv.shape[0] % 2 == 0: # 确保高度是偶数
|
165 |
-
top_half = img_cv[:img_cv.shape[0]//2, :]
|
166 |
-
bottom_half = cv2.flip(img_cv[img_cv.shape[0]//2:, :], 0)
|
167 |
-
if top_half.shape == bottom_half.shape:
|
168 |
-
v_symmetry = 1 - float(np.mean(cv2.absdiff(top_half, bottom_half)) / 255)
|
169 |
-
features["vertical_symmetry"] = v_symmetry
|
170 |
-
|
171 |
-
# 分析颜色分布 - AI生成图像通常有更平滑的颜色过渡
|
172 |
-
if len(img_cv.shape) == 3:
|
173 |
-
hsv = cv2.cvtColor(img_cv, cv2.COLOR_BGR2HSV)
|
174 |
-
hue_std = float(np.std(hsv[:,:,0]))
|
175 |
-
sat_std = float(np.std(hsv[:,:,1]))
|
176 |
-
val_std = float(np.std(hsv[:,:,2])) = hue_std /一化
|
177 |
-
features["saturation_variation"] =_variation"] = val_std /_final_decision(ai_probability, image率和图像特征做出更准确的决策策
|
178 |
-
if ai_probability > 0.7:
|
179 |
-
base_decision = "高概率AI生成"
|
180 |
-
elif ai_probability < 0.3:
|
181 |
-
base_decision = "高概率人类创作"
|
182 |
-
|
183 |
-
|
184 |
-
# 特征调整
|
185 |
-
feature_score = 0
|
186 |
-
|
187 |
-
# 检查对称性 - 高对称性通常表示AI生成
|
188 |
-
if "horizontal_symmetry" in image_features and image_features["horizontal_symmetry"] > 0.850.1
|
189 |
-
if "vertical_symmetry" in image_features and image_features["vertical_symmetry"] > 0.85:
|
190 |
-
# 检查边缘 - AI生成图像通常边缘密度较低_density"] < 0.01_score += 0.1 检查噪声 - AI生成图像通常噪声较低
|
191 |
-
"] < 0_score += 0.1 检查颜色变化 - AI生成图像通常颜色变化更ue_variation" in image_features and image_features["hue_variation"] < 0.05_score += uration_variation" in image_features and image_features["saturation_variation"] < _score += 0.1
|
192 |
-
率
|
193 |
-
adjusted_probability = min(1.0, max(0.0, ai_probability + feature_score))
|
194 |
-
|
195 |
-
断
|
196 |
-
if adjusted_probability > 0.7:
|
197 |
-
return "高概率AI生成", adjusted_probability
|
198 |
-
elif adjusted_probability < 0.3:
|
199 |
-
return "高概率人类创作", adjusted_probability
|
200 |
-
else:
|
201 |
-
return "无法确定", adjusted_probability
|
202 |
|
203 |
def detect_ai_image(image):
|
204 |
if image is None:
|
@@ -217,14 +90,36 @@ def detect_ai_image(image):
|
|
217 |
with torch.no_grad():
|
218 |
outputs = model_info["model"](**inputs)
|
219 |
|
|
|
|
|
|
|
|
|
220 |
# 获取概率
|
221 |
-
probabilities = torch.nn.functional.softmax(
|
|
|
|
|
|
|
|
|
222 |
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
# 添加到结果
|
227 |
-
predicted_class_idx = outputs.logits.argmax(-1).item()
|
228 |
results[key] = {
|
229 |
"model_name": model_info["name"],
|
230 |
"ai_probability": ai_probability,
|
@@ -250,13 +145,17 @@ def detect_ai_image(image):
|
|
250 |
# 分析图像特征
|
251 |
image_features = analyze_image_features(image)
|
252 |
|
253 |
-
#
|
254 |
-
|
|
|
|
|
|
|
|
|
|
|
255 |
|
256 |
# 构建最终结果
|
257 |
final_result = {
|
258 |
-
"ai_probability":
|
259 |
-
"original_ai_probability": final_ai_probability,
|
260 |
"confidence_level": confidence_level,
|
261 |
"individual_model_results": results,
|
262 |
"features": image_features
|
@@ -276,3 +175,4 @@ iface = gr.Interface(
|
|
276 |
)
|
277 |
|
278 |
iface.launch()
|
|
|
|
5 |
import cv2
|
6 |
from transformers import AutoImageProcessor, AutoModelForImageClassification
|
7 |
|
8 |
+
# 加载检测模型
|
9 |
models = {
|
10 |
"model1": {
|
11 |
"name": "umm-maybe/AI-image-detector",
|
12 |
"processor": None,
|
13 |
"model": None,
|
14 |
+
"weight": 1.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
}
|
17 |
|
|
|
26 |
models[key]["processor"] = None
|
27 |
models[key]["model"] = None
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
def analyze_image_features(image):
|
30 |
# 转换为OpenCV格式
|
31 |
img_array = np.array(image)
|
|
|
71 |
noise = cv2.absdiff(img_cv, blurred)
|
72 |
features["noise_level"] = float(np.mean(noise))
|
73 |
|
74 |
+
return features
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
def detect_ai_image(image):
|
77 |
if image is None:
|
|
|
90 |
with torch.no_grad():
|
91 |
outputs = model_info["model"](**inputs)
|
92 |
|
93 |
+
# 获取预测结果
|
94 |
+
logits = outputs.logits
|
95 |
+
predicted_class_idx = logits.argmax(-1).item()
|
96 |
+
|
97 |
# 获取概率
|
98 |
+
probabilities = torch.nn.functional.softmax(logits, dim=-1)
|
99 |
+
|
100 |
+
# 确定AI生成概率
|
101 |
+
ai_label_idx = None
|
102 |
+
human_label_idx = None
|
103 |
|
104 |
+
for idx, label in model_info["model"].config.id2label.items():
|
105 |
+
label_lower = label.lower()
|
106 |
+
if "ai" in label_lower or "generated" in label_lower or "fake" in label_lower:
|
107 |
+
ai_label_idx = idx
|
108 |
+
if "human" in label_lower or "real" in label_lower:
|
109 |
+
human_label_idx = idx
|
110 |
+
|
111 |
+
# 根据标签确定AI概率
|
112 |
+
if human_label_idx is not None:
|
113 |
+
# 如果有human标签,AI概率是1减去human概率
|
114 |
+
ai_probability = 1 - float(probabilities[0][human_label_idx].item())
|
115 |
+
elif ai_label_idx is not None:
|
116 |
+
# 如果有AI标签
|
117 |
+
ai_probability = float(probabilities[0][ai_label_idx].item())
|
118 |
+
else:
|
119 |
+
# 默认使用索引1作为AI标签
|
120 |
+
ai_probability = float(probabilities[0][1].item())
|
121 |
|
122 |
# 添加到结果
|
|
|
123 |
results[key] = {
|
124 |
"model_name": model_info["name"],
|
125 |
"ai_probability": ai_probability,
|
|
|
145 |
# 分析图像特征
|
146 |
image_features = analyze_image_features(image)
|
147 |
|
148 |
+
# 确定置信度级别
|
149 |
+
if final_ai_probability > 0.7:
|
150 |
+
confidence_level = "高概率AI生成"
|
151 |
+
elif final_ai_probability < 0.3:
|
152 |
+
confidence_level = "高概率人类创作"
|
153 |
+
else:
|
154 |
+
confidence_level = "无法确定"
|
155 |
|
156 |
# 构建最终结果
|
157 |
final_result = {
|
158 |
+
"ai_probability": final_ai_probability,
|
|
|
159 |
"confidence_level": confidence_level,
|
160 |
"individual_model_results": results,
|
161 |
"features": image_features
|
|
|
175 |
)
|
176 |
|
177 |
iface.launch()
|
178 |
+
|