aaappp7878 commited on
Commit
d2c6cf8
·
verified ·
1 Parent(s): 2daec1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +264 -40
app.py CHANGED
@@ -5,13 +5,25 @@ 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": 1.0
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
  }
17
 
@@ -26,7 +38,78 @@ for key in models:
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)
32
  if len(img_array.shape) == 3 and img_array.shape[2] == 3:
@@ -46,6 +129,13 @@ def analyze_image_features(image):
46
  features["avg_red"] = float(np.mean(img_array[:,:,0]))
47
  features["avg_green"] = float(np.mean(img_array[:,:,1]))
48
  features["avg_blue"] = float(np.mean(img_array[:,:,2]))
 
 
 
 
 
 
 
49
 
50
  # 边缘一致性分析
51
  edges = cv2.Canny(img_cv, 100, 200)
@@ -64,16 +154,168 @@ def analyze_image_features(image):
64
  # 计算GLCM属性
65
  features["texture_contrast"] = float(np.mean(graycoprops(glcm, 'contrast')[0]))
66
  features["texture_homogeneity"] = float(np.mean(graycoprops(glcm, 'homogeneity')[0]))
 
 
67
 
68
  # 噪声分析
69
  if len(img_array.shape) == 3:
70
  blurred = cv2.GaussianBlur(img_cv, (5, 5), 0)
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:
78
  return {"error": "未提供图像"}
79
 
@@ -90,36 +332,14 @@ def detect_ai_image(image):
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
- # 修改后的标签解释逻辑
112
- if human_label_idx is not None:
113
- # 反转解释,将human标签视为AI生成的指标
114
- ai_probability = 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,
@@ -150,32 +370,36 @@ def detect_ai_image(image):
150
 
151
  # 低边缘密度通常表示AI生成
152
  if image_features["edge_density"] < 0.01:
153
- adjusted_probability += 0.2
154
 
155
  # 高纹理均匀性通常表示AI生成
156
- if image_features["texture_homogeneity"] > 0.5:
157
  adjusted_probability += 0.1
158
 
159
  # 低噪声水平通常表示AI生成
160
  if image_features["noise_level"] < 0.5:
161
  adjusted_probability += 0.1
162
 
 
 
 
 
163
  # 确保概率在0-1范围内
164
  adjusted_probability = min(1.0, max(0.0, adjusted_probability))
165
 
166
- # 调整后的阈值判断
167
- if adjusted_probability > 0.5: # 降低AI判定阈值
168
- confidence_level = "高概率AI生成"
169
- elif adjusted_probability < 0.2: # 提高人类判定要求
170
- confidence_level = "高概率人类创作"
171
- else:
172
- confidence_level = "无法确定"
173
 
174
  # 构建最终结果
175
  final_result = {
176
  "ai_probability": adjusted_probability,
177
- "original_ai_probability": final_ai_probability,
178
- "confidence_level": confidence_level,
 
 
179
  "individual_model_results": results,
180
  "features": image_features
181
  }
@@ -188,7 +412,7 @@ iface = gr.Interface(
188
  inputs=gr.Image(type="pil"),
189
  outputs=gr.JSON(),
190
  title="增强型AI图像检测API",
191
- description="多模型集成检测图像是否由AI生成",
192
  examples=None,
193
  allow_flagging="never"
194
  )
 
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.5
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
  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
+ # 修改后的标签解释逻辑 - 反转解释
60
+ if human_label_idx is not None:
61
+ # 将human标签视为AI生成的指标
62
+ ai_probability = float(probabilities[0][human_label_idx].item())
63
+ elif ai_label_idx is not None:
64
+ # 如果有AI标签
65
+ ai_probability = float(probabilities[0][ai_label_idx].item())
66
+ else:
67
+ # 默认使用索引1作为AI标签
68
+ ai_probability = 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
+ return ai_probability
110
+
111
  def analyze_image_features(image):
