File size: 11,105 Bytes
4b6a001
 
 
 
e8ef8e8
22d466a
4b6a001
e8ef8e8
 
 
 
 
 
071497b
e8ef8e8
 
071497b
e8ef8e8
 
071497b
e8ef8e8
 
071497b
e8ef8e8
 
071497b
4b6a001
e8ef8e8
 
 
 
 
 
 
 
 
 
 
 
4b6a001
071497b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4b6a001
e8ef8e8
4b6a001
e8ef8e8
 
 
 
 
 
4b6a001
 
 
 
 
 
 
e8ef8e8
4b6a001
 
 
 
e8ef8e8
 
 
 
 
 
 
c68418d
0d119a8
 
 
 
 
 
 
 
 
e8ef8e8
 
 
 
 
 
 
071497b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4b6a001
e8ef8e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
071497b
e8ef8e8
071497b
 
e8ef8e8
 
071497b
e8ef8e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
071497b
 
 
 
e8ef8e8
 
 
 
071497b
 
e8ef8e8
 
 
071497b
 
e8ef8e8
 
 
 
 
 
 
4b6a001
 
 
 
 
e8ef8e8
 
f16fd05
e8ef8e8
4b6a001
 
071497b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import gradio as gr
import torch
from PIL import Image
import numpy as np
import cv2
from transformers import AutoImageProcessor, AutoModelForImageClassification

# 加载多个检测模型
models = {
    "model1": {
        "name": "umm-maybe/AI-image-detector",
        "processor": None,
        "model": None,
        "weight": 0.5
    },
    "model2": {
        "name": "microsoft/resnet-50",  # 通用图像分类模型
        "processor": None,
        "model": None,
        "weight": 0.25
    },
    "model3": {
        "name": "google/vit-base-patch16-224",  # Vision Transformer模型
        "processor": None,
        "model": None,
        "weight": 0.25
    }
}

# 初始化模型
for key in models:
    try:
        models[key]["processor"] = AutoImageProcessor.from_pretrained(models[key]["name"])
        models[key]["model"] = AutoModelForImageClassification.from_pretrained(models[key]["name"])
        print(f"成功加载模型: {models[key]['name']}")
    except Exception as e:
        print(f"加载模型 {models[key]['name']} 失败: {str(e)}")
        models[key]["processor"] = None
        models[key]["model"] = None

def process_model_output(model_info, outputs, probabilities):
    """处理不同模型的输出,统一返回AI生成概率"""
    model_name = model_info["name"].lower()
    
    # 针对不同模型的特殊处理
    if "ai-image-detector" in model_name:
        # umm-maybe/AI-image-detector模型特殊处理
        # 检查标签
        ai_label_idx = None
        human_label_idx = None
        
        for idx, label in model_info["model"].config.id2label.items():
            label_lower = label.lower()
            if "ai" in label_lower or "generated" in label_lower or "fake" in label_lower:
                ai_label_idx = idx
            if "human" in label_lower or "real" in label_lower:
                human_label_idx = idx
        
        # 根据标签确定AI概率
        if human_label_idx is not None:
            # 如果有human标签,AI概率是1减去human概率
            return 1 - float(probabilities[0][human_label_idx].item())
        elif ai_label_idx is not None:
            # 如果有AI标签
            return float(probabilities[0][ai_label_idx].item())
        else:
            # 默认使用索引1作为AI标签
            return float(probabilities[0][1].item())
    
    elif "resnet" in model_name:
        # 通用图像分类模型,使用简单启发式方法
        predicted_class_idx = outputs.logits.argmax(-1).item()
        # 检查是否有与AI相关的类别
        predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
        
        # 简单启发式:检查类别名称是否包含与AI生成相关的关键词
        ai_keywords = ["artificial", "generated", "synthetic", "fake", "computer"]
        for keyword in ai_keywords:
            if keyword in predicted_class:
                return float(probabilities[0][predicted_class_idx].item())
        
        # 如果没有明确的AI类别,返回中等概率
        return 0.5
    
    elif "vit" in model_name:
        # Vision Transformer模型
        predicted_class_idx = outputs.logits.argmax(-1).item()
        # 同样检查类别名称
        predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
        
        # 简单启发式:检查类别名称是否包含与AI生成相关的关键词
        ai_keywords = ["artificial", "generated", "synthetic", "fake", "computer"]
        for keyword in ai_keywords:
            if keyword in predicted_class:
                return float(probabilities[0][predicted_class_idx].item())
        
        # 如果没有明确的AI类别,返回中等概率
        return 0.5
    
    # 默认处理
    predicted_class_idx = outputs.logits.argmax(-1).item()
    predicted_class = model_info["model"].config.id2label[predicted_class_idx].lower()
    
    if "ai" in predicted_class or "generated" in predicted_class or "fake" in predicted_class:
        return float(probabilities[0][predicted_class_idx].item())
    else:
        return 1 - float(probabilities[0][predicted_class_idx].item())

