File size: 3,006 Bytes
6ceaa94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Neural richness proxy computation.

Uses composite signals derived from CLIP features, saliency, and aesthetic scores
as a proxy for predicted brain-response richness.

In a production V2 deployment, this module could be swapped to use
V-JEPA-2 features or a precomputed TRIBE scoring service.
"""

import numpy as np
from typing import Dict


def compute_neural_richness_proxy(
    semantic_features: Dict[str, float],
    saliency_features: Dict[str, float],
    quality_features: Dict[str, float],
    heuristic_features: Dict[str, float]
) -> float:
    """
    Compute a neural richness proxy score from available features.
    
    This is a weighted composite of signals known to correlate with
    human visual engagement and brain response breadth:
    
    - CLIP embedding complexity (rich visual representations)
    - Saliency spatial spread (distributed attention engagement)
    - Aesthetic signal (reward-circuit correlates)
    - Color/feature diversity (visual cortex breadth)
    
    Args:
        semantic_features: from features/semantic.py
        saliency_features: from features/saliency.py
        quality_features: from features/quality.py
        heuristic_features: from features/heuristics.py
    
    Returns:
        Float in [0, 100] representing predicted neural richness.
    """
    # CLIP complexity: normalized embedding norm
    clip_norm = semantic_features.get("clip_image_norm", 0.0)
    # Typical range observed: 15–35 for CLIP ViT-B/32 features
    clip_complexity = _sigmoid_normalize(clip_norm, center=25.0, scale=8.0)
    
    # Saliency spread: entropy of saliency map (already normalized in saliency_features)
    saliency_spread = saliency_features.get("saliency_entropy", 0.5)
    
    # Aesthetic signal: NIMA proxy
    aesthetic = quality_features.get("nima_aesthetic_proxy", 0.5)
    
    # Feature diversity: color entropy (normalized by max possible ~5.55)
    color_entropy = heuristic_features.get("color_entropy", 3.0)
    feature_diversity = _sigmoid_normalize(color_entropy, center=4.5, scale=1.5)
    
    # Edge density (complexity proxy)
    edge_density = heuristic_features.get("edge_density", 0.08)
    complexity = _sigmoid_normalize(edge_density, center=0.10, scale=0.06)
    
    # Weighted combination
    weights = {
        "clip_complexity": 0.25,
        "saliency_spread": 0.20,
        "aesthetic": 0.20,
        "feature_diversity": 0.15,
        "complexity": 0.20,
    }
    
    score = (
        weights["clip_complexity"] * clip_complexity +
        weights["saliency_spread"] * saliency_spread +
        weights["aesthetic"] * aesthetic +
        weights["feature_diversity"] * feature_diversity +
        weights["complexity"] * complexity
    )
    
    return float(np.clip(score * 100, 0, 100))


def _sigmoid_normalize(x: float, center: float, scale: float) -> float:
    """Map x to [0,1] using logistic sigmoid centered at `center` with width `scale`."""
    return 1.0 / (1.0 + np.exp(-(x - center) / scale))