112
+ """分析图像特征"""
113
  # 转换为OpenCV格式
114
  img_array = np.array(image)
115
  if len(img_array.shape) == 3 and img_array.shape[2] == 3:
 
129
  features["avg_red"] = float(np.mean(img_array[:,:,0]))
130
  features["avg_green"] = float(np.mean(img_array[:,:,1]))
131
  features["avg_blue"] = float(np.mean(img_array[:,:,2]))
132
+
133
+ # 颜色标准差 - 用于检测颜色分布是否自然
134
+ features["color_std"] = float(np.std([
135
+ features["avg_red"],
136
+ features["avg_green"],
137
+ features["avg_blue"]
138
+ ]))
139
 
140
  # 边缘一致性分析
141
  edges = cv2.Canny(img_cv, 100, 200)
 
154
  # 计算GLCM属性
155
  features["texture_contrast"] = float(np.mean(graycoprops(glcm, 'contrast')[0]))
156
  features["texture_homogeneity"] = float(np.mean(graycoprops(glcm, 'homogeneity')[0]))
157
+ features["texture_correlation"] = float(np.mean(graycoprops(glcm, 'correlation')[0]))
158
+ features["texture_energy"] = float(np.mean(graycoprops(glcm, 'energy')[0]))
159
 
160
  # 噪声分析
161
  if len(img_array.shape) == 3:
162
  blurred = cv2.GaussianBlur(img_cv, (5, 5), 0)
163
  noise = cv2.absdiff(img_cv, blurred)
164
  features["noise_level"] = float(np.mean(noise))