def analyze_image_features(image):
    # 转换为OpenCV格式
    img_array = np.array(image)
    if len(img_array.shape) == 3 and img_array.shape[2] == 3:
        img_cv = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
    else:
        img_cv = img_array
    
    features = {}
    
    # 基本特征
    features["width"] = image.width
    features["height"] = image.height
    features["aspect_ratio"] = image.width / max(1, image.height)
    
    # 颜色分析
    if len(img_array.shape) == 3:
        features["avg_red"] = float(np.mean(img_array[:,:,0]))
        features["avg_green"] = float(np.mean(img_array[:,:,1]))
        features["avg_blue"] = float(np.mean(img_array[:,:,2]))
    
    # 边缘一致性分析
    edges = cv2.Canny(img_cv, 100, 200)
    features["edge_density"] = float(np.sum(edges > 0) / (image.width * image.height))
    
    # 纹理分析 - 使用灰度共生矩阵
    if len(img_array.shape) == 3:
        gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
        from skimage.feature import graycomatrix, graycoprops
        
        # 计算GLCM
        distances = [5]
        angles = [0, np.pi/4, np.pi/2, 3*np.pi/4]
        glcm = graycomatrix(gray, distances=distances, angles=angles, symmetric=True, normed=True)
        
        # 计算GLCM属性
        features["texture_contrast"] = float(np.mean(graycoprops(glcm, 'contrast')[0]))
        features["texture_homogeneity"] = float(np.mean(graycoprops(glcm, 'homogeneity')[0]))
    
    # 噪声分析
    if len(img_array.shape) == 3:
        blurred = cv2.GaussianBlur(img_cv, (5, 5), 0)
        noise = cv2.absdiff(img_cv, blurred)
        features["noise_level"] = float(np.mean(noise))
    
    # 分析对称性 - AI生成图像通常有更高的对称性
    # 水平对称性
    if img_cv.shape[1] % 2 == 0:  # 确保宽度是偶数
        left_half = img_cv[:, :img_cv.shape[1]//2]
        right_half = cv2.flip(img_cv[:, img_cv.shape[1]//2:], 1)
        if left_half.shape == right_half.shape:
            h_symmetry = 1 - float(np.mean(cv2.absdiff(left_half, right_half)) / 255)
            features["horizontal_symmetry"] = h_symmetry
    
    # 垂直对称性
    if img_cv.shape[0] % 2 == 0:  # 确保高度是偶数
        top_half = img_cv[:img_cv.shape[0]//2, :]
        bottom_half = cv2.flip(img_cv[img_cv.shape[0]//2:, :], 0)
        if top_half.shape == bottom_half.shape:
            v_symmetry = 1 - float(np.mean(cv2.absdiff(top_half, bottom_half)) / 255)
            features["vertical_symmetry"] = v_symmetry
    
    # 分析颜色分布 - AI生成图像通常有更平滑的颜色过渡
    if len(img_cv.shape) == 3:
        hsv = cv2.cvtColor(img_cv, cv2.COLOR_BGR2HSV)
        hue_std = float(np.std(hsv[:,:,0]))
        sat_std = float(np.std(hsv[:,:,1]))
        val_std = float(np.std(hsv[:,:,2]))"] = hue_std / 180  # 归一化
        features["saturation_variation"] =_variation"] = val_std /_final_decision(ai_probability, image率和图像特征做出更准确的决策础决策
    if ai_probability > 0.7:
        base_decision = "高概率AI生 < 0.3:
        base_decision = "高概率人类创 "无法确定"
    
    整
    feature_score = 0
    
    # 检查对称性 - 高对称性通常表示AI" in image_features and image_features["horizontal_symmetry"] > 0.0.1
    if "vertical_symmetry" in image_features and image_features["vertical_symmetry"] > 0. 0.1
    
    - AI生成图像通常边缘密度较低
    if image_features["edge_density"] < 0.01
    
    # 检查噪声 - AI生成图像通常噪声较低< 0.3:
        feature_score += 0.1
    
    # 检查颜色变化 - AI生成图像通常颜色变化ue_variation" in image_features and image_features["hue_variation"] < 0.1
    if "saturation_variation" in image_features and image_features["saturation_variation"] 0.05
    
    # 调整最终概率
    adjusted_probability = min(1.0, max(0.0, ai_probability + feature_score))新判断
    if adjusted_probability > 0.7:
        return "高概率AI生成", adjusted_probability
    elif adjusted_probability < 0.3:
        return "高概率人类创作", adjusted_probability
    else:
        return "无法确定", adjusted_probability

def detect_ai_image(image):
    if image is None:
        return {"error": "未提供图像"}
    
    results = {}
    valid_models = 0
    weighted_ai_probability = 0
    
    # 使用每个模型进行预测
    for key, model_info in models.items():
        if model_info["processor"] is not None and model_info["model"] is not None:
            try:
                # 处理图像
                inputs = model_info["processor"](images=image, return_tensors="pt")
                with torch.no_grad():
                    outputs = model_info["model"](**inputs)
                
                # 获取概率
                probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
                
                # 使用适配器处理不同模型的输出
                ai_probability = process_model_output(model_info, outputs, probabilities)
                
                # 添加到结果
                predicted_class_idx = outputs.logits.argmax(-1).item()
                results[key] = {
                    "model_name": model_info["name"],
                    "ai_probability": ai_probability,
                    "predicted_class": model_info["model"].config.id2label[predicted_class_idx]
                }
                
                # 累加加权概率
                weighted_ai_probability += ai_probability * model_info["weight"]
                valid_models += 1
            
            except Exception as e:
                results[key] = {
                    "model_name": model_info["name"],
                    "error": str(e)
                }
    
    # 计算最终加权概率
    if valid_models > 0:
        final_ai_probability = weighted_ai_probability / sum(m["weight"] for k, m in models.items() if m["processor"] is not None and m["model"] is not None)
    else:
        return {"error": "所有模型加载失败"}
    
    # 分析图像特征
    image_features = analyze_image_features(image)
    
    # 做出最终决策
    confidence_level, adjusted_probability = make_final_decision(final_ai_probability, image_features)
    
    # 构建最终结果
    final_result = {
        "ai_probability": adjusted_probability,
        "original_ai_probability": final_ai_probability,
        "confidence_level": confidence_level,
        "individual_model_results": results,
        "features": image_features
    }
    
    return final_result

# 创建Gradio界面
iface = gr.Interface(
    fn=detect_ai_image,
    inputs=gr.Image(type="pil"),
    outputs=gr.JSON(),
    title="增强型AI图像检测API",
    description="多模型集成检测图像是否由AI生成",
    examples=None,
    allow_flagging="never"
)

iface.launch()