@TeslaFeo молодец, я посмотрю. @voral конечно фон учитывается ровно так же как всё остальное. если фона много, его цвет будет доминировать.
У меня самого есть кой-какие идеи насчёт оптимизации. Не хочу сейчас озвучивать, чтобы не повлиять на чей-то выбор. Позже раскажу.
Нарештi сподобился. Спасибо @artoodetoo за интересную задачу, хоть появился повод что-то нормально на гитхабе оформить. Ты уж извини насчет прав, публикую под MIT =) Paletter. https://github.com/VasyaSh/Paletter Я обратил внимание на то, что в примере из первого сообщения всегда используется одна и та же палитра. Это означает, что не обязательно нужно выбирать цвета из картинки. Можно взять сравнительно небольшую палитру и притягивать цвета изображения к её цветам, начисляя очки каждому цвету за каждый пиксель. Поэтому я решил генерировать свою палитру из 210 цветов и 46 градаций серого Нельзя сказать, что это очень далеко от правды. Во-первых, картинку в любом случае приходится уменьшать, а это означает потерю оригинальных цветов на ресэмплинге. Во-вторых, в полноцветной картинке, с большой вероятностью, действительно присутствуют эти оттенки. Теперь самый главный финт. Когда есть оценка по всей палитре, мы можем создать новую палитру из нескольких топовых цветов и повторить процедуру, притянув минорные цвета к наиболее подходящим основным. Сначала я так и сделал, но потом понял, что это очень не оптимально и можно поступить проще - не "прогонять" картинку второй раз, а "прогнать" нашу базовую палитру, сравнивая её цвета между собой и отдавая очки лишних цветов наиболее близким основным. Это всё оформлено в виде наглядного (в ущерб быстродействию, конечно) ООП. Хотя кое-какие оптимизации есть. Paletter.php - класс, с которым можно полноценно работать. Classes/Base.php - класс палитры с функцией построения 256-цветного спектра. Classes/RealImage.php - класс представляет анализируемую картинку. Создает для себя уменьшенную до 200 пикс. по стороне картинку и разбирает попиксельно. Classes/PseudoImage.php - класс для подмены (на анализ) реальной картинки на фейк с заданным количеством пикселей заданных цветов. То есть, как было сказано, не нужно второй раз гонять картинку по уменьшенной палитре. Достаточно передать вот такой объект с информацией, каких пикселей какого цвета сколько в нём (ведь это как раз результат первого анализа). Classes/Color.php - класс цвета. Умеет разбирать целочисленный индекс на составляющие по RGB, а так же пересчитывать целое число при изменении значений каналов. В папке примеров готовые скрипты для просмотра палитры, разбора картинки на 256 цветов, разбор на топ-10 цветов. Анализ картинки на моем сервере занимает около 30 секунд. Любая картинка (кроме маленькой) будет анализироваться одинаково долго, потому что все приводятся к примерно одинаковому размеру. А что меня осенило в понедельник, это способ нахождения ближайшего цвета. Как сравнивать? Есть элементарный прием. Будем считать значения R, G, B как координаты в трехмерном пространстве x, y, z. Тогда длина отрезка между двумя цветами рассчитывается по формуле Здравствуй, школа. Хотя, это только предположение, что ближайшие цвета будут похожими. Но результаты, вроде бы. приемлемы. И есть мысль, что можно в одну функцию уместить редукцию количества цветов с самой картинки, "притягивая" ближайшие друг к другу, до сокращения к нужному числу.
@[vs], а если берем цвет (0,0,100). И есть два цвета (0,100,100) и (0,0,300). (утрировано развел).Точно не окажемся в ближнем, но визуально другом цвете? --- Добавлено --- Даже лучше с одним расстоянием (0,100,100) и (0,0,200)
ну видимо ты так отказался от премии. ещё не факт, что ты бы её заслужил народ, TeslaFeo у нас вне конкурса. челендж продолжается. никак не соберусь посмотреть код. в любом случае поздравляю! жди от меня issues на гитхабе.
@voral как бы да, темный синий (0, 0, 100) запросто окажется ближе к темному сине-зеленому (0, 99, 100) чем к яркому синему (0, 0, 200), однако тут можно спорить, что лучше. Вспоминается эта иллюзия с оранжевой ячейкой на темной стороне. @artoodetoo я открыт для пожертвований
моя идея оптимизации в том, чтобы доверить тяжелые процедуры сишным библиотекам. то есть делегировать GD или ImageMagic. думаю сначала надо их попросить ужать картинку до какого-то скромного размера. суть в том, что маленькая превьюшка содержит те же цвета в среднем. пикселы могут потеряться, но вариант масштабирования imagecopyresampled() бережно относится к цвету, вычисляя средние значения. в чём-то картинка станет даже достовернее с точки зрения зрения . кто когда-нибудь смешивал краски на палитре, поймёт о чём я. затем я думаю поиграть с imagetruecolortopalette() чтобы упростить палитру. ну а со скромным остатком пикселей и цветов уже можно на PHP работать за ограниченное время
Мысли в слух (пока не проверял):для метода с расстоянием в 3D. Корень,квадрат,сложение и вычитание. Заменить на слеующее. Например принимаем параметр погрешности 8. И каждый цвет приводим следующим образом: PHP: function convert(array $rgb,$koeff = 8) { return [ 'r' => intdiv($rfb['r']/$koef) * $koef + $koef / 2, 'g' => intdiv($rfb['g']/$koef) * $koef + $koef / 2, 'b' => intdiv($rfb['b']/$koef) * $koef + $koef / 2, ]; } --- Добавлено --- Точнее правильнее будет с математическим округлением
@artoodetoo, может пора ТЗ актуализировать? Например, может ли использоваться imagemagik? Если требуется 1 оттенок вывести на 100% - это будет преобладающий оттенок или усредненный оттенок всей картинки? В примере @[vs] два красных оттенка считать одинаковыми или разными? Ну и почему @TeslaFeo вне конкурса? Он выполнил все пункты ТЗ.
@Maputo я не думаю, что такие детали надо конкретизировать. по мне так выводы можно делать только попробовав код на нескольких разных картинках, взять результат и зарядить в поиск, на который я дал ссылку. если результат будет на глаз близок к исходной палитре, значит получилось. лично мне по барабану что там за цифры #100100100 или #0f8100104, мне интересно похоже или не похоже.
@artoodetoo я поигрался с resized и resampled, и выяснил, проблема с маленькими фрагментами практически не решаема. К примеру, какой-то цвет может суммарно занимать прилично места, но быть раздроблен на мелкие фрагменты по всему изображению. Уменьшение без сглаживания его просто съест, но сохранит соседние цвета. Со сглаживанием - смешает в какую-то кашу непонятного цвета, которая в итоге будет в результате. @voral можно в математической формуле, к примеру после возведения в квадрат, делить на коэффициент лидирующий канал, тем самым сокращая расстояние между цветами с одинаковым лидирующим каналом.
зайду издалека: эксперимент. сделай в фотошопе картинку где вертикальные полоски в 1 пиксель толщиной чередуются. например каждая вторая синяя, а каждая первая жёлтая. размножь это до, например, 300 пикселей в ширину. теперь отодвинься от экрана и посмотри какого цвета картинка. она зелёная! так какой цвет нам надо искать в итоге?
@[vs], тут даже не лидирующий, вероятно, а все надо на их весовые коэффициенты. Ведь при одинаковом лидирующем важен будет уже второй канал.
мне не удалось расставить пиксели равномерно. видна текстура ))) но думаю суть понятна. глаз "замыливает" мелкие детали, вычисляет усреднённый цвет. поэтому я считаю, что потеря мелких фрагментов не критична, когда наша цель выделить преимущественные цвета. по человечески это зеленый цвет, а по машинному синий + желтый. но в итоге, повторюсь: только реальный прогон на нескольких сильно разных картинках может выявить лучший вариант. --- Добавлено --- грязно зеленый. другие оттенки исходных цветов дали бы более чистый результат
ИМХО уменьшать картинки не надо. Надо выбрать ширину диапазонов по вкусу. 40 сек - это не много. Можно в цикл пачку картинок засунуть, запустить через консоль и оставить на ночь. Результаты сохранить в БД и потом пользоваться. Или для добавления картинок можно реализовать что-то типа очереди и кроном запуливать по ночам.
источник: http://www.myshared.ru/slide/1294317/ Цвет. Основы цветоведения. Изобразительное искусство 6 класс
Компьютеры складывают цвета так PHP: $color1 = 0xFFFF00; $color2 = 0x0000FF; echo dechex(($color1 ^ $color2) / 1.875); из синего + желтый получится серый 888888. --- Добавлено --- А не, это фигня какая-то. Но не фигня, что ресайзинг сводит к серому (по крайней мере в Paint).
ресайзить не надо. Надо как-то пиксели объединить в группы и вычислить какой цвет летит в глаз пользователю) при этом четкие границы в группах пикселей быть не может. Шизофрения короче какая-то) мне пока-что задача кажется нерешаемой. Можно на выходных побаловаться. Если научиться вычислять зеленый из синего и желтого, то можно брать группы пикселей, распределять равномерно по площади и вычислять выходной цвет. Но тут упрешься в разную плотность пикселей на разных устройствах. Короче хз...
Этот пример как раз и показывает что уменьшать изображения перед анализом нельзя. Т.к. исходное избражение может состоять, например, четких синих и желтых элементов, и именно так и выглядеть (предположим у нас картинка 5000 х 5000 квадраты размером 50х50) а она у нас сведется к грязно зеленому. Более того если уменьшать правильно то надо не за один подход 5000x5000 -> 100x100. А в несколько этапов (сейчас конкретики не помню, подчерпнул из статей по работе с фотографиями). Т.е. это дополнительные затраты времени и ресурсов. Более того. если вернуться к исходному ТЗ, как я понял, наша цель максимально быстро найти фотографии по заданным цветам. Т.е. анализировать картинки на ходу уже не правильно,правильно, как и прозвучало выше, их индексировать. Т.е. сразу скорость анализа картинки уходит на второй план. Как только снимается вопрос скорости анализа картинки так появляется возможность выполнять все с минимальной погрешностью. (В конце концов систему можно будет масштабировать - разделяя задачи поиска и анализа между серверами. Ну и несколько заметок на полях: 1. Стоит учитывать прозрачность. Т.е. пикселы у которых прозрачность 0 вообще убирать. С полупрозрачными надо подумать,. Т.е. alpha возвращаемый imagecolorat то же стоит учитывать 2. Для ускорения анализа - написать модуль для php. (с, c++, freepascal и т.п.)....