Примечание : Андерс Касорг был награжден приёмкой на данный момент, чтобы привлечь внимание к его великолепному ответу, но задача еще не окончена! В предложении по-прежнему есть награда в 400 очков для тех, кто набирает высший балл без использования встроенного сжатия.
Ниже 386x320
png представление «Звездной ночи» Ван Гога.
Ваша цель - воспроизвести это изображение как можно более точно, не более чем в 1024 байтах кода. Для целей этой задачи близость изображений измеряется квадратом различий в значениях пикселей RGB, как описано ниже.
Это код-вызов . Результаты рассчитываются с использованием сценария проверки ниже. Самый низкий балл побеждает.
Ваш код должен соответствовать следующим ограничениям:
- Это должна быть полная программа
- Он должен выводить изображение в формате, который можно прочитать с помощью приведенного ниже сценария проверки, работающего на моем компьютере. Скрипт использует библиотеку PIL Python, которая может загружать самые разные форматы файлов , включая png, jpg и bmp.
- Он должен быть полностью автономным, без ввода и загрузки файлов (кроме импорта библиотек, что разрешено)
- Если ваш язык или библиотека содержит функцию, которая выводит «Звездную ночь», вам не разрешено использовать эту функцию.
- Он должен работать детерминистически, каждый раз производя один и тот же результат.
- Размеры выходного изображения должны быть
386x320
- Во избежание сомнений: действительные ответы должны использовать языки программирования в соответствии с обычными правилами PPCG . Это должна быть программа, которая выводит изображение, а не просто файл изображения.
Вполне вероятно, что некоторые материалы будут сами генерироваться кодом. Если это так, пожалуйста, включите в ваш ответ код, который использовался для подготовки вашего представления , и объясните, как это работает. Вышеуказанные ограничения применяются только к отправляемой вами программе создания изображений размером 1 КБ; они не применяются к любому коду, используемому для его генерации.
счет
Чтобы вычислить ваш счет, возьмите ваше выходное изображение и оригинал выше и преобразуйте значения пикселей RGB в числа с плавающей запятой в диапазоне от 0 до 1. Счет пикселей (orig_r-img_r)^2 +(orig_g-img_g)^2 + (orig_b-img_b)^2
квадрату расстояния в пространстве RGB между двумя изображениями. Оценка изображения - это сумма оценок его пикселей.
Ниже приведен скрипт Python, который выполняет эти вычисления - в случае любой несогласованности или неоднозначности, окончательная оценка - это та, которая рассчитывается этим скриптом, запущенным на моем компьютере.
Обратите внимание, что оценка рассчитывается на основе выходного изображения, поэтому, если вы используете формат с потерями, который повлияет на оценку.
Чем ниже оценка, тем лучше. Исходное изображение «Звездной ночи» имело бы балл 0. В астрономически маловероятном случае ничьей победитель определит ответ с наибольшим количеством голосов.
Бонусные цели
Поскольку в ответах преобладали решения, использующие встроенное сжатие, я присудил ряд наград за ответы, в которых используются другие методы. Следующим будет вознаграждение в 400 очков. , которое будет присуждаться, если и когда ответ, который не использует встроенную компрессию, занимает первое место в общем зачете.
Премиальные премиальные награды были следующими:
За ответ nneonneo была назначена награда в 100 баллов за то, что она получила наивысший балл, который в то время не использовал встроенное сжатие. На момент вручения ему было 4852,87 балла. Похвальные грамоты идут на 2012 год, который сделал доблестную попытку победить nneonneo, используя подход, основанный на тесселяции Вороного , набрав 5076 очков, и на Sleafar, чей ответ был в лидерах почти до конца, с 5052 очками, используя аналогичный метод для nneonneo.
Награда Strawdog была удостоена награды в 200 баллов . Эта награда была присуждена за стратегию, основанную на оптимизации, которая лидировала среди ответов без встроенного сжатия и удерживала ее в течение недели. Он набрал 4749,88 балла, используя впечатляюще умный метод.
Сценарий оценки / проверки
Следующий скрипт Python должен быть помещен в ту же папку, что и изображение выше (которое должно иметь имя ORIGINAL.png
), и запускаться с помощью команды вида python validate.py myImage.png
.
from PIL import Image
import sys
orig = Image.open("ORIGINAL.png")
img = Image.open(sys.argv[1])
if img.size != orig.size:
print("NOT VALID: image dimensions do not match the original")
exit()
w, h = img.size
orig = orig.convert("RGB")
img = img.convert("RGB")
orig_pix = orig.load()
img_pix = img.load()
score = 0
for x in range(w):
for y in range(h):
orig_r, orig_g, orig_b = orig_pix[x,y]
img_r, img_g, img_b = img_pix[x,y]
score += (img_r-orig_r)**2
score += (img_g-orig_g)**2
score += (img_b-orig_b)**2
print(score/255.**2)
Техническое примечание: объективные меры подобия изображения - хитрая вещь. В этом случае я выбрал тот, который легко реализовать любому, хорошо зная, что существуют гораздо лучшие меры.
Leaderboard
источник
pip unistall PIL
, затемpip install pillow
) и изменить первую строку наfrom PIL import Image
.Ответы:
Pyth (без встроенного сжатия), оценка
4695,074656,034444,82Единственная функциональность Pyth, связанная с изображениями, - это встроенная функция записи матрицы RGB-троек в виде файла изображения. Поэтому безумная идея состоит в том, чтобы натренировать небольшую глубокую нейронную сеть на функции ( x , y ) ↦ ( r , g , b ), представляющей изображение, и запустить ее по координатам каждого пикселя.
План
Текущая сеть построена из 45 сигмовидных нейронов, причем каждый нейрон подключен к входам x , y и к каждому предыдущему нейрону, а последние три нейрона интерпретируются как r , g , b . Он обучен с использованием алгоритма Адама без пакетирования. Параметры, взвешивающие 1125 соединений, квантуются до диапазона 93 возможных значений (кроме константных членов, которые имеют 93 2 возможных значения) с использованием варианта стохастического квантования , первичным вариантом которого является то, что мы устанавливаем градиент для квантованных параметров на ноль.
Результат
Код
1023 байта, закодированные с
xxd
(декодировать с помощьюxxd -r
). Я использовал версию Pyth 2016-01-22, которая была актуальна, когда эта проблема была выпущена. Вы можете запустить код непосредственно в Pyth, но Pyth в PyPy3 (pypy3 pyth starry.pyth
) запускает его в девять раз быстрее, примерно за 3 минуты. Выходное изображение записывается вo.png
.Как это устроено
Тренировка
Во время моего последнего тренировочного цикла я использовал гораздо более медленный график квантования и немного поиграл с этим и скоростью обучения, но код, который я использовал, был примерно следующим.
Визуализация
На этом рисунке показаны активации всех 45 нейронов в зависимости от координат x , y . Нажмите, чтобы увеличить.
источник
Mathematica, оценка 14125,71333
Сохраняет это изображение:
к
a.png
.источник
Java, 7399.80678201
Это напомнило мне о проекте, который я имел в своем классе численных вычислений несколько семестров назад, который должен был нарисовать силуэт горы Эверест с использованием полиномиальной интерполяции. Это было сделано в MATLAB, но я не очень люблю MATLAB, поэтому я решил работать на Java. Основная идея заключается в том, что я выбрал «умные» точки (читаемые здесь как «случайные») для полиномиальной интерполяции. С помощью нескольких оставленных байтов я создал способ рисования звезд, что происходит до рисования горы. Может быть возможным сжать код и добавить еще один многочлен для нижней части, чтобы улучшить результат.
Изменить: я добавил и изменил некоторые из полиномов и добавил все звезды. Мой предыдущий счет был 9807.7168935, так что, как вы видите, это очень большое улучшение. К сожалению, код получил удар по читаемости, потому что мне пришлось выжать последние несколько байтов, чтобы получить все звезды и дать им группы.
9807,7168935 баллов: 7399,80678201 баллов:
источник
Python3.4 +, 4697.26
Я использовал тот же метод, что и в моем ответе ImageMagick, но со следующими параметрами:
Используя эти параметры, я сгенерировал следующую 1003-байтовую программу на Python (я не нашел никаких улучшений по сравнению с методом вывода @ kennytm):
Который в свою очередь генерирует это изображение:
источник
1
изlatin1
и сохранить пробельныеimport *
, по крайней мере. Но игра в гольф не была приоритетом (так как она меньше 1024 байтов).Python 3, оценка 5701,31
Просто измените масштаб изображения PNG 18 × 13.
источник
Ява 8748,95
Другой подход:
Я создал класс, который вычисляет диаграмму Вороного по заданному набору точек. Этот набор точек используется как набор параметров, который служит входом для Apache BOBYQAOptimizer . Функция оценки оптимизатора берет точки и создает из них диаграмму Вороного. Области вороной окрашены в средний цвет соответствующей области исходного изображения.
Процесс оптимизации показан здесь:
Финальное изображение это:
который достигает 8748,95 баллов
(Это было измерено с помощью моей собственной функции, но должно быть таким же, как и в сценарии оценки)
Результатом этого процесса является только набор из 8 точек и соответствующих цветов. (Большее количество баллов приводило к худшим результатам, но я не очень старался это делать).
Результирующий код показан здесь (извините, мне пришлось немного поиграть в гольф, чтобы сжать его до предела в 1 КБ):
(Я знаю, есть несколько простых способов, которые могли бы достичь лучших результатов, но ... это как-то было весело ...)
В ответ на комментарий относительно художественного стиля такого изображения вороной с большим количеством точек: это действительно выглядит интересно, и некоторые инструменты обработки изображений фактически предлагают его как «Мозаичный фильтр» - например, Мозаичный фильтр в GIMP ( хотя это предлагает варианты, чтобы подчеркнуть края и т. д.).
Вот пример изображения «Звездная ночь» с 256 точками. (Они выбираются случайным образом, но с большим количеством точек улучшение, которое может быть достигнуто за счет оптимизации, исчезнет).
Это не часть конкурса (так как он не помещается в 1 КБ), просто для любопытных:
источник
import java.util.*;
Фактическое изменение всех классов импорта на звездочки.AutoIt ,
9183,257882,53ОБНОВИТЬ
Таким образом, оказывается, что перерисовка изображения как (пьяного) малыша более эффективна, чем сохранение любой версии изображения. (В любом случае, более эффективно, чем мое старое решение).
Каждая линия, которая рисует элемент, имеет решающее значение для уменьшения оценки. Я подозреваю, что эта программа способна достичь оценок значительно ниже 7000 с очень незначительными изменениями, потому что каждое отдельное изменение имеет огромное (~ 20 до 100 баллов) влияние на счет. Программа использует мою
processing
графическую библиотеку, которая предоставляет краткие имена функций для рисования с использованием GDI.Поскольку это решение связано со случайностью, мы засеиваем PRNG, используя постоянное значение,
0
используяSRandom(0)
. Почему 0? Потому что это до 50 баллов лучше, чем любой другой, которыйn<=100
я пробовал.Холст начинается как пустой
#587092
.Генерация пола
Нижняя часть изображения (которая, как оказывается, начинается с ровно 233 пикселей (опять же из-за точек)) заполнена ровно
int(1e4*2.9)
эллипсами. Изменение коэффициента здесь (или десятичного разряда фактора) может увеличить или увеличить оценку на сотни баллов. Я остановился на 2,9 после нескольких попыток. Естественно, это займет некоторое время (несколько секунд).Пятицветная палитра поставляется:
Капли на полу
Четыре эллипса используются для установки контрастных акцентов в области пола (
$4
это указатель на функциюellipse()
):Генерация акцентов в небе
Некоторые линии нарисованы с помощью более толстого пера для представления значительных цветных областей внутри неба, которые слишком сильно растянуты для эллипсов:
Взвешивание пикселей
После всего вышеперечисленного все промывают и повторяют, пока у нас не кончатся байты. Затем применяется размытие, чтобы обмануть метод проверки. С помощью грубой силы было определено, что радиус ровно 20 обеспечивает лучший результат. Это улучшает счет примерно на 1,5К (!).
Конечное изображение
Код, 985 байт
СТАРЫЙ ОТВЕТ
Это хранит 80 значений цвета, которые составляют 10x8 пикселей изображения. Это необработанное изображение имеет оценку 10291. Поскольку 10x8 - это коэффициент пикселизации, равный 40 пикселям, применяется размытие по Гауссу с использованием радиуса 40 пикселей, чтобы уменьшить оценку. Так сценарий достигает 9183,25.
Это сохраненные данные:
Полученный файл - True.png:
Длина программы 998 байт :
источник
1e4*2.9
равно29e3
?Windows BAT файл, оценка 4458,854
Размер программы составляет 1024 байта.
Преобразует из BP64-кодированного изображения BPG в PNG.
В качестве библиотек используется certutil.exe (стандартная утилита Windows) и декодер изображений bpgdec.exe .
Сжатие:
источник
C ++ 11,
7441,681261056997,654348335198,16 7651Больше обновлений
Мне очень понравились эллипсы из Perl, и мне пришлось попробовать их в C ++ 11. Я использовал необработанную строку, чтобы вставить туда байты, но какое-то время я получал небольшое расхождение с ожидаемым результатом и сгенерированным кодом. Оказывается, что вы на самом деле не можете поместить необработанный 0x0d (возврат каретки), так как g ++ преобразует это в 0x0a (новая строка). Честно говоря, я не уверен, насколько легитимен этот сгенерированный источник, но он компилируется и работает на нескольких моих машинах.
Я также опробовал другой алгоритм, адаптивный поиск размеров после того, как GA выглядел так, как будто он застопорился, просто чтобы попытаться откорректировать локальный минимум и, возможно, получить удачу и попасть в другую скважину.
При этом C ++ 11 дает удивительно конкурентоспособную оценку (намного лучше, чем я мог бы изначально догадаться) ... Я очень удивлен, что он может сделать это с помощью fstream в качестве единственного включения.
Текст (да, новые строки находятся в фактическом источнике ... Я полагаю, я мог бы удалить их):
HexDump:
Этот ответ сочетает в себе несколько подходов из предыдущих ответов, которые я объясню ниже, к сожалению, мне пришлось немного поиграть в программу, чтобы соответствовать
944949 символам (согласноwc -c
), так что она больше не похожа на C ++ (извиняюсь, если это противоречит правилам конкурса, в ближайшее время я собираюсь попробовать некоторые улучшения). Сначала я не планировал этого, так что он все еще не полностью не поддается расшифровке, и все еще есть много висящих фруктов.Обновленные результаты
Простое выполнение генетического алгоритма дольше дало немного лучший результат; однако, учитывая, что конвергенция значительно замедлилась, я бы сказал, что этот конкретный метод, вероятно, начинает достигать максимума (или я попал в какой-то глубокий локальный минимум). Я запустил финальную программу еще немного, чтобы сжать еще пару прямоугольников (генератор остался прежним, за исключением того, что максимальный размер генома был увеличен).
Реализация пересечения между людьми поможет, если проблема заключается в глубоком локальном минимуме, но, учитывая, что он некоторое время остается в одном и том же диапазоне, я начинаю думать, что это примерно так же хорошо, как и число прямоугольников.
Версия Вороного, 7331,92407536, 989 символов
Я использовал « Идею Вороного» от Marco13 с моим кодом GA. На самом деле это не сработало так, как я надеялся. Я мог только втиснуть в несколько больше точек, чем прямоугольники. Я думаю, что потенциально непересекающаяся природа прямоугольников из-за перекрытия помогает баллу немного. Несмотря на это, мне на самом деле нравится, как это выглядит значительно лучше, несмотря на результат, аналогичный моему первому заявлению.
Старые результаты, 7441,68126105, 944 символа
Как и некоторые другие записи, программа просто рисует перекрывающиеся прямоугольники. Он использует двоичный PPM, поскольку формат прост (вывод есть
a.ppm
, но я загрузил версию png, поскольку SE не понравился PPM), и он полностью детерминирован.объяснение
Генерация PPM потребовала много кода, что означало, что у меня не может быть слишком много прямоугольников даже после небольшого количества игры в гольф. Еще несколько, вероятно, можно сжать здесь, чтобы улучшить счет дальше.
Настоящая магия - это список прямоугольников. Подобно ответу Вольфганга, я использовал генетический алгоритм, чтобы найти их. На самом деле реализация в значительной степени неполная, поскольку рекомбинация между людьми еще не происходит, но мутации все же происходят, и рейтинг в турнирном стиле по физической пригодности сохраняет лучшие организмы в следующем раунде. Элитарность также используется, поскольку копия лучшего человека из последнего раунда сохраняется в следующем раунде, поэтому наиболее подходящий организм всегда, по крайней мере, такой же, как и в предыдущем раунде.
Я не слишком внимательно присматривался к коду Вольфганга с тех пор, как начал его вчера, но похоже, что он также позволяет изменять цвет, что может объяснить разницу в баллах.
Чтобы уменьшить пространство поиска, я смотрел только на положение прямоугольника; цвет рассчитывается по среднему значению для каждого канала видимых пикселей из этого прямоугольника, поскольку у нас есть исходное изображение (я не думаю, что мы можем добиться большего успеха для этого конкретного прямоугольника, поскольку это минимизирует квадратное расстояние).
Я оставлю репозиторий github в следующих нескольких изменениях, если буду продолжать над ним работать, но пока (однофайловый) код находится на pastebin . Скомпилируйте его в режиме C ++ 11 (примечание, я довольно смущен тем, насколько грязно это даже для одного раза).
Вам также понадобится изображение звездной ночи P3 PPM, названное так,
ORIGINAL.ppm
чтобы это работало. Вы можете скачать файл из этого GitHub Gist .источник
i r,g,b
вместо отдельно, и много пробелов может быть отброшено). Я не был уверен, должна ли программа сгенерировать файл напрямую или все в порядке с конвейером в stdout / stderr.#include <fstream>
? Кроме того, удалите символы новой строки и поместите все в одну строку, так как C ++ в любом случае нуждается в точках с запятойImageMagick, 4551.71
Использует язык программирования «ImageMagick», используя следующие параметры (возможно, вам придется выйти из этого режима
!
):Предполагая следующий 968-байтовый исходный файл (заданный как hexdump):
Создание этого изображения:
Вам, наверное, интересно, как я сгенерировал входной файл, и ответ довольно прост. Измените размер до 48x40 с помощью фильтра Ланцоша, используйте индексированную палитру из 20 цветов и оптимизируйте полученный PNG.
Использует
convert
,pngquant
,optipng
иadvdef
.источник
=(tail +2 $0)
трюк из моего ответа , вы можете создать один скрипт ZSH, который содержит как скрипт ImageMagick, так и входной файл PNG.Python 2, 4749,88
1018 байт
Все, наверное, уже забыли об этой проблеме, кроме меня ....
Эта проблема интересовала меня слишком сильно, особенно потому, что быстро стало очевидно, что подходы, использующие алгоритмы сжатия изображений, определенно лидируют, но все же почему-то неудовлетворительные с эстетической точки зрения. Подходы, основанные на оптимизации набора примитивов рисования, были несколько более приятными с эстетической точки зрения, но казались заблокированными чуть выше 5000 баллов.
Метод nneonneo, который не использовал стандартное сжатие изображений, превосходит отметку 5000, но делает это путем кодирования крошечного изображения и его масштабирования.
Вот программа, которая использует только примитивы рисования, автоматически генерируется методом оптимизации и получает оценку 4749,88.
который выглядит так:
и hexdump кода:
Он использует ряд приемов, использованных ранее здесь:
В качестве первого примитива я размещаю линию горизонта, разделяя изображение на два цветных блока. Впоследствии, в качестве основного примитива я использовал круг, перетаскиваемый между двумя точками. Это выглядело смутно, как мазок, но можно было выразить в 7 байтов. Для процесса поиска я использовал поиск по шаблону. Это происходит путем попеременного добавления примитива и оптимизации его параметров. Примитив добавляется в точку, где размытая ошибка со знаком является наибольшей. Параметры оптимизируются путем исчерпывающей оптимизации линии в небольшом домене, один за другим. Сорок-пятьдесят примитивов добавляются и оптимизируются индивидуально. Затем список примитивов сокращается до размера, отбрасывая примитивы, которые помогают наименьшему количеству очков.
Это все еще не побивает счет nneonneo. Чтобы побить этот показатель, потребовалась вторая стадия оптимизации, которая снова проходит процесс добавления примитивов на каждом из нескольких уровней фильтрации и отбрасывания примитивов, чтобы урезать сгенерированную программу до размера. Что было действительно интересно для меня, так это идея применить это к другим изображениям. Я применил его к паре других изображений и предоставил дополнительную информацию и анимацию примитивов, нарисованных в моем блоге здесь .
Две программы, используемые для генерации этого, на самом деле не помещаются в пространство, допустимое на сообщениях Stack Exchange, но они находятся на github: https://github.com/str4w/starrynight/tree/StackExchange
сначала запускается звездная ночь, а затем этап2 оптимизации. Полученная программа также там, в том же каталоге.
источник
Матлаб, оценка 5388,3
Без какой-либо встроенной компрессии. Глубина цвета уменьшается так, что каждый пиксель может быть представлен одним печатным символом. И разрешение уменьшается. Это тогда жестко закодировано как строка. Сам код полностью изменяет процесс. Операция изменения размера использует интерполяционное ядро Lanczos 3.
источник
zsh + bpgdec, 4159.061760861207
Да, другое решение BPG. Я думаю, что это в основном служит доказательством того, что BPG - лучшая утилита сжатия изображений, доступная в настоящее время. Считайте это улучшением по сравнению с оригинальным решением BPG от Yallie .
Файл имеет длину 1024 байта, прямо на пределе. Состоит из линии
с последующим необработанным выходом BPG из
В шестнадцатеричном виде это скрипт:
В результате получается файл
out.png
(расположение поbpgdec
умолчанию), который выглядит следующим образом:Я нахожу это довольно удивительным, что
bpg
всего за 996 байт точно восстановил четкие контуры дерева слева и холмов справа. У этого даже есть проходимое приближение для церковного шпиля! Уровень детализации очень впечатляет (для меня) для небольшого размера файла. Конечно,bpgdec
сама по себе не маленькая программа, но мне ясно, что BPG на порядок лучше, чем JPEG для сжатия изображений.Поскольку это использует
bpgdec
, этот ответ, очевидно, не имеет права на награду.РЕДАКТИРОВАНИЕ: Добавлен
-n
аргумент, чтобыtail
сделать его совместимым с GNUtail
.источник
tail: cannot open ‘+2’ for reading
. На Ubuntu это нужно-n +2
, что ставит его в 1025 байт = /-n+2
его с точностью 1024 байта - попробуйте и дайте мне знать, если это работает. Я изменю свой ответ для совместимости.С 6641
999 байт, используя только
stdio.h
иmath.h
.Я сделал функцию заполненного круга
d()
которая рисует концентрические цветные круги RGB поверх значений радиуса r..0. 21 круг используется здесь. Я мог бы сжать еще несколько, если бы я удалил больше пробелов, но мне нравится относительная читаемость в ее нынешнем виде.Я разобрался с грубым расположением кругов, используя слои Gimp в
Difference
режиме. Ищите яркие пятна, добавьте круг, повторите. ИспользуетсяHistogram
инструмент для выделения, чтобы определить начальные цвета для использования.Я набрал около 7700 баллов, используя вышеизложенное, но решил, что мог бы добиться большего успеха, изменив значения цвета и радиуса, поэтому я написал некоторый код скаффолдинга для грубой силы и оптимизировал каждое значение, изменив его -10 .. + 10, повторно рендеринг, запуск валидатора (который я переписал в C для скорости) и сохранение значения, которое дало наименьшую оценку. В конце он сбрасывает массив значений, который я вставляю обратно в код и перекомпилирую. Я пробежал несколько проходов, и это сбило счет примерно на 1000. Затем я удалил код лесов.
Код,
источник
((x-xo)*(x-xo) + (y-yo)*(y-yo)) <= (r*r)
) кажется, что она будет короче и уберет зависимость отmath.h
. С таким размером изображения я не думаю, что что-либо может переполниться.Python 3, оценка 5390,25, 998 байт
Я использовал программу имитации отжига, чтобы привести прямоугольники в форму звездной ночи. Затем он использует размытие по Гауссу, чтобы сгладить прямые прямоугольные края.
Чтобы сохранить несколько байтов, я сжал данные прямоугольника в базу 94.
источник
Python 2, 5238,59 балла
Возможно, пришло время опубликовать мой собственный ответ. Вот изображение
Код выглядит так
Или как шестнадцатеричный дамп:
Он просто распаковывает эту длинную строку в параметры для рисования 95 полупрозрачных эллипсов.
Как и многие другие ответы, код генерируется с использованием генетического алгоритма. Он использует определенный тип генетического алгоритма, который я изобрел, который я называю «алгоритмом генофонда», хотя вполне возможно, что кто-то другой также изобрел его и дал ему другое имя. Вместо того, чтобы иметь популяцию людей, у нас есть 95 «генофондов», по одному на каждый ген. Каждый генофонд содержит 10000 различных версий гена. Ген содержит параметры для одного эллипса (положение, форма, цвет, альфа и его место в z-порядке). На каждой итерации мы создаем две картинки, выбирая по одному гену из каждого из 95 пулов, и гены из картинки с наименьшей оценкой заменяют гены на картине с наихудшей оценкой с небольшой мутацией.
Я запускал его примерно до 378000-й итерации, что заняло пару дней. На тот момент оценка все еще снижалась, но очень медленно, поэтому я сомневаюсь, что она станет намного лучше, без каких-либо изменений в алгоритме.
Вот код генетического алгоритма:
Наконец, вот анимация , показывающая алгоритм на работе. Он показывает лучшее изображение, сгенерированное до сих пор после каждых 1000 итераций. (GIF-файл был слишком большим, чтобы вставить его в этот пост.)
Вероятно, это может быть улучшено с помощью (1) использования трюка кодирования nneonneo для добавления большего количества данных в строку; (2) добавление размытия по Гауссу в конец кода рендеринга (но это сделает его медленнее) и (3) дальнейшее улучшение алгоритма. В настоящий момент он очень быстро достигает приличного значения, но затем меняется очень медленно - если я каким-то образом замедляю первоначальную конвергенцию, это может привести к лучшему результату в конце. Возможно, я когда-нибудь осуществлю эти вещи.
источник
Звездный ,
11428.189450210904.307927710874.1307958Звездный может быть не лучшим языком для этого, но, безусловно, это наиболее подходящий.
Вы можете попробовать это онлайн, однако кажется, что вывод обрезан, поэтому вы не получите полное изображение.
Эта программа выводит несжатые ppm-файлы в стандартный формат.
Вот вывод программы:
объяснение
Чтобы программа вывела все необходимые 123 520 пикселей, я разделил изображение на 8 горизонтальных полос и создал 7 петель, первые 6 из которых печатают одну полосу, а последняя печатает две полосы одного цвета. Код состоит из заголовка, который сообщает файлу ppm, как отформатировать себя и 7 вышеупомянутых циклов.
источник
Python 2, 4684,46
1021 байт.
При этом используется метод декодирования, очень похожий на пару других ответов, но он используется в Python 2, поэтому вместо base85 используются данные в кодировке base64.
Закодированные данные представляют собой изображение формата 64x48 WebP.
Вот код, который я использовал, чтобы найти лучший размер изображения и настройку качества. Я ограничил пространство поиска, чтобы он занимал не более нескольких минут.
источник
Python 2,
5098,24,5080,04,4869,15,4852,87,4755,88589004.Не используется встроенная декомпрессия! Просто утилита изменения размера PIL и вручную раскодированное 16-цветное изображение. Поэтому он должен иметь право на награду.
Программа содержит встроенные символы не ASCII. Он имеет длину 1024 байта и выглядит так:
и в шестнадцатеричном виде:
и генерирует эту картину:
Эта программа злоупотребляет тем фактом, что вы можете вставлять необработанные байты в исходный код Python, если вы избегаете NUL и обратной косой черты.
Сама программа состоит из палитры из
|
16 записей ( разделенная строка) и 16-цветного изображения 40x41 (кодируется с 4 битами на пиксель и декодируется злоупотреблением.encode('hex')
). Размер изображения изменяется до соответствующего размера с помощью бикубического фильтра, и все.Фактическое изображение было сгенерировано с помощью ImageMagick:
и данные палитры и изображения были извлечены из полученного BMP. (Обратите внимание, что мы запрашиваем 18 цветов из ImageMagick, поскольку IM автоматически вставляет некоторые неиспользуемые записи).
Палитра была немного переупорядочена, чтобы уменьшить количество экранированных символов в двоичных данных, а окончательные двоичные данные были отредактированы вручную, чтобы все это уместилось в 1024 байта.
РЕДАКТИРОВАНИЕ: немного изменил код и улучшил точность, запросив 17 цветов из ImageMagick.
Отредактировано: отключение дизеринга привело к значительному улучшению показателей. Сейчас он набрал более 5000 баллов и становится конкурентоспособным с готовыми алгоритмами сжатия!
РЕДАКТИРОВАНИЕ: Добавление
-filter Cosine
дает еще одно значительное улучшение. Агрессивный гольф, благодаря @primo за трюк с UTF-8, позволил мне добавить еще один ряд к картине, что еще больше улучшило счет.источник
!
самом деле по бокам с обеих сторон находятся непечатные символы. Полный цвет -#1d211e
слегка голубоватый темно-серый.#coding:latin
строка может быть заменена меткой порядка байтов UTF-8:
(0xEF, 0xBB, 0xBF).zsh + FLIF + ImageMagick, 4358.14
Благодаря тому, что BPG привлек к себе внимание в качестве кодека с потерями, я усовершенствовал свой высококлассный подход без потерь, используя FLIF вместо PNG, используя трюк @ nneonneo zsh. ImageMagick используется только в качестве апскейлера.
Hexdump (на этот раз с
xxd
, я не понял,hexdump
был нестандартным в моем последнем ответе):Я сгенерировал скрипт, используя ... другой скрипт:
источник
Mathematica, 5076,54
Взвешивая ровно 1024 байта, я наконец удалось побить счет nneonneo ... пока он не улучшил его час назад = (
Не использует готовых алгоритмов сжатия.
(Лучшее описание позже)
источник
HTML / JavaScript,
10855,838000,55 (± 5, на основе браузера)Результаты могут незначительно отличаться из-за различий между браузером или графическим процессором.
Вы должны щелкнуть правой кнопкой мыши> Сохранить изображение как, чтобы сохранить данные холста как изображение, но это единственное взаимодействие, которое требуется.
Я использовал GIMP, чтобы выбрать определенные области и найти их среднее значение. В частности, инструмент выбора цвета и функция «разность слоев» были очень полезны.
Попытка № 1 (10855,83)
Попытка № 2 (8000,55)
источник
Скала, 6003,56
993 персонажа. Один из них - библиотека изображений Scala . Второй импорт - это кодер Base 91 .
Это данные base91:
источник
Ява, оценка 12251,19
На основании этого ответа Mathematica , но с большим количеством прямоугольников. Я, вероятно, продолжу изменять это позже.
Результаты:
Некоторые предыдущие версии:
источник
Python 2 (без встроенного сжатия), оценка 4497,730
При этом используется тот же подход к 16-цветному изображению, который был вручную декодирован, как и в моем предыдущем ответе , но на этот раз я фактически применил стратегию оптимизации с градиентным спуском, чтобы значительно улучшить оценку. Предыдущее представление набрало 4755,886 балла, в то время как новое представление набрало более 250 баллов, превзойдя множество встроенных подходов к сжатию.
Как и прежде, конечная программа имеет длину 1024 байта. Фактически, необработанный вывод алгоритма оптимизации содержал четыре байта, которые были экранированы (
\0
), и которые мне пришлось «выдумать», чтобы уменьшить количество байтов до 1024 байтов. Без выдумки 1028-байтовая программа набрала бы 4490,685 - на 7 баллов лучше.Основная идея заключается в совместной оптимизации палитры и данных. За одну итерацию я ищу все настройки палитры (в основном, каждую модифицированную палитру, которая отличается на 1 в некотором цветовом компоненте) и выбираю модифицированную палитру, которая лучше всего улучшает оценку. Затем я выполняю поиск по всем изменениям данных (каждый модифицированный индексный массив, в котором один пиксель изменяется на какую-то другую запись в палитре) и выбираю модификацию, которая уменьшает оценку (здесь мне наплевать на лучшее, потому что я не хотите бесполезно искать в каждой итерации более 25000 твиков).
Наконец, при генерации окончательного вывода программы я запускаю другой этап оптимизации, который перестраивает палитру, чтобы минимизировать количество обратных слешей, требуемых в конечном выводе (например, для программы, показанной ниже, палитра была переупорядочена с использованием шестнадцатеричной таблицы "0e3428916b7df5ca").
Этот подход привел к значительному количественному и перцептивному улучшению по сравнению с предыдущим наивным подходом ImageMagick. Предыдущее представление:
И новый вывод представления:
Новый подход на основе оптимизации имеет значительно больше деталей и точную цветопередачу.
Вот hexdump финальной программы:
Есть еще возможности для улучшения. Например, простая гистограмма показывает, что некоторые цвета почти не используются:
Это говорит о том, что перебалансированная палитра может повысить эффективность, возможно, достаточно, чтобы поймать 5-е место решения BPG. Тем не менее, я весьма сомневаюсь, что этот подход к оптимизации (или, на самом деле, все, что не связано с экстраординарным механизмом H.265) может занять первое место в реализации BPG.
источник
Perl,
5955,968781245149,56218378Взглянув на подход «непечатной тарабарщины», я решил, что могу попробовать это и в Perl. Опять же, я на самом деле не знаю Perl, поэтому я уверен, что это можно улучшить (на самом деле, наиболее очевидное улучшение, сокращение до 7 байт на эллипс за счет пропуска альфа-канала, уже реализовано для следующей версии, но я ' Я до сих пор работаю над другими частями этого кода, я также думаю, что весь поп / пуш-бизнес может быть в гольфе больше).
Я не думаю, что это на самом деле будет работать на машинах Windows (я не могу проверить), так как я не мог найти простой способ открыть раздел DATA в двоичном режиме - однако это работало на моих машинах Linux.
Я был в состоянии продолжать использовать мой код GA для создания:
Где вывод xxd:
Который генерирует изображение:
Интересно, что, несмотря на то, что он лучше, изображение выглядит для меня несколько хуже - слишком много всего происходит со всеми дополнительными эллипсами, так как с более простым изображением легче работать визуально.
Старые результаты
Увидев ответ Джеймегинана , я использовал эллипсы в качестве примитива для рисования, поскольку в Perl у меня есть доступ к библиотеке GD для рисования. Я вообще не эксперт по Perl, поэтому любые предложения будут полезны. Я использовал генетический алгоритм, который был изменен из моего ответа C ++ .
Кажется, все работает хорошо, но, честно говоря, я немного разочарован в счете. Я мог бы позволить ему работать немного дольше, так как вы можете легко увидеть, что несколько эллипсов не находятся в оптимальных положениях. Тем не менее, даже сейчас это выглядит приятнее для моих глаз по сравнению с решением на основе прямоугольника.
источник
Bash + Netpbm,
4558,54394,1ОБНОВЛЕНИЕ: я улучшил счет, используя SPIHT вместо FIASCO.
SPIHT - это аббревиатура для разбиения множеств в иерархических деревьях. Это высокоэффективный формат сжатия изображений на основе вейвлетов.
Я сжался оригинальный PNG на четверть, а затем преобразуется в PNM , используя
pngtopnm
из Netpbm ст. 10.68, затем удаляют заголовок и преобразовали данные RAW в SPIHT сcodecolr in.raw out.spi 80 96 0.95
и получил файл изображения 913 байт. Затем я преобразовал его обратно вdecdcolr -s out.spi out.raw 0.95
формат RAW , затем преобразовал в формат PNMrawtoppm -bgr 96 80
, перевернул с помощьюpamflip -tb
, увеличил до исходного размера с помощьюpamscale -xsize 386 -ysize 320 -filter sinc
и сохранил в файл PNM, который читается PIL. Вот мой сценарий (1 КБ):Вот вывод PNG:
Ниже мой более простой ответ:
FIASCO - это аббревиатура от Fractal Image And Sequence COdec, это высокоэффективная реализация сжатия фракталов с потерями .
Я сжался оригинальный PNG на четверть, а затем преобразуется в PNM , используя
pngtopnm
из Netpbm v. 10.68, а затем преобразуется в облом сpnmtofiasco -q=14 -z=3
и получил файл изображения 969 байт. Затем я преобразовал его обратно в формат PNMfiascotopnm
, увеличил до исходного размераpamscale -xyfill 386 320
и сохранил в файле PNM, который читается PIL. Вот мой сценарий (1 КБ):На самом деле, я сначала сделал это в Windows
cmd
, но скрипт не умещался в 1 КБ. Тогда я переписал это вbash
. Вот вывод PNG:источник
Рубин, 7834,38
Это было весело!
Я использовал программу генератора ruby, чтобы написать скрипт ruby следующим образом:
Хотя размер сгенерированного файла ruby составляет менее 1024 байтов:
Обратите внимание, что мой алгоритм оценки случайным образом отбирает кучу цветов и выбирает тот, который дает наименьшее отличие от ORIGINAL.png. Поскольку он вероятностный, я несколько раз перезапускал сценарий и выбирал самый низкий результат.
Вот мой лучший сценарий на данный момент:
Сгенерировано следующее изображение, набравшее 7834 балла:
Чтобы увидеть, как мой алгоритм пришел к этому, вот анимированный GIF, показывающий, как он разбивает прямоугольники:
Мой код полностью на GitHub на https://github.com/jrotter/starry_night_contest
источник
Ява, 9215.38294502
Считывание изображения в формате GIF размером 8x6 пикселей (!) Из строки в кодировке Base64 (содержащей 368 символов) и билинейное масштабирование.
РЕДАКТИРОВАТЬ: Результат, согласно запросу в комментариях, показан на этом изображении:
источник
Python 3, 5797.125628604383
Программа сжатия сначала усекает биты изображения, а затем преобразует основание 2 в основание 36.
Программа декодирования делает это в обратном порядке и изменяет размеры изображения.
источник