165
+
166
+ # 噪声分布 - 用于检测噪声是否自然
167
+ features["noise_std"] = float(np.std(noise))
168
+
169
+ # 对称性分析 - AI生成图像通常有更高的对称性
170
+ if img_cv.shape[1] % 2 == 0: # 确保宽度是偶数
171
+ left_half = img_cv[:, :img_cv.shape[1]//2]
172
+ right_half = cv2.flip(img_cv[:, img_cv.shape[1]//2:], 1)
173
+ if left_half.shape == right_half.shape:
174
+ h_symmetry = 1 - float(np.mean(cv2.absdiff(left_half, right_half)) / 255)
175
+ features["horizontal_symmetry"] = h_symmetry
176
+
177
+ if img_cv.shape[0] % 2 == 0: # 确保高度是偶数
178
+ top_half = img_cv[:img_cv.shape[0]//2, :]
179
+ bottom_half = cv2.flip(img_cv[img_cv.shape[0]//2:, :], 0)
180
+ if top_half.shape == bottom_half.shape:
181
+ v_symmetry = 1 - float(np.mean(cv2.absdiff(top_half, bottom_half)) / 255)
182
+ features["vertical_symmetry"] = v_symmetry
183
+
184
+ # 频率域分析 - 检测不自然的频率分布
185
+ if len(img_array.shape) == 3:
186
+ gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
187
+ f_transform = np.fft.fft2(gray)
188
+ f_shift = np.fft.fftshift(f_transform)
189
+ magnitude = np.log(np.abs(f_shift) + 1)
190
+
191
+ # 计算高频和低频成分的比例
192
+ h, w = magnitude.shape
193
+ center_h, center_w = h // 2, w // 2
194
+
195
+ # 低频区域 (中心区域)
196
+ low_freq_region = magnitude[center_h-h//8:center_h+h//8, center_w-w//8:center_w+w//8]
197
+ low_freq_mean = np.mean(low_freq_region)
198
+
199
+ # 高频区域 (边缘区域)
200
+ high_freq_mean = np.mean(magnitude) - low_freq_mean
201
+
202
+ features["freq_ratio"] = float(high_freq_mean / max(low_freq_mean, 0.001))
203
 
204
  return features
205
 
206
+ def detect_photoshop_signs(image_features):
207
+ """检测图像中的PS痕迹"""
208
+ ps_score = 0
209
+ ps_signs = []
210
+
211
+ # 检查皮肤质感
212
+ if "texture_homogeneity" in image_features:
213
+ if image_features["texture_homogeneity"] > 0.4:
214
+ ps_score += 0.2
215
+ ps_signs.append("皮肤质感过于均匀")
216
+ elif image_features["texture_homogeneity"] > 0.3:
217
+ ps_score += 0.1
218
+ ps_signs.append("皮肤质感较为均匀")
219
+
220
+ # 检查边缘不自然
221
+ if "edge_density" in image_features:
222
+ if image_features["edge_density"] < 0.01:
223
+ ps_score += 0.2
224
+ ps_signs.append("边缘过于平滑")
225
+ elif image_features["edge_density"] < 0.03:
226
+ ps_score += 0.1
227
+ ps_signs.append("边缘较为平滑")
228
+
229
+ # 检查颜色不自然
230
+ if "color_std" in image_features:
231
+ if image_features["color_std"] > 50:
232
+ ps_score += 0.2
233
+ ps_signs.append("颜色分布极不自然")
234
+ elif image_features["color_std"] > 30:
235
+ ps_score += 0.1
236
+ ps_signs.append("颜色分布略不自然")
237
+
238
+ # 检查噪点不一致
239
+ if "noise_level" in image_features and "noise_std" in image_features:
240
+ noise_ratio = image_features["noise_std"] / max(image_features["noise_level"], 0.001)
241
+ if noise_ratio < 0.5:
242
+ ps_score += 0.2
243
+ ps_signs.append("噪点分布不自然")
244
+ elif noise_ratio < 0.7:
245
+ ps_score += 0.1
246
+ ps_signs.append("噪点分布略不自然")
247
+
248
+ # 检查频率分布不自然
249
+ if "freq_ratio" in image_features:
250
+ if image_features["freq_ratio"] < 0.2:
251
+ ps_score += 0.2
252
+ ps_signs.append("频率分布不自然,可能有过度模糊处理")
253
+ elif image_features["freq_ratio"] > 2.0:
254
+ ps_score += 0.2
255
+ ps_signs.append("频率分布不自然,可能有过度锐化处理")
256
+
257
+ # 检查对称性不自然
258
+ if "horizontal_symmetry" in image_features and "vertical_symmetry" in image_features:
259
+ avg_symmetry = (image_features["horizontal_symmetry"] + image_features["vertical_symmetry"]) / 2
260
+ if avg_symmetry > 0.8:
261
+ ps_score += 0.2
262
+ ps_signs.append("图像对称性过高,可能经过对称处理")
263
+
264
+ return min(ps_score, 1.0), ps_signs
265
+
266
+ def get_detailed_analysis(ai_probability, ps_score, ps_signs, valid_models_count):
267
+ """提供更详细的分析结果"""
268
+
269
+ # 根据有效模型数量调整置信度描述
270
+ confidence_prefix = ""
271
+ if valid_models_count >= 3:
272
+ confidence_prefix = "极高置信度:"
273
+ elif valid_models_count == 2:
274
+ confidence_prefix = "高置信度:"
275
+ elif valid_models_count == 1:
276
+ confidence_prefix = "中等置信度:"
277
+
278
+ if ai_probability > 0.8:
279
+ category = confidence_prefix + "高概率AI生成"
280
+ description = "图像几乎可以确定是由AI完全生成,几乎没有真人照片的特征。"
281
+ elif ai_probability > 0.6:
282
+ if ps_score > 0.5:
283
+ category = confidence_prefix + "中等概率AI生成,高概率PS修图"
284
+ description = "图像可能是真人照片经过大量后期处理,或是AI生成后经过修饰的图像。"
285
+ else:
286
+ category = confidence_prefix + "中等概率AI生成"
287
+ description = "图像有较多AI生成的特征,但也保留了一些真实照片的特点。"
288
+ elif ai_probability > 0.4:
289
+ if ps_score > 0.5:
290
+ category = confidence_prefix + "低概率AI生成,高概率PS修图"
291
+ description = "图像更可能是真人照片经过大量后期处理,PS痕迹明显。"
292
+ else:
293
+ category = confidence_prefix + "低概率AI生成"
294
+ description = "图像更可能是真人照片,但有一些AI生成或修饰的特征。"
295
+ else:
296
+ if ps_score > 0.6:
297
+ category = confidence_prefix + "真人照片,重度PS修图"
298
+ description = "图像基本是真人照片,但经过了大量后期处理,修饰痕迹明显。"
299
+ elif ps_score > 0.3:
300
+ category = confidence_prefix + "真人照片,中度PS修图"
301
+ description = "图像是真人照片,有明显的后期处理痕迹。"
302
+ elif ps_score > 0.1:
303
+ category = confidence_prefix + "真人照片,轻度PS修图"
304
+ description = "图像是真人照片,有少量后期处理。"
305
+ else:
306
+ category = confidence_prefix + "高概率真人照片,几乎无修图"
307
+ description = "图像几乎可以确定是未经大量处理的真人照片。"
308
+
309
+ # 添加具体的PS痕迹描述
310
+ if ps_signs:
311
+ ps_details = "检测到的修图痕迹:" + "、".join(ps_signs)
312
+ else:
313
+ ps_details = "未检测到明显的修图痕迹。"
314
+
315
+ return category, description, ps_details
316
+
317
  def detect_ai_image(image):
318
+ """主检测函数"""
319
  if image is None:
320
  return {"error": "未提供图像"}
321
 
 
332
  with torch.no_grad():
333
  outputs = model_info["model"](**inputs)
334
 
 
 
 
 
335
  # 获取概率
336
+ probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
337
 
338
+ # 使用适配器处理不同模型的输出
339
+ ai_probability = process_model_output(model_info, outputs, probabilities)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
  # 添加到结果
342
+ predicted_class_idx = outputs.logits.argmax(-1).item()
343
  results[key] = {
344
  "model_name": model_info["name"],
345
  "ai_probability": ai_probability,
 
370
 
371
  # 低边缘密度通常表示AI生成
372
  if image_features["edge_density"] < 0.01:
373
+ adjusted_probability += 0.15
374
 
375
  # 高纹理均匀性通常表示AI生成
376
+ if "texture_homogeneity" in image_features and image_features["texture_homogeneity"] > 0.5:
377
  adjusted_probability += 0.1
378
 
379
  # 低噪声水平通常表示AI生成
380
  if image_features["noise_level"] < 0.5:
381
  adjusted_probability += 0.1
382
 
383
+ # 高对称性通常表示AI生成
384
+ if "horizontal_symmetry" in image_features and image_features["horizontal_symmetry"] > 0.8:
385
+ adjusted_probability += 0.1
386
+
387
  # 确保概率在0-1范围内
388
  adjusted_probability = min(1.0, max(0.0, adjusted_probability))
389
 
390
+ # 分析PS痕迹
391
+ ps_score, ps_signs = detect_photoshop_signs(image_features)
392
+
393
+ # 获取详细分析
394
+ category, description, ps_details = get_detailed_analysis(adjusted_probability, ps_score, ps_signs, valid_models)
 
 
395
 
396
  # 构建最终结果
397
  final_result = {
398
  "ai_probability": adjusted_probability,
399
+ "ps_score": ps_score,
400
+ "category": category,
401
+ "description": description,
402
+ "ps_details": ps_details,
403
  "individual_model_results": results,
404
  "features": image_features
405
  }
 
412
  inputs=gr.Image(type="pil"),
413
  outputs=gr.JSON(),
414
  title="增强型AI图像检测API",
415
+ description="多模型集成检测图像是否由AI生成,同时分析PS修图痕迹",
416
  examples=None,
417
  allow_flagging="never"
418
  )