olivas/backend/tests/test_analysis.py
DJP 3467dbcf03 Initial commit — OliVAS visual attention analysis platform
Full-stack application for predicting where humans look in images using
DeepGaze saliency models. Includes heatmap overlays, gaze sequence prediction,
hotspot detection, AOI analysis, rule-based insights, optional Claude AI
design analysis, and professional PDF report generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:20:58 -05:00

94 lines
3.5 KiB
Python

import numpy as np
import pytest
from app.services.gaze_sequence import extract_gaze_sequence
from app.services.aoi_analysis import compute_aoi_attention
from app.services.heatmap import generate_heatmap_overlay, generate_standalone_heatmap
from app.services.image_processing import prepare_for_inference, upscale_saliency
from PIL import Image
class TestGazeSequence:
def test_extracts_correct_number_of_fixations(self):
saliency = np.random.rand(100, 100)
result = extract_gaze_sequence(saliency, num_fixations=5)
assert len(result) == 5
def test_fixations_are_ranked(self):
saliency = np.random.rand(100, 100)
result = extract_gaze_sequence(saliency, num_fixations=3)
ranks = [p["rank"] for p in result]
assert ranks == [1, 2, 3]
def test_first_fixation_is_at_peak(self):
saliency = np.zeros((100, 100))
saliency[50, 75] = 1.0 # Set a clear peak
result = extract_gaze_sequence(saliency, num_fixations=1)
assert result[0]["x"] == 75
assert result[0]["y"] == 50
def test_coordinates_have_percentages(self):
saliency = np.random.rand(200, 300)
result = extract_gaze_sequence(saliency, num_fixations=1)
assert 0 <= result[0]["x_pct"] <= 100
assert 0 <= result[0]["y_pct"] <= 100
class TestAOIAnalysis:
def test_full_image_aoi_gets_100_percent(self):
saliency = np.ones((100, 100))
regions = [{"x": 0, "y": 0, "width": 100, "height": 100}]
result = compute_aoi_attention(saliency, regions)
assert abs(result[0]["attention_pct"] - 100.0) < 0.1
def test_half_image_aoi(self):
saliency = np.ones((100, 100))
regions = [{"x": 0, "y": 0, "width": 50, "height": 100}]
result = compute_aoi_attention(saliency, regions)
assert abs(result[0]["attention_pct"] - 50.0) < 1.0
def test_density_calculation(self):
saliency = np.zeros((100, 100))
saliency[0:10, 0:10] = 1.0 # High saliency in small region
regions = [{"x": 0, "y": 0, "width": 10, "height": 10}]
result = compute_aoi_attention(saliency, regions)
assert result[0]["attention_density"] > 1.0
def test_zero_saliency(self):
saliency = np.zeros((100, 100))
regions = [{"x": 0, "y": 0, "width": 50, "height": 50}]
result = compute_aoi_attention(saliency, regions)
assert result[0]["attention_pct"] == 0.0
class TestHeatmap:
def test_generates_overlay(self):
img = Image.new("RGB", (100, 100), color="white")
saliency = np.random.rand(100, 100)
result = generate_heatmap_overlay(img, saliency)
assert result.size == (100, 100)
assert result.mode == "RGB"
def test_generates_standalone(self):
saliency = np.random.rand(100, 100)
result = generate_standalone_heatmap(saliency)
assert result.size == (100, 100)
class TestImageProcessing:
def test_resize_large_image(self):
img = Image.new("RGB", (2000, 1000))
resized, scale = prepare_for_inference(img)
assert max(resized.size) <= 1024
assert scale < 1.0
def test_no_resize_small_image(self):
img = Image.new("RGB", (500, 300))
resized, scale = prepare_for_inference(img)
assert resized.size == (500, 300)
assert scale == 1.0
def test_upscale_saliency(self):
saliency = np.random.rand(50, 50)
result = upscale_saliency(saliency, 200, 300)
assert result.shape == (200, 300)