Escriba un programa que tome una imagen truecolor estándar y un solo color RGB de 24 bits (tres números del 0 al 255). Modifique la imagen de entrada (o envíe una nueva imagen con las mismas dimensiones) de modo que su color promedio sea exactamente el único color que se ingresó. Puede modificar los píxeles de la imagen de entrada de la forma que desee para lograrlo, pero el objetivo es hacer que los cambios de color sean lo más visualmente imperceptibles posible .
El color promedio de una imagen RGB es realmente un conjunto de tres medios aritméticos , uno para cada canal de color. El valor rojo promedio es la suma de los valores rojos en todos los píxeles de la imagen divididos por el número total de píxeles (el área de la imagen), redondeados al número entero más cercano. Los promedios verde y azul se calculan de la misma manera.
Este script Python 2 (con PIL ) puede calcular el color promedio de la mayoría de los formatos de archivo de imagen:
from PIL import Image
print 'Enter image file'
im = Image.open(raw_input()).convert('RGB')
pixels = im.load()
avg = [0, 0, 0]
for x in range(im.size[0]):
for y in range(im.size[1]):
for i in range(3):
avg[i] += pixels[x, y][i]
print 'The average color is', tuple(c // (im.size[0] * im.size[1]) for c in avg)
(Hay programas de color promedio similares aquí , pero no necesariamente hacen exactamente el mismo cálculo).
El requisito principal para su programa es que para cualquier imagen de entrada, el color promedio de su salida correspondiente debe coincidir exactamente con el color que se ingresó, según el fragmento de Python o algún código equivalente. La imagen de salida también debe tener exactamente las mismas dimensiones que la imagen de entrada.
Por lo tanto, técnicamente podría enviar un programa que simplemente colorea la entrada completa con el color promedio especificado (porque el promedio siempre sería ese color), pero este es un concurso de popularidad : la presentación con el mayor número de votos ganará , y será tan trivial la sumisión no le dará muchos votos a favor. Ideas novedosas como aprovechar las peculiaridades de la visión humana, o reducir la imagen y dibujar un borde de color a su alrededor (con suerte) le dará votos.
Tenga en cuenta que ciertas combinaciones de colores e imágenes promedio requieren cambios de color extremadamente notables. Por ejemplo, si el color promedio para igualar fuera negro (0, 0, 0), cualquier imagen de entrada necesitaría hacerse completamente negra porque si los píxeles tuvieran valores distintos de cero, también harían que el promedio no sea cero ( salvo errores de redondeo). Tenga en cuenta tales limitaciones al votar.
Imágenes de prueba
Algunas imágenes y sus colores promedio predeterminados para jugar. Haga clic para ver los tamaños completos.
A. promedio (127, 127, 127)
De las imágenes de fejesjoco con respuesta de todos los colores . Encontrado original en su blog .
B. promedio (62, 71, 73)
Yokohama . Proporcionado por Geobits .
C. promedio (115, 112, 111)
Tokio . Proporcionado por Geobits .
D. promedio (154, 151, 154)
La cascada de Escher . Original .
E. promedio (105, 103, 102)
Monte Shasta . Proporcionado por mí
F. promedio (75, 91, 110)
Notas
- Los formatos exactos de entrada y salida y los tipos de archivos de imagen que usa su programa no importan demasiado. Solo asegúrese de que esté claro cómo usar su programa.
- Probablemente sea una buena idea (pero técnicamente no es un requisito) que si una imagen ya tiene el color promedio objetivo, debería salir como está.
- Publique imágenes de prueba con la entrada de color promedio como (150, 100, 100) o (75, 91, 110), para que los votantes puedan ver las mismas entradas en diferentes soluciones. (Publicar más ejemplos que esto está bien, incluso alentado).
fuente
Respuestas:
Python 2 + PIL, escala de color simple
Aquí hay un enfoque ingenuo que debería servir como una buena línea de base. En cada iteración, comparamos nuestro promedio actual con el promedio deseado, y escalamos el RGB de cada píxel en la proporción correspondiente. Sin embargo, debemos tener un poco de cuidado por dos razones:
Escalar 0 todavía da como resultado 0, así que antes de escalar agregamos algo pequeño (aquí
0.01
)Los valores RGB están entre 0 y 255, por lo que debemos ajustar la relación en consecuencia para compensar el hecho de que el escalado de píxeles limitados no hace nada.
Las imágenes se guardan como PNG porque guardar como JPG parece estropear los promedios de color.
Salida de muestra
(40, 40, 40)
(150, 100, 100)
(75, 91, 110), paleta Starry Night
fuente
C ++, corrección gamma
Esto hace un ajuste de brillo de la imagen usando una corrección gamma simple, con el valor gamma determinado por separado para cada componente para que coincida con el promedio objetivo.
Los pasos de alto nivel son:
Todas las entradas / salidas de imágenes utilizan archivos PPM en ASCII. Las imágenes se convirtieron de / a PNG usando GIMP. El código se ejecutó en una Mac, las conversiones de imágenes se realizaron en Windows.
Código:
El código en sí es bastante sencillo. Un detalle sutil pero importante es que, mientras los valores de color están en el rango [0, 255], los mapeo a la curva gamma como si el rango fuera [-1, 256]. Esto permite que el promedio se fuerce a 0 o 255. De lo contrario, 0 siempre sería 0 y 255 siempre sería 255, lo que podría nunca permitir un promedio de 0/255.
Usar:
.cpp
, por ejemploforce.cpp
.c++ -o force -O2 force.cpp
../force input.ppm targetR targetG target >output.ppm
.Salida de muestra para 40, 40, 40
Tenga en cuenta que las imágenes para todas las muestras más grandes se incluyen como JPEG, ya que exceden el límite de tamaño SE como PNG. Dado que JPEG es un formato de compresión con pérdida, es posible que no coincidan exactamente con el promedio objetivo. Tengo la versión PNG de todos los archivos, que coincide exactamente.
Salida de muestra para 150, 100, 100:
Salida de muestra para 75, 91, 110:
fuente
Python 2 + PIL
Esto itera a través de cada píxel en un orden aleatorio y reduce la distancia entre cada componente del color del píxel
255
o0
(dependiendo de si el promedio actual es menor o mayor que el promedio deseado). La distancia se reduce por un factor multiplicativo fijo. Esto se repite hasta obtener el promedio deseado. La reducción es siempre al menos1
, a menos que el color sea255
(o0
), para garantizar que el procesamiento no se detenga una vez que el píxel esté cerca del blanco o el negro.Salida de muestra
(40, 40, 40)
(150, 100, 100)
(75, 91, 110)
fuente
Java
Un enfoque basado en RNG. Un poco lento para grandes imágenes de entrada.
Pruebas:
(40,40,40)
(150,100,100)
(75,91,110)
fuente