Spaces:
Running
Running
Update app.py
Browse files
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.
|
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.
|
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.
|
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.
|
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.
|
449 |
ai_signs.append("局部颜色变化异常少")
|
450 |
|
451 |
# 检查边缘变化 - 真实照片的边缘通常更自然
|
452 |
if "edge_variance" in image_features and image_features["edge_variance"] < 100:
|
453 |
-
ai_score += 0.
|
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.
|
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.
|
464 |
ai_signs.append("人脸对称性异常高")
|
465 |
|
466 |
if "face_skin_std" in image_features and image_features["face_skin_std"] < 10:
|
467 |
-
ai_score += 0.
|
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.
|
473 |
ai_signs.append("衣物褶皱角度分布不自然")
|
474 |
|
475 |
if "clothing_texture_std" in image_features and image_features["clothing_texture_std"] < 100:
|
476 |
-
ai_score += 0.
|
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.
|
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.
|
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 |
)
|