joel taylor pedrós
blog

profile or wanted (linkedin o interpol): la foto lo delataba

un cuadrado gris de 200 por 200 junto a uno azul de 1.583 por 1.583, a escala, bajo el título nítido quería decir buscado.

4 de cada 10 jugadores toman por un fugitivo de la interpol un perfil de linkedin con foto de carné. lo mide profile or wanted, el juego en el que ves una cara y tienes que decir si es de un perfil de linkedin o de una ficha de busca y captura.

en marzo, el juego tenía partidas de 30 rondas, unos scripts de n8n que cada día descargaban fichas de la interpol y perfiles de linkedin a través de la api de google, y más de 3.000 perfiles. desde entonces lo he rehecho entero, y ahora hay partidas de 5 a 50 rondas, una sin final y un reto diario. este artículo va de las fotos, y de por qué durante meses el juego medía una cosa distinta de la que decía.

el juego daba la respuesta

en julio cogí 60 fotos al azar de cada tipo y las medí. las de linkedin medían casi todas 200 píxeles de lado y unos 5 kb, porque eran la miniatura que google guardaba de la foto del perfil. las de la interpol variaban mucho, y las había muy detalladas. ampliadas al tamaño del tablero, las de linkedin se veían siempre igual de blandas, y una foto nítida solo podía ser de una ficha. quien se fijaba aprendía que nítido quería decir buscado, y acertaba.

en octubre de 2025 ya le había puesto un parche. le dije al componente de imagen que las sirviera todas a 100 píxeles en lugar de 500, para igualarlas. no lo arregló.

antes de cambiar nada hice una copia de los datos para comparar. solo con el tamaño del lado corto se podía clasificar como linkedin o interpol el 99,0% de las fotos que pude medir. la cabecera Content-Type sola, image/jpeg en google y image/JPG en la interpol, acertaba el 96,2%. los jugadores acertaban el 77,7%. un programa que no mirara ninguna cara les ganaba a todos.

descargar las fotos de la interpol

hasta septiembre, el juego guardaba el enlace a la foto de cada cara, y no la foto. para poder tratarlas antes de servirlas, tenía que descargarlas. la foto de cada ficha sale de /notices/v1/red/{id}/images, en la api de la interpol. las que saqué de ahí tenían una mediana de 265 píxeles de lado corto, y el 10% más grande superaba los 1.500.

descargarlas no era inmediato. la api de la interpol responde un 403 a todo lo que no sea un navegador, y un 429 si le haces peticiones en paralelo. ahora el script sirve una página pequeña en 127.0.0.1 que se queda abierta en chrome. la página hace cada petición que el script le pasa y le devuelve la respuesta, y el script decide todo lo demás.

las fotos nuevas entraron el 20 de septiembre, como versión 2 de cada cara. los contadores de aciertos van por versión de la foto y no por persona, así que las respuestas a las fotos viejas se quedaron como registro de la foto vieja.

había que igualar por abajo

una foto de la interpol puede tener 1.583 píxeles de lado corto. una de linkedin es una miniatura de google imágenes de 200 píxeles, en jpeg a una calidad de unos 72. las dos se amplían al mismo tablero de 768 píxeles, y entonces la de la interpol queda nítida y la de linkedin, blanda. nítido seguía queriendo decir buscado.

mejorar las de linkedin no era posible. de las 1.518 fichas de linkedin solo tenía el enlace a la miniatura de google, y la api de búsqueda de google con la que las había encontrado ya no acepta clientes nuevos. el 25 de julio, un proyecto nuevo recibía un 403, y el servicio cierra del todo el 1 de enero de 2027. además, de las 1.516 miniaturas que aún respondían, 191 no eran la foto de una persona: banners de empresa, certificados, una señal de stop, el logo de linkedin y 57 copias de tres imágenes por defecto.

así que 200 píxeles es el techo, y había que bajar las de la interpol hasta ahí sin tocar su contenido. la regla que me puse es normalizar el medio y no la foto. resolución, compresión y formato, sí. luz, encuadre, fondo y expresión, no, porque son lo que el juego te pide que leas. nada de pasar a blanco y negro ni de ecualizar el histograma.

el embudo de 200 píxeles

primero hay que saber cuánto detalle tiene de verdad una foto, y eso no es su tamaño en píxeles. una miniatura de 150 ampliada a 600 sigue teniendo 150 píxeles de información. la medida que uso es el lado más pequeño al que puedo reducir el recorte cuadrado y volver a ampliarlo sin bajar de 38 db de psnr respecto al original, con lanczos en las dos operaciones. el 4 de octubre daba esto, en píxeles:

medianap95máximomás de 200
perfiles, 1.3171522002171
fichas, 3211624821.271126

un recorte con más de 200 píxeles de detalle real pasa por lo mismo que google le hizo a cada perfil:

def thumbnail_pass(square: Image.Image) -> Image.Image:
    small = square.resize((THUMB_SIZE, THUMB_SIZE), Image.LANCZOS)
    buf = io.BytesIO()
    small.save(buf, "JPEG", quality=THUMB_QUALITY)
    with Image.open(io.BytesIO(buf.getvalue())) as decoded:
        return decoded.convert("RGB")

el jpeg está a propósito. los bloques y los halos de una compresión a calidad 72 forman parte de cómo se ve un perfil, tanto como la resolución. un recorte de 200 o menos no se toca.

diagrama del paso de la miniatura: la foto de la ficha se recorta en cuadrado anclado a la cara, se mide su detalle real y, si pasa de 200 píxeles, se reduce a 200, se guarda en jpeg a calidad 72 y se descodifica antes de ampliarla a 768 píxeles en webp.
un recorte de 200 píxeles de detalle o menos va directo al tablero, como antes.

medidas sobre el recorte que usa el tablero, 124 de las 321 fichas pasan de 200. después del paso, al tamaño del tablero, tienen una mediana de 144 y un p95 de 204, lo mismo que una muestra de 300 tableros de perfiles. también probé a reducir cada foto a un tamaño sacado de la distribución de los perfiles, y la mediana caía hasta 108. por eso es un 200 fijo.

rehíce en su sitio las fichas que ya estaban en el juego, sin versión nueva, porque es la misma foto con una pista menos. el script solo sobrescribe una cara si la foto original guardada genera byte a byte el tablero que se está sirviendo, y después purga la caché de cloudflare y lo comprueba por el hash.

qué pasó con el acierto

con las fotos viejas, del 25 de julio al 20 de septiembre, los jugadores acertaron 5.143 de las 6.408 respuestas a las 252 fichas, un 80,3%. con las fotos nuevas, desde el 20 de septiembre, han acertado 10.151 de 13.133, un 77,3%. son las mismas fichas, y cuento todas las modalidades y también las respuestas repetidas. el 77% incluye dos semanas en las que las fotos nuevas aún eran más nítidas que las de linkedin, porque el embudo llegó el 4 de octubre.

qué foto hace equivocarse a los jugadores

con las fotos igualadas, ya se podía mirar qué tipo de foto engaña. el 29 de septiembre, claude sonnet puntuó a ciegas las 500 caras del juego, 248 perfiles y 252 fichas. cada foto era un fichero numerado, sin ningún id ni nombre, e iban mezcladas mitad y mitad, como en el juego. para cada una daba la probabilidad de que fuera de la interpol y hasta 6 etiquetas de una lista cerrada de 31, como foto de carné, retrato profesional, sonriente, serio o poca resolución. las instrucciones le prohibían usar la etnia aparente, la nacionalidad, el color de piel, la edad o el aspecto de la persona. dos pasadas a ciegas coincidieron con una correlación de spearman de 0,91.

después crucé las etiquetas con las respuestas. cuento solo la primera respuesta de cada jugador a cada cara, en las partidas normales del 22 de septiembre al 6 de octubre:

  • con un perfil de linkedin con foto de carné, se equivoca el 42%, 186 de 444
  • con un perfil con retrato profesional, el 21%
  • con una ficha en la que el fugitivo sonríe, el 37%
  • con una ficha con cara seria, el 18%
  • con un perfil de poca resolución, el 43%
gráfico de barras con el porcentaje de jugadores que se equivocan según cómo es la foto. en los perfiles de linkedin, foto borrosa 43%, foto de carné 42%, todos los perfiles 29% y retrato profesional 21%. en las fichas de la interpol, sonriente 37%, con americana 35%, todas las fichas 26% y cara seria 18%.
primera respuesta de cada jugador a cada cara, en partidas normales, del 22 de septiembre al 6 de octubre de 2026.

en conjunto, la pista funciona. sonnet marcó como foto de carné 164 de las 252 fichas y solo 23 de los 248 perfiles, y como retrato profesional, 74 perfiles y 2 fichas. el juego se vuelve difícil en las excepciones, el perfil con foto de carné o la ficha con sonrisa. y una foto borrosa hace pensar en un criminal, aunque sea de un perfil.

estas puntuaciones deciden ahora qué caras entran en el juego. la mitad de la interpol era demasiado fácil. la ficha mediana la acertaba el 81% de los jugadores, y 221 de las 252 eran hombres. ahora entran las fichas que a sonnet le parecen menos evidentes, con las mujeres primero, y ningún país emisor puede pasar del 40% de las aceptadas. ese límite salió de una tanda en la que 24 de las 40 eran de rusia. cada cara nueva entra a prueba, y se queda o se retira según cuántos jugadores la aciertan.

cómo lo encuentra la gente

la mayoría de jugadores llega desde bing, que en 14 días mandó 428 clics, frente a 11 de google. y en bing nadie busca el nombre del juego. de las 85 búsquedas que llevan hasta él, ninguna es «profile or wanted». la que trae más clics es «linkedin or interpol», con 100, y la segunda, «linkedin o interpol», con 76.

el 98% de esos clics vienen de un ordenador, y hay 40 al día entre semana y 7 el fin de semana. una de las 85 búsquedas es «interpol or linkedin unblocked». todo apunta a gente que juega desde el ordenador del colegio o del trabajo.