aaappp7878 commited on
Commit
6e3ea05
·
verified ·
1 Parent(s): 0cdea19

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +391 -37
app.py CHANGED
@@ -4,6 +4,8 @@ from PIL import Image
4
  import numpy as np
5
  import cv2
6
  from transformers import AutoImageProcessor, AutoModelForImageClassification
 
 
7
 
8
  # 加载多个检测模型
9
  models = {
@@ -144,6 +146,17 @@ def analyze_image_features(image):
144
  patch = img_array[i:i+10, j:j+10]
145
  local_color_variations.append(np.std(patch))
146
  features["local_color_variation"] = float(np.mean(local_color_variations))
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  # 边缘一致性分析
149
  edges = cv2.Canny(img_cv, 100, 200)
@@ -156,11 +169,15 @@ def analyze_image_features(image):
156
  sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
157
  edge_magnitude = np.sqrt(sobelx**2 + sobely**2)
158
  features["edge_variance"] = float(np.var(edge_magnitude))
 
 
 
 
 
159
 
160
  # 纹理分析 - 使用灰度共生矩阵
161
  if len(img_array.shape) == 3:
162
  gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
163
- from skimage.feature import graycomatrix, graycoprops
164
 
165
  # 计算GLCM
166
  distances = [5]
@@ -174,6 +191,18 @@ def analyze_image_features(image):
174
  features["texture_energy"] = float(np.mean(graycoprops(glcm, 'energy')[0]))
175
  features["texture_dissimilarity"] = float(np.mean(graycoprops(glcm, 'dissimilarity')[0]))
176
  features["texture_ASM"] = float(np.mean(graycoprops(glcm, 'ASM')[0]))
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
  # 噪声分析
179
  if len(img_array.shape) == 3:
@@ -189,6 +218,15 @@ def analyze_image_features(image):
189
  noise_fft_shift = np.fft.fftshift(noise_fft)
190
  noise_magnitude = np.abs(noise_fft_shift)
191
  features["noise_spectrum_std"] = float(np.std(noise_magnitude))
 
 
 
 
 
 
 
 
 
192
 
193
  # 对称性分析 - AI生成图像通常有更高的对称性
194
  if img_cv.shape[1] % 2 == 0: # 确保宽度是偶数
@@ -228,6 +266,14 @@ def analyze_image_features(image):
228
  # 频率分布的自然度 - 真实照片通常有更自然的频率分布
229
  freq_std = np.std(magnitude)
230
  features["freq_std"] = float(freq_std)
 
 
 
 
 
 
 
 
231
 
232
  # 尝试检测人脸
233
  try:
@@ -256,10 +302,31 @@ def analyze_image_features(image):
256
  features["face_skin_std"] = np.mean([f["skin_std"] for f in face_features])
257
  features["face_local_contrast"] = np.mean([f["skin_local_contrast"] for f in face_features])
258
  features["face_symmetry"] = np.mean([f["face_symmetry"] for f in face_features])
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  except:
260
  # 如果人脸检测失败,不添加人脸特征
261
  pass
262
 
 
 
 
 
 
 
 
 
263
  # 分析衣物细节
264
  clothing_features = analyze_clothing_details(img_cv)
265
  features.update(clothing_features)
@@ -279,6 +346,137 @@ def analyze_face_symmetry(face):
279
  return 1 - float(np.mean(cv2.absdiff(left_half, right_half)) / 255)
280
  return 0.5 # 默认值
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  def analyze_clothing_details(image):
283
  """分析衣物细节的自然度"""
284
  features = {}
@@ -316,7 +514,7 @@ def analyze_clothing_details(image):
316
  features["clothing_angle_uniformity"] = float(max_count / max(total_count, 1))
317
 
318
  # 分析纹理的一致性
319
- # 将图像分成小块,计算每个块的纹理特征
320
  block_size = 32
321
  h, w = gray.shape
322
  texture_variations = []
@@ -333,6 +531,30 @@ def analyze_clothing_details(image):
333
 
334
  # 计算纹理变化的均值 - AI生成的衣物纹理通常变化较小
335
  features["clothing_texture_mean"] = float(np.mean(texture_variations))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  except:
337
  # 如果分析失败,不添加衣物特征
338
  pass
@@ -390,6 +612,41 @@ def analyze_extremities(image):
390
  if defect_depths:
391
  features["extremity_defect_depth_mean"] = float(np.mean(defect_depths))
392
  features["extremity_defect_depth_std"] = float(np.std(defect_depths))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  except:
394
  # 如果分析失败,不添加末端特征
395
  pass
@@ -405,7 +662,7 @@ def check_ai_specific_features(image_features):
405
  if "horizontal_symmetry" in image_features and "vertical_symmetry" in image_features:
406
  avg_symmetry = (image_features["horizontal_symmetry"] + image_features["vertical_symmetry"]) / 2
407
  if avg_symmetry > 0.8: # 提高阈值
408
- ai_score += 0.2 # 降低权重
409
  ai_signs.append("图像对称性异常高")
410
  elif avg_symmetry > 0.7:
411
  ai_score += 0.1
@@ -414,7 +671,7 @@ def check_ai_specific_features(image_features):
414
  # 检查纹理相关性 - AI生成图像通常纹理相关性高
415
  if "texture_correlation" in image_features:
416
  if image_features["texture_correlation"] > 0.95: # 提高阈值
417
- ai_score += 0.2
418
  ai_signs.append("纹理相关性异常高")
419
  elif image_features["texture_correlation"] > 0.9:
420
  ai_score += 0.1
@@ -424,68 +681,147 @@ def check_ai_specific_features(image_features):
424
  if "edge_density" in image_features and "noise_level" in image_features:
425
  edge_noise_ratio = image_features["edge_density"] / max(image_features["noise_level"], 0.001)
426
  if edge_noise_ratio < 0.01:
427
- ai_score += 0.2
428
  ai_signs.append("边缘与噪声分布不自然")
429
 
430
  # 检查颜色平滑度 - AI生成图像通常颜色过渡更平滑
431
  if "color_std" in image_features and image_features["color_std"] < 10:
432
- ai_score += 0.1 # 降低权重
433
  ai_signs.append("颜色过渡异常平滑")
434
 
 
 
 
 
 
435
  # 检查纹理能量 - AI生成图像通常纹理能量分布不自然
436
  if "texture_energy" in image_features and image_features["texture_energy"] < 0.01:
437
- ai_score += 0.2
438
  ai_signs.append("纹理能量分布不自然")
439
 
440
  # 检查频率比例 - AI生成图像通常频率分布不自然
441
  if "freq_ratio" in image_features:
442
  if image_features["freq_ratio"] < 0.1 or image_features["freq_ratio"] > 2.0:
443
- ai_score += 0.1 # 降低权重
444
  ai_signs.append("频率分布不自然")
445
 
 
 
 
 
 
446
  # 检查局部颜色变化 - 真实照片通常有更多局部颜色变化
447
  if "local_color_variation" in image_features and image_features["local_color_variation"] < 5:
448
- ai_score += 0.2
449
  ai_signs.append("局部颜色变化异常少")
450
 
451
  # 检查边缘变化 - 真实照片的边缘通常更自然
452
  if "edge_variance" in image_features and image_features["edge_variance"] < 100:
453
- ai_score += 0.2
454
  ai_signs.append("边缘变化异常均匀")
455
 
 
 
 
 
 
456
  # 检查噪声频谱 - 真实照片的噪声频谱更自然
457
  if "noise_spectrum_std" in image_features and image_features["noise_spectrum_std"] < 1000:
458
- ai_score += 0.2
459
  ai_signs.append("噪��频谱异常规则")
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  # 检查人脸特征 - AI生成的人脸通常有特定特征
462
  if "face_symmetry" in image_features and image_features["face_symmetry"] > 0.8:
463
- ai_score += 0.2
464
  ai_signs.append("人脸对称性异常高")
465
 
466
  if "face_skin_std" in image_features and image_features["face_skin_std"] < 10:
467
- ai_score += 0.3
468
  ai_signs.append("皮肤质感异常均匀")
469
 
 
 
 
 
 
 
 
 
470
  # 检查衣物特征 - AI生成的衣物通常有特定问题
471
  if "clothing_angle_uniformity" in image_features and image_features["clothing_angle_uniformity"] > 0.3:
472
- ai_score += 0.3
473
  ai_signs.append("衣物褶皱角度分布不自然")
474
 
475
  if "clothing_texture_std" in image_features and image_features["clothing_texture_std"] < 100:
476
- ai_score += 0.2
477
  ai_signs.append("衣物纹理变化异常均匀")
478
 
 
 
 
 
 
 
 
 
479
  # 检查手部特征 - AI生成的手部通常有特定问题
480
  if "extremity_perimeter_area_ratio" in image_features:
481
  if image_features["extremity_perimeter_area_ratio"] < 0.05:
482
- ai_score += 0.3
483
  ai_signs.append("手部/末端轮廓异常平滑")
484
 
485
  if "extremity_defect_depth_std" in image_features and image_features["extremity_defect_depth_std"] < 10:
486
- ai_score += 0.2
487
  ai_signs.append("手指间隙异常均匀")
488
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  return min(ai_score, 1.0), ai_signs
490
 
491
  def detect_beauty_filter_signs(image_features):
@@ -535,6 +871,19 @@ def detect_beauty_filter_signs(image_features):
535
  beauty_score += 0.1
536
  beauty_signs.append("面部对称性较高,可能使用了美颜")
537
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
  return min(beauty_score, 1.0), beauty_signs
539
 
540
  def detect_photoshop_signs(image_features):
@@ -550,7 +899,8 @@ def detect_photoshop_signs(image_features):
550
  elif image_features["texture_homogeneity"] > 0.3:
551
  ps_score += 0.1
552
  ps_signs.append("皮肤质感较为均匀")
553
- # 检查边缘不自然
 
554
  if "edge_density" in image_features:
555
  if image_features["edge_density"] < 0.01:
556
  ps_score += 0.2
@@ -587,6 +937,20 @@ def detect_photoshop_signs(image_features):
587
  ps_score += 0.2
588
  ps_signs.append("频率分布不自然,可能有过度锐化处理")
589
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  return min(ps_score, 1.0), ps_signs
591
 
592
  def get_detailed_analysis(ai_probability, ps_score, beauty_score, ps_signs, ai_signs, beauty_signs, valid_models_count):
@@ -740,28 +1104,18 @@ def detect_ai_image(image):
740
  if "extremity_perimeter_area_ratio" in image_features and image_features["extremity_perimeter_area_ratio"] < 0.05:
741
  adjusted_probability = max(adjusted_probability, 0.7)
742
 
 
 
 
 
 
 
 
 
743
  # 如果美颜分数高但AI特征分数不高,降低AI概率
744
  if beauty_score > 0.6 and ai_feature_score < 0.5:
745
  adjusted_probability = min(adjusted_probability, 0.5)
746
 
747
- # 高对称性是AI生成的指标,但权重降低
748
- if "horizontal_symmetry" in image_features and image_features["horizontal_symmetry"] > 0.8:
749
- adjusted_probability += 0.1
750
- if "vertical_symmetry" in image_features and image_features["vertical_symmetry"] > 0.8:
751
- adjusted_probability += 0.1
752
-
753
- # 高纹理相关性通常表示AI生成
754
- if "texture_correlation" in image_features and image_features["texture_correlation"] > 0.95:
755
- adjusted_probability += 0.1
756
-
757
- # 低边缘密度通常表示AI生成
758
- if image_features["edge_density"] < 0.01:
759
- adjusted_probability += 0.1
760
-
761
- # 如果检测到人脸特征异常,增加AI概率
762
- if "face_skin_std" in image_features and image_features["face_skin_std"] < 10:
763
- adjusted_probability += 0.2
764
-
765
  # 确保概率在0-1范围内
766
  adjusted_probability = min(1.0, max(0.0, adjusted_probability))
767
 
@@ -801,7 +1155,7 @@ iface = gr.Interface(
801
  inputs=gr.Image(type="pil"),
802
  outputs=gr.JSON(),
803
  title="增强型AI图像检测API",
804
- description="多模型集成检测图像是否由AI生成,同时分析PS修图和美颜痕迹,特别关注衣物和手部等细节问题",
805
  examples=None,
806
  allow_flagging="never"
807
  )
 
4
  import numpy as np
5
  import cv2
6
  from transformers import AutoImageProcessor, AutoModelForImageClassification
7
+ from skimage.feature import graycomatrix, graycoprops, local_binary_pattern
8
+ from scipy import ndimage, stats
9
 
10
  # 加载多个检测模型
11
  models = {
 
146
  patch = img_array[i:i+10, j:j+10]
147
  local_color_variations.append(np.std(patch))
148
  features["local_color_variation"] = float(np.mean(local_color_variations))
149
+
150
+ # 颜色分布的自然度 - 真实照片的颜色分布更自然
151
+ r_hist, _ = np.histogram(img_array[:,:,0], bins=256, range=(0, 256))
152
+ g_hist, _ = np.histogram(img_array[:,:,1], bins=256, range=(0, 256))
153
+ b_hist, _ = np.histogram(img_array[:,:,2], bins=256, range=(0, 256))
154
+
155
+ # 计算颜色直方图的熵 - 真实照片通常熵值更高
156
+ r_entropy = stats.entropy(r_hist + 1e-10) # 添加小值避免log(0)
157
+ g_entropy = stats.entropy(g_hist + 1e-10)
158
+ b_entropy = stats.entropy(b_hist + 1e-10)
159
+ features["color_entropy"] = float((r_entropy + g_entropy + b_entropy) / 3)
160
 
161
  # 边缘一致性分析
162
  edges = cv2.Canny(img_cv, 100, 200)
 
169
  sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
170
  edge_magnitude = np.sqrt(sobelx**2 + sobely**2)
171
  features["edge_variance"] = float(np.var(edge_magnitude))
172
+
173
+ # 边缘方向分布 - 真实照片的边缘方向分布更自然
174
+ edge_direction = np.arctan2(sobely, sobelx) * 180 / np.pi
175
+ edge_dir_hist, _ = np.histogram(edge_direction[edge_magnitude > 30], bins=36, range=(-180, 180))
176
+ features["edge_direction_entropy"] = float(stats.entropy(edge_dir_hist + 1e-10))
177
 
178
  # 纹理分析 - 使用灰度共生矩阵
179
  if len(img_array.shape) == 3:
180
  gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
 
181
 
182
  # 计算GLCM
183
  distances = [5]
 
191
  features["texture_energy"] = float(np.mean(graycoprops(glcm, 'energy')[0]))
192
  features["texture_dissimilarity"] = float(np.mean(graycoprops(glcm, 'dissimilarity')[0]))
193
  features["texture_ASM"] = float(np.mean(graycoprops(glcm, 'ASM')[0]))
194
+
195
+ # 局部二值模式 (LBP) - 分析微观纹理
196
+ try:
197
+ radius = 3
198
+ n_points = 8 * radius
199
+ lbp = local_binary_pattern(gray, n_points, radius, method='uniform')
200
+ lbp_hist, _ = np.histogram(lbp, bins=n_points + 2, range=(0, n_points + 2))
201
+ lbp_hist = lbp_hist.astype(float) / sum(lbp_hist)
202
+ features["lbp_entropy"] = float(stats.entropy(lbp_hist + 1e-10))
203
+ except:
204
+ # 如果LBP分析失败,不添加这个特征
205
+ pass
206
 
207
  # 噪声分析
208
  if len(img_array.shape) == 3:
 
218
  noise_fft_shift = np.fft.fftshift(noise_fft)
219
  noise_magnitude = np.abs(noise_fft_shift)
220
  features["noise_spectrum_std"] = float(np.std(noise_magnitude))
221
+
222
+ # 噪声的空间一致性 - AI生成图像的噪声空间分布通常不够自然
223
+ noise_blocks = []
224
+ block_size = 32
225
+ for i in range(0, noise.shape[0]-block_size, block_size):
226
+ for j in range(0, noise.shape[1]-block_size, block_size):
227
+ block = noise[i:i+block_size, j:j+block_size]
228
+ noise_blocks.append(np.mean(block))
229
+ features["noise_spatial_std"] = float(np.std(noise_blocks))
230
 
231
  # 对称性分析 - AI生成图像通常有更高的对称性
232
  if img_cv.shape[1] % 2 == 0: # 确保宽度是偶数
 
266
  # 频率分布的自然度 - 真实照片通常有更自然的频率分布
267
  freq_std = np.std(magnitude)
268
  features["freq_std"] = float(freq_std)
269
+
270
+ # 频率分布的各向异性 - 真实照片的频率分布通常更各向异性
271
+ freq_blocks = []
272
+ for angle in range(0, 180, 20):
273
+ mask = np.zeros_like(magnitude)
274
+ cv2.ellipse(mask, (center_w, center_h), (w//2, h//2), angle, -10, 10, 1, -1)
275
+ freq_blocks.append(np.mean(magnitude * mask))
276
+ features["freq_anisotropy"] = float(np.std(freq_blocks))
277
 
278
  # 尝试检测人脸
279
  try:
 
302
  features["face_skin_std"] = np.mean([f["skin_std"] for f in face_features])
303
  features["face_local_contrast"] = np.mean([f["skin_local_contrast"] for f in face_features])
304
  features["face_symmetry"] = np.mean([f["face_symmetry"] for f in face_features])
305
+
306
+ # 面部微表情分析
307
+ for i, (x, y, w, h) in enumerate(faces):
308
+ face = gray[y:y+h, x:x+w]
309
+ # 分析面部纹理的局部变化
310
+ face_blocks = []
311
+ block_size = 8
312
+ for bi in range(0, face.shape[0]-block_size, block_size):
313
+ for bj in range(0, face.shape[1]-block_size, block_size):
314
+ block = face[bi:bi+block_size, bj:bj+block_size]
315
+ face_blocks.append(np.std(block))
316
+ if face_blocks:
317
+ features[f"face_{i}_texture_variation"] = float(np.std(face_blocks))
318
  except:
319
  # 如果人脸检测失败,不添加人脸特征
320
  pass
321
 
322
+ # 分析物理一致性
323
+ physical_features = analyze_physical_consistency(img_cv)
324
+ features.update(physical_features)
325
+
326
+ # 分析细节连贯性
327
+ detail_features = analyze_detail_coherence(img_cv)
328
+ features.update(detail_features)
329
+
330
  # 分析衣物细节
331
  clothing_features = analyze_clothing_details(img_cv)
332
  features.update(clothing_features)
 
346
  return 1 - float(np.mean(cv2.absdiff(left_half, right_half)) / 255)
347
  return 0.5 # 默认值
348
 
349
+ def analyze_physical_consistency(image):
350
+ """分析图像中的物理一致性"""
351
+ features = {}
352
+
353
+ try:
354
+ # 转换为灰度图
355
+ if len(image.shape) == 3:
356
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
357
+ else:
358
+ gray = image
359
+
360
+ # 光影一致性分析
361
+ # 检测亮度梯度
362
+ sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
363
+ sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
364
+ gradient_magnitude = np.sqrt(sobelx**2 + sobely**2)
365
+ gradient_direction = np.arctan2(sobely, sobelx)
366
+
367
+ # 分析梯度方向的一致性 - 真实照片的光影梯度方向更一致
368
+ # 将图像分成块,分析每个块的主要梯度方向
369
+ block_size = 32
370
+ gradient_dirs = []
371
+ for i in range(0, gray.shape[0]-block_size, block_size):
372
+ for j in range(0, gray.shape[1]-block_size, block_size):
373
+ block_gradient = gradient_direction[i:i+block_size, j:j+block_size]
374
+ block_magnitude = gradient_magnitude[i:i+block_size, j:j+block_size]
375
+ # 只考虑梯度幅值较大的像素
376
+ significant_gradients = block_gradient[block_magnitude > np.mean(block_magnitude)]
377
+ if len(significant_gradients) > 0:
378
+ # 计算主要方向
379
+ hist, _ = np.histogram(significant_gradients, bins=8, range=(-np.pi, np.pi))
380
+ main_dir = np.argmax(hist)
381
+ gradient_dirs.append(main_dir)
382
+
383
+ if gradient_dirs:
384
+ # 计算主要方向的一致性
385
+ hist, _ = np.histogram(gradient_dirs, bins=8, range=(0, 8))
386
+ features["light_direction_consistency"] = float(np.max(hist) / max(sum(hist), 1))
387
+
388
+ # 透视一致性分析
389
+ # 使用霍夫变换检测直线
390
+ edges = cv2.Canny(gray, 50, 150)
391
+ lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=50, minLineLength=50, maxLineGap=10)
392
+
393
+ if lines is not None and len(lines) > 1:
394
+ # 分析消失点
395
+ vanishing_points = []
396
+ for i in range(len(lines)):
397
+ for j in range(i+1, len(lines)):
398
+ x1, y1, x2, y2 = lines[i][0]
399
+ x3, y3, x4, y4 = lines[j][0]
400
+
401
+ # 计算两条线的交点(可能的消失点)
402
+ d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
403
+ if abs(d) > 0.001: # 避免平行线
404
+ px = ((x1*y2 - y1*x2)*(x3-x4) - (x1-x2)*(x3*y4 - y3*x4)) / d
405
+ py = ((x1*y2 - y1*x2)*(y3-y4) - (y1-y2)*(x3*y4 - y3*x4)) / d
406
+
407
+ # 只考虑图像范围内或附近的交点
408
+ img_diag = np.sqrt(gray.shape[0]**2 + gray.shape[1]**2)
409
+ if -img_diag < px < 2*gray.shape[1] and -img_diag < py < 2*gray.shape[0]:
410
+ vanishing_points.append((px, py))
411
+
412
+ if vanishing_points:
413
+ # 分析消失点的聚集程度 - 真实照片的消失点通常更聚集
414
+ vp_x = [p[0] for p in vanishing_points]
415
+ vp_y = [p[1] for p in vanishing_points]
416
+ features["perspective_consistency"] = float(1 / (1 + np.std(vp_x) + np.std(vp_y)))
417
+ except:
418
+ # 如果分析失败,不添加物理一致性特征
419
+ pass
420
+
421
+ return features
422
+
423
+ def analyze_detail_coherence(image):
424
+ """分析图像细节的连贯性"""
425
+ features = {}
426
+
427
+ try:
428
+ # 转换为灰度图
429
+ if len(image.shape) == 3:
430
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
431
+ else:
432
+ gray = image
433
+
434
+ # 多尺度细节��析
435
+ scales = [3, 5, 9]
436
+ detail_levels = []
437
+
438
+ for scale in scales:
439
+ # 使用不同尺度的拉普拉斯算子提取细节
440
+ laplacian = cv2.Laplacian(gray, cv2.CV_64F, ksize=scale)
441
+ abs_laplacian = np.abs(laplacian)
442
+ detail_levels.append(np.mean(abs_laplacian))
443
+
444
+ # 计算细节随尺度变化的一致性 - 真实照片的细节随尺度变化更自然
445
+ if len(detail_levels) > 1:
446
+ features["detail_scale_consistency"] = float(np.std(detail_levels) / max(np.mean(detail_levels), 0.001))
447
+
448
+ # 分析图像不同区域的细节一致性
449
+ block_size = 64
450
+ detail_blocks = []
451
+
452
+ for i in range(0, gray.shape[0]-block_size, block_size):
453
+ for j in range(0, gray.shape[1]-block_size, block_size):
454
+ block = gray[i:i+block_size, j:j+block_size]
455
+ # 计算块的细节水平
456
+ block_laplacian = cv2.Laplacian(block, cv2.CV_64F)
457
+ detail_blocks.append(np.mean(np.abs(block_laplacian)))
458
+
459
+ if detail_blocks:
460
+ # 计算细节分布的均匀性 - AI生成图像的细节分布通常不够均匀
461
+ features["detail_spatial_std"] = float(np.std(detail_blocks))
462
+ features["detail_spatial_entropy"] = float(stats.entropy(detail_blocks + 1e-10))
463
+
464
+ # 边缘过渡分析
465
+ edges = cv2.Canny(gray, 50, 150)
466
+ dilated = cv2.dilate(edges, np.ones((3,3), np.uint8))
467
+ edge_transition = cv2.absdiff(dilated, edges)
468
+
469
+ # 计算边缘过渡区域的特性 - 真实照片的边缘过渡更自然
470
+ if np.sum(edge_transition) > 0:
471
+ transition_values = gray[edge_transition > 0]
472
+ if len(transition_values) > 0:
473
+ features["edge_transition_std"] = float(np.std(transition_values))
474
+ except:
475
+ # 如果分析失败,不添加细节连贯性特征
476
+ pass
477
+
478
+ return features
479
+
480
  def analyze_clothing_details(image):
481
  """分析衣物细节的自然度"""
482
  features = {}
 
514
  features["clothing_angle_uniformity"] = float(max_count / max(total_count, 1))
515
 
516
  # 分析纹理的一致性
517
+ # 将图像分成小块,计算每个块的纹理特征
518
  block_size = 32
519
  h, w = gray.shape
520
  texture_variations = []
 
531
 
532
  # 计算纹理变化的均值 - AI生成的衣物纹理通常变化较小
533
  features["clothing_texture_mean"] = float(np.mean(texture_variations))
534
+
535
+ # 计算纹理变化的熵 - 真实衣物纹理变化的熵更高
536
+ features["clothing_texture_entropy"] = float(stats.entropy(texture_variations + 1e-10))
537
+ # 褶皱分析 - 使用形态学操作提取可能的褶皱
538
+ _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
539
+ kernel = np.ones((3,3), np.uint8)
540
+ opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
541
+
542
+ # 寻找轮廓
543
+ contours, _ = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
544
+
545
+ # 分析轮廓的复杂度
546
+ if contours:
547
+ contour_complexities = []
548
+ for contour in contours:
549
+ area = cv2.contourArea(contour)
550
+ if area > 100: # 忽略太小的轮廓
551
+ perimeter = cv2.arcLength(contour, True)
552
+ complexity = perimeter / max(np.sqrt(area), 1)
553
+ contour_complexities.append(complexity)
554
+
555
+ if contour_complexities:
556
+ features["clothing_contour_complexity"] = float(np.mean(contour_complexities))
557
+ features["clothing_contour_std"] = float(np.std(contour_complexities))
558
  except:
559
  # 如果分析失败,不添加衣物特征
560
  pass
 
612
  if defect_depths:
613
  features["extremity_defect_depth_mean"] = float(np.mean(defect_depths))
614
  features["extremity_defect_depth_std"] = float(np.std(defect_depths))
615
+
616
+ # 分析缺陷的分布 - 真实手指的缺陷分布更自然
617
+ defect_hist, _ = np.histogram(defect_depths, bins=10)
618
+ features["extremity_defect_entropy"] = float(stats.entropy(defect_hist + 1e-10))
619
+
620
+ # 分析轮廓的曲率变化 - 真实手指的曲率变化更自然
621
+ curvature_variations = []
622
+ for contour in contours:
623
+ if len(contour) > 20: # 需要足够多的点来计算曲率
624
+ # 简化轮廓以减少噪声
625
+ epsilon = 0.01 * cv2.arcLength(contour, True)
626
+ approx = cv2.approxPolyDP(contour, epsilon, True)
627
+
628
+ # 计算相邻点之间的角度变化
629
+ angles = []
630
+ for i in range(len(approx)):
631
+ p1 = approx[i][0]
632
+ p2 = approx[(i+1) % len(approx)][0]
633
+ p3 = approx[(i+2) % len(approx)][0]
634
+
635
+ # 计算两个向量之间的角度
636
+ v1 = p2 - p1
637
+ v2 = p3 - p2
638
+
639
+ if np.linalg.norm(v1) > 0 and np.linalg.norm(v2) > 0:
640
+ cos_angle = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
641
+ cos_angle = np.clip(cos_angle, -1.0, 1.0) # 确保在有效范围内
642
+ angle = np.arccos(cos_angle)
643
+ angles.append(angle)
644
+
645
+ if angles:
646
+ curvature_variations.append(np.std(angles))
647
+
648
+ if curvature_variations:
649
+ features["extremity_curvature_std"] = float(np.mean(curvature_variations))
650
  except:
651
  # 如果分析失败,不添加末端特征
652
  pass
 
662
  if "horizontal_symmetry" in image_features and "vertical_symmetry" in image_features:
663
  avg_symmetry = (image_features["horizontal_symmetry"] + image_features["vertical_symmetry"]) / 2
664
  if avg_symmetry > 0.8: # 提高阈值
665
+ ai_score += 0.15 # 降低权重
666
  ai_signs.append("图像对称性异常高")
667
  elif avg_symmetry > 0.7:
668
  ai_score += 0.1
 
671
  # 检查纹理相关性 - AI生成图像通常纹理相关性高
672
  if "texture_correlation" in image_features:
673
  if image_features["texture_correlation"] > 0.95: # 提高阈值
674
+ ai_score += 0.15
675
  ai_signs.append("纹理相关性异常高")
676
  elif image_features["texture_correlation"] > 0.9:
677
  ai_score += 0.1
 
681
  if "edge_density" in image_features and "noise_level" in image_features:
682
  edge_noise_ratio = image_features["edge_density"] / max(image_features["noise_level"], 0.001)
683
  if edge_noise_ratio < 0.01:
684
+ ai_score += 0.15
685
  ai_signs.append("边缘与噪声分布不自然")
686
 
687
  # 检查颜色平滑度 - AI生成图像通常颜色过渡更平滑
688
  if "color_std" in image_features and image_features["color_std"] < 10:
689
+ ai_score += 0.1
690
  ai_signs.append("颜色过渡异常平滑")
691
 
692
+ # 检查颜色熵 - AI生成图像通常颜色熵较低
693
+ if "color_entropy" in image_features and image_features["color_entropy"] < 5:
694
+ ai_score += 0.15
695
+ ai_signs.append("颜色分布熵值异常低")
696
+
697
  # 检查纹理能量 - AI生成图像通常纹理能量分布不自然
698
  if "texture_energy" in image_features and image_features["texture_energy"] < 0.01:
699
+ ai_score += 0.15
700
  ai_signs.append("纹理能量分布不自然")
701
 
702
  # 检查频率比例 - AI生成图像通常频率分布不自然
703
  if "freq_ratio" in image_features:
704
  if image_features["freq_ratio"] < 0.1 or image_features["freq_ratio"] > 2.0:
705
+ ai_score += 0.1
706
  ai_signs.append("频率分布不自然")
707
 
708
+ # 检查频率各向异性 - AI生成图像通常频率分布各向异性较低
709
+ if "freq_anisotropy" in image_features and image_features["freq_anisotropy"] < 0.5:
710
+ ai_score += 0.15
711
+ ai_signs.append("频率分布各向异性异常低")
712
+
713
  # 检查局部颜色变化 - 真实照片通常有更多局部颜色变化
714
  if "local_color_variation" in image_features and image_features["local_color_variation"] < 5:
715
+ ai_score += 0.15
716
  ai_signs.append("局部颜色变化异常少")
717
 
718
  # 检查边缘变化 - 真实照片的边缘通常更自然
719
  if "edge_variance" in image_features and image_features["edge_variance"] < 100:
720
+ ai_score += 0.15
721
  ai_signs.append("边缘变化异常均匀")
722
 
723
+ # 检查边缘方向熵 - 真实照片的边缘方向熵通常更高
724
+ if "edge_direction_entropy" in image_features and image_features["edge_direction_entropy"] < 1.5:
725
+ ai_score += 0.15
726
+ ai_signs.append("边缘方向熵异常低")
727
+
728
  # 检查噪声频谱 - 真实照片的噪声频谱更自然
729
  if "noise_spectrum_std" in image_features and image_features["noise_spectrum_std"] < 1000:
730
+ ai_score += 0.15
731
  ai_signs.append("噪��频谱异常规则")
732
 
733
+ # 检查噪声空间分布 - 真实照片的噪声空间分布更自然
734
+ if "noise_spatial_std" in image_features and image_features["noise_spatial_std"] < 0.5:
735
+ ai_score += 0.15
736
+ ai_signs.append("噪声空间分布异常均匀")
737
+
738
+ # 检查细节尺度一致性 - AI生成图像的细节尺度一致性通常不够自然
739
+ if "detail_scale_consistency" in image_features and image_features["detail_scale_consistency"] < 0.2:
740
+ ai_score += 0.15
741
+ ai_signs.append("细节尺度变化异常均匀")
742
+
743
+ # 检查细节空间分布 - AI生成图像的细节空间分布通常不够自然
744
+ if "detail_spatial_std" in image_features and image_features["detail_spatial_std"] < 5:
745
+ ai_score += 0.15
746
+ ai_signs.append("细节空间分布异常均匀")
747
+
748
+ # 检查细节空间熵 - AI生成图像的细节空间熵通常较低
749
+ if "detail_spatial_entropy" in image_features and image_features["detail_spatial_entropy"] < 1.5:
750
+ ai_score += 0.15
751
+ ai_signs.append("细节空间熵异常低")
752
+
753
+ # 检查边缘过渡 - AI生成图像的边缘过渡通常不够自然
754
+ if "edge_transition_std" in image_features and image_features["edge_transition_std"] < 10:
755
+ ai_score += 0.15
756
+ ai_signs.append("边缘过渡异常均匀")
757
+
758
+ # 检查光影一致性 - AI生成图像的光影一致性通常过高
759
+ if "light_direction_consistency" in image_features and image_features["light_direction_consistency"] > 0.7:
760
+ ai_score += 0.15
761
+ ai_signs.append("光影方向一致性异常高")
762
+
763
+ # 检查透视一致性 - AI生成图像的透视一致性通常过高
764
+ if "perspective_consistency" in image_features and image_features["perspective_consistency"] > 0.7:
765
+ ai_score += 0.15
766
+ ai_signs.append("透视一致性异常高")
767
+
768
  # 检查人脸特征 - AI生成的人脸通常有特定特征
769
  if "face_symmetry" in image_features and image_features["face_symmetry"] > 0.8:
770
+ ai_score += 0.15
771
  ai_signs.append("人脸对称性异常高")
772
 
773
  if "face_skin_std" in image_features and image_features["face_skin_std"] < 10:
774
+ ai_score += 0.2
775
  ai_signs.append("皮肤质感异常均匀")
776
 
777
+ # 检查面部纹理变化 - AI生成的面部纹理变化通常不够自然
778
+ face_texture_keys = [k for k in image_features.keys() if k.startswith("face_") and k.endswith("_texture_variation")]
779
+ if face_texture_keys:
780
+ face_texture_variations = [image_features[k] for k in face_texture_keys]
781
+ if np.mean(face_texture_variations) < 5:
782
+ ai_score += 0.2
783
+ ai_signs.append("面部纹理变化异常均匀")
784
+
785
  # 检查衣物特征 - AI生成的衣物通常有特定问题
786
  if "clothing_angle_uniformity" in image_features and image_features["clothing_angle_uniformity"] > 0.3:
787
+ ai_score += 0.2
788
  ai_signs.append("衣物褶皱角度分布不自然")
789
 
790
  if "clothing_texture_std" in image_features and image_features["clothing_texture_std"] < 100:
791
+ ai_score += 0.15
792
  ai_signs.append("衣物纹理变化异常均匀")
793
 
794
+ if "clothing_texture_entropy" in image_features and image_features["clothing_texture_entropy"] < 1.5:
795
+ ai_score += 0.15
796
+ ai_signs.append("衣物纹理熵异常低")
797
+
798
+ if "clothing_contour_complexity" in image_features and image_features["clothing_contour_complexity"] < 5:
799
+ ai_score += 0.15
800
+ ai_signs.append("衣物轮廓复杂度异常低")
801
+
802
  # 检查手部特征 - AI生成的手部通常有特定问题
803
  if "extremity_perimeter_area_ratio" in image_features:
804
  if image_features["extremity_perimeter_area_ratio"] < 0.05:
805
+ ai_score += 0.2
806
  ai_signs.append("手部/末端轮廓异常平滑")
807
 
808
  if "extremity_defect_depth_std" in image_features and image_features["extremity_defect_depth_std"] < 10:
809
+ ai_score += 0.15
810
  ai_signs.append("手指间隙异常均匀")
811
 
812
+ if "extremity_defect_entropy" in image_features and image_features["extremity_defect_entropy"] < 1.0:
813
+ ai_score += 0.15
814
+ ai_signs.append("手指间隙分布熵异常低")
815
+
816
+ if "extremity_curvature_std" in image_features and image_features["extremity_curvature_std"] < 0.2:
817
+ ai_score += 0.15
818
+ ai_signs.append("手部曲率变化异常均匀")
819
+
820
+ # 微观纹理分析 - AI生成图像的微观纹理通常不够自然
821
+ if "lbp_entropy" in image_features and image_features["lbp_entropy"] < 3.0:
822
+ ai_score += 0.2
823
+ ai_signs.append("微观纹理熵异常低")
824
+
825
  return min(ai_score, 1.0), ai_signs
826
 
827
  def detect_beauty_filter_signs(image_features):
 
871
  beauty_score += 0.1
872
  beauty_signs.append("面部对称性较高,可能使用了美颜")
873
 
874
+ # 检查面部纹理变化 - 美颜通常会使面部纹理更均匀
875
+ face_texture_keys = [k for k in image_features.keys() if k.startswith("face_") and k.endswith("_texture_variation")]
876
+ if face_texture_keys:
877
+ face_texture_variations = [image_features[k] for k in face_texture_keys]
878
+ if np.mean(face_texture_variations) < 10:
879
+ beauty_score += 0.2
880
+ beauty_signs.append("面部纹理变化异常均匀,典型美颜特征")
881
+
882
+ # 检查边缘过渡 - 美颜通常会使边缘过渡更平滑
883
+ if "edge_transition_std" in image_features and image_features["edge_transition_std"] < 15:
884
+ beauty_score += 0.2
885
+ beauty_signs.append("边缘过渡异常平滑,典型美颜特征")
886
+
887
  return min(beauty_score, 1.0), beauty_signs
888
 
889
  def detect_photoshop_signs(image_features):
 
899
  elif image_features["texture_homogeneity"] > 0.3:
900
  ps_score += 0.1
901
  ps_signs.append("皮肤质感较为均匀")
902
+
903
+ # 检查边缘不自然
904
  if "edge_density" in image_features:
905
  if image_features["edge_density"] < 0.01:
906
  ps_score += 0.2
 
937
  ps_score += 0.2
938
  ps_signs.append("频率分布不自然,可能有过度锐化处理")
939
 
940
+ # 检查细节不一致
941
+ if "detail_spatial_std" in image_features and image_features["detail_spatial_std"] > 50:
942
+ ps_score += 0.2
943
+ ps_signs.append("图像细节分布不一致,可能有局部修饰")
944
+
945
+ # 检查边缘过渡不自然
946
+ if "edge_transition_std" in image_features:
947
+ if image_features["edge_transition_std"] > 50:
948
+ ps_score += 0.2
949
+ ps_signs.append("边缘过渡不自然,可能有选区修饰")
950
+ elif image_features["edge_transition_std"] < 5:
951
+ ps_score += 0.2
952
+ ps_signs.append("边缘过渡过于平滑,可能有过度修饰")
953
+
954
  return min(ps_score, 1.0), ps_signs
955
 
956
  def get_detailed_analysis(ai_probability, ps_score, beauty_score, ps_signs, ai_signs, beauty_signs, valid_models_count):
 
1104
  if "extremity_perimeter_area_ratio" in image_features and image_features["extremity_perimeter_area_ratio"] < 0.05:
1105
  adjusted_probability = max(adjusted_probability, 0.7)
1106
 
1107
+ # 如果检测到微观纹理异常,提高AI概率
1108
+ if "lbp_entropy" in image_features and image_features["lbp_entropy"] < 3.0:
1109
+ adjusted_probability = max(adjusted_probability, 0.6)
1110
+
1111
+ # 如果检测到频率分布异常,提高AI概率
1112
+ if "freq_anisotropy" in image_features and image_features["freq_anisotropy"] < 0.5:
1113
+ adjusted_probability = max(adjusted_probability, 0.6)
1114
+
1115
  # 如果美颜分数高但AI特征分数不高,降低AI概率
1116
  if beauty_score > 0.6 and ai_feature_score < 0.5:
1117
  adjusted_probability = min(adjusted_probability, 0.5)
1118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1119
  # 确保概率在0-1范围内
1120
  adjusted_probability = min(1.0, max(0.0, adjusted_probability))
1121
 
 
1155
  inputs=gr.Image(type="pil"),
1156
  outputs=gr.JSON(),
1157
  title="增强型AI图像检测API",
1158
+ description="多模型集成检测图像是否由AI生成,同时分析PS修图和美颜痕迹,特别关注通用细节特征",
1159
  examples=None,
1160
  allow_flagging="never"
1161
  )