Aquí tienes una función en PHP que compara dos imágenes usando el algoritmo SSIM (Structural Similarity Index). Está hecha con la extensión GD (común en PHP) y calcula el SSIM por bloques usando una ventana Gaussiana, tal como en el paper original. Devuelve un valor entre 0 y 1 (más cercano a 1 significa mayor similitud). Requisitos: PHP con la extensión GD habilitada. Rendimiento: Por defecto reescala las imágenes a 512×512 para acelerar el cálculo. --------------------------------- 0 ? max(0.0, min(1.0, $ssimSum / $blockCount)) : 0.0; } /** -------------------- Helpers -------------------- */ /** * Carga una imagen con GD desde ruta (auto-detecta mime). */ function loadImageGD(string $path) { if (!is_file($path)) return false; $data = @file_get_contents($path); if ($data === false) return false; return @imagecreatefromstring($data); } /** * Redimensiona un recurso GD a w×h con resampleo bilineal. */ function resizeGD($im, int $w, int $h) { $dst = imagecreatetruecolor($w, $h); imagealphablending($dst, false); imagesavealpha($dst, true); imagecopyresampled($dst, $im, 0, 0, 0, 0, $w, $h, imagesx($im), imagesy($im)); return $dst; } /** * Convierte imagen GD a matriz [y][x] de luminancia (escala de grises 0..255). * Usa la aproximación: Y = 0.299 R + 0.587 G + 0.114 B */ function toGrayscaleMatrix($im): array { $w = imagesx($im); $h = imagesy($im); $mat = array_fill(0, $h, array_fill(0, $w, 0.0)); for ($y = 0; $y < $h; $y++) { for ($x = 0; $x < $w; $x++) { $rgb = imagecolorat($im, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $yLum = 0.299 * $r + 0.587 * $g + 0.114 * $b; $mat[$y][$x] = $yLum; } } return $mat; } /** * Kernel Gaussiano 2D de tamaño n×n con sigma dado. Normalizado (suma = 1). */ function gaussianKernel2D(int $n, float $sigma): array { if ($n < 1) $n = 1; $kernel = array_fill(0, $n, array_fill(0, $n, 0.0)); $half = ($n - 1) / 2.0; $sum = 0.0; for ($j = 0; $j < $n; $j++) { for ($i = 0; $i < $n; $i++) { $x = $i - $half; $y = $j - $half; $val = exp(-( ($x*$x + $y*$y) / (2.0 * $sigma * $sigma) )); $kernel[$j][$i] = $val; $sum += $val; } } // Normalización for ($j = 0; $j < $n; $j++) { for ($i = 0; $i < $n; $i++) { $kernel[$j][$i] /= $sum; } } return $kernel; } /** -------------------- Ejemplo de uso -------------------- */ // try { // $score = ssim(__DIR__ . '/img1.jpg', __DIR__ . '/img2.jpg', 512, 8, 1.5); // echo "SSIM: " . round($score, 6) . PHP_EOL; // // Puedes definir un umbral para "similar" // $umbral = 0.95; // echo ($score >= $umbral) ? "Muy similares" : "Diferentes"; // } catch (Throwable $e) { // echo "Error: " . $e->getMessage(); // } --------------------------------- Cómo usarlo Guarda el código en un archivo, por ejemplo: ssim.php. Llama a la función pasando las rutas de tus imágenes: = 0.95) { echo "Las imágenes son muy similares.\n"; } else { echo "Hay diferencias apreciables.\n"; } Notas y consejos Umbral práctico: SSIM ≥ 0.98: casi idénticas. 0.95–0.98: diferencias leves (p. ej., compresión). < 0.90: diferencias visibles. Rendimiento: si trabajas con imágenes grandes, deja resizeTo=512 o 256 para velocidad sin perder demasiada precisión perceptual. Exactitud vs. velocidad: Aumentar window (p. ej., 11) y ajustar sigma (≈1.5) se acerca más a implementaciones académicas. Usar ventanas solapadas (stride 1) mejora precisión pero es más lento. Si quieres eso, cambia $stepX y $stepY a 1. Imagick: si dispones de ImageMagick/Imagick reciente, puedes usar su métrica SSIM nativa (si tu versión la soporta). Aun así, el método anterior es 100% PHP+GD y portable.