[Разработка моих комментариев к Патрику - все вышло немного из-под контроля!]
Это действительно интересный вопрос, и одна из причин, по которой он интересен, заключается в том, чтонет «правильного» ответа.Представление цвета и интерполяция данных могут выполняться разными способами.Вы должны адаптировать подход к вашей проблемной области.Так как нам не дали много априорной информации об этой области, мы можем исследовать только некоторые из возможностей.
Бизнес цветов несколько запутывает воду, поэтому давайте отложим это в сторонувременно и сначала подумайте об интерполяции простых скаляров.
Экскурсия в интерполяцию
Допустим, у нас есть несколько точек данных, таких как:
Мы хотим найти значение y
на этом графике в точках вдоль оси x
, отличных от тех, для которых у нас есть известные значения.То есть мы ищем функцию
y = f(x)
, которая проходит через эти точки.
Очевидно, что есть много разных способов присоединиться кточек.Мы могли бы просто связать их с отрезками прямой линии.Или нам может потребоваться плавная кривая, и эта кривая может быть простой или произвольно сложной:
Здесь легко понять, откуда берутся красные линии - мыпросто рисуя прямые линии от одной известной точки к другой.Зеленая линия также выглядит разумной, хотя мы добавляем некоторые предположения о том, как должна вести себя кривая.Синюю линию, с другой стороны, было бы трудно оправдать только на основе точек данных, но может * быть обстоятельствами, когда у нас есть причины для моделирования системы с использованием такой формы - как мыпосмотрим чуть позже.
Обратите внимание также на пунктирные линии, идущие от сторон каждой кривой.Они идут за известными точками, что называется экстраполяция , а не интерполяция.Это часто немного более сомнительно, чем интерполяция.По крайней мере, когда вы переходите из одной известной точки в другую, у вас есть доказательства, что вы движетесь в правильном направлении.Принимая во внимание, что чем дальше вы добираетесь от известных точек, тем больше вероятность, что вы отклонитесь от пути.Но, тем не менее, это полезный метод, и он вполне может иметь смысл.
Хорошо, так что картина хороша и все, но как мы генерируем эти строки?
Нам нужно найти f(x)
, что даст нам желаемое y
.Существует много различных функций, которые мы могли бы использовать в зависимости от обстоятельств, но наиболее распространенным является использование полиномиальной функции, например:
f(x) = a0 + a1 * x + a2 * x * x + a3 * x * x * x + ....
Теперь, учитывая N
различных точек данных, это всегдаможно найти идеально подходящую кривую, используя многочлен степени N-1
- прямую линию для двух точек, параболу для трех, кубическую для четырех и т. д., но если данные не являются необычайно хорошими, кривая стремится ксойти с ума по мере повышения степени.Поэтому, если нет веских оснований полагать, что поведение данных хорошо моделируется полиномами более высокой степени, вместо этого обычно вместо этого интерполируют данные кусочно , подбирая отдельный сегмент кривой между каждой последовательной парой точек.
Как правило, каждый сегмент моделируется как полином степени 1 или 3 .Первый - это просто прямая линия, и он используется потому, что он действительно прост и не требует никакой информации, кроме самих двух точек данных.Последний является кубическим сплайном и используется, потому что это самый простой полином, который даст вам плавный переход через каждую точку.Однако его вычисление немного сложнее и требует двух дополнительных фрагментов информации для каждого сегмента (в зависимости от того, какая именно часть используется, зависит от используемой вами формы сплайна).
Линейная интерполяция достаточно проста, чтобы войти в одну строку кода.Если наша первая точка данных равна (x1, y1)
, а наша вторая - (x2, y2)
, то линейно-интерполированное y
для любого промежуточного звена x
равно:
y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)
(вариации этого появляются в некоторыхдругие ответы.)
Кубические сплайны слишком сложны, чтобы здесь углубляться, но Google должен найти несколько приличных ссылок.В любом случае, в этом случае они, возможно, излишни, поскольку у вас есть только три балла.
Вернуться к вопросу
Имея все это под нашими поясами, давайте рассмотрим проблему, как описано:
У нас есть линия (показана здесь серым цветом), цвет которой известен только в трех точках, и нас просят вычислить, какой цвет будет в другой точке.Поскольку у нас нет никаких знаний о том, как распределяются цвета, мы должны сделать некоторые предположения.
Одним из ключевых предположений является то, что изменения цвета вдоль линии будут непрерывными , по крайней мерев некотором приближении.Понятно, что если строка действительно выглядела так:
, тогда все эти более ранние вещи об интерполяции уходили бы в окно.У нас не было бы оснований решать, какого цвета должна быть какая-либо часть, и мы должны просто сдаться и пойти домой.Давайте предположим, что это не так, и нам нужно что-то интерполировать.
Известные цвета определены как RGB .В этом представлении каждый канал представляет собой отдельное скалярное значение, и мы можем рассматривать его как полностью независимое от других.Таким образом, один вполне разумный подход состоит в том, чтобы сделать кусочно-линейную интерполяцию каждого канала и затем рекомбинировать результаты.
Это дает нам что-то вроде этого:
Это нормально, но некоторые аспекты результата нам могут не понравиться.Во-первых, переход от красного к зеленому проходит через довольно мутный серо-коричневый.Другая причина заключается в том, что зеленый пик на уровне 0,3 немного резкий.
Важно отметить, что в отсутствие более полной спецификации это действительно просто эстетические проблемы.Наша техника идеально звучит, но не дает того результата, которого мы могли бы пожелать.Подобные вещи зависят от нашей конкретной проблемной области, и в конечном итоге все зависит от выбора.
Поскольку у нас всего три точки данных - и поскольку Ганс Пассант предложил это - возможно, мы могли бы вместо этого попытаться подобратьпарабола для моделирования всей кривой на каждом канале?Это правда, у нас нет никаких оснований думать, что это хорошая модель, но не мешало бы попробовать:
Различиямежду этим градиентом и последним поучительны.Квадратик сгладил все, но также резко упал.Помните, что зеленый канал начинается и заканчивается в 0. Парабола симметрична, поэтому ее максимум должен быть посередине.Единственный способ, которым он может соответствовать зеленому росту к 0,3, - это продолжать расти до 0,5.(Существует аналогичный эффект в красном канале, но он менее очевиден, потому что в этом случае это недолгое и значение ограничено до 0.)
Есть ли у нас какие-либо доказательства того, что такая форма действительно присутствует внаша цветная линия?Нет: мы явно представили это через наш выбор модели.Это не делает его недействительным - у нас могут быть веские причины для того, чтобы это работало таким образом - еще раз, это вопрос выбора.
Но как насчет ВПГ?
Пока что мыМы придерживались оригинального цветового пространства RGB, но, как поспешили указать на это разные люди, это может быть далеко не идеальным вариантом для интерполяции: цвет и интенсивность связаны в RGB, поэтому интерполяция между двумя разными цветами полной интенсивности обычно приводит вас к некоторымсерое низкоинтенсивное среднее.
В HSV представление, цвет и интенсивность находятся в разных измерениях, поэтому у нас нет этой проблемы. Почему бы не преобразовать и не выполнить интерполяцию в этом пространстве?
Это немедленно вызывает трудности - или, во всяком случае, другое решение. Отображение между HSV и RGB не является биективным ; в частности, black , который является одной из наших трех точек данных, является единственной точкой в пространстве RGB, но занимает всю плоскость в HSV. Мы не можем интерполировать между точкой и плоскостью, поэтому нам нужно выбрать одну конкретную черную точку HSV, чтобы перейти к ней.
Это основа оригинального решения Патрика, в котором H и S специально выбраны, чтобы сделать весь градиент цвета линейным. Результат выглядит примерно так:
Это выглядит намного красивее и красочнее, чем предыдущие попытки, но есть несколько вещей, с которыми мы могли бы поспорить.
Одна важная проблема заключается в том, что в случае V, где у нас все еще есть определенные данные во всех трех точках, эти данные на самом деле не являются линейными, и поэтому линейное приближение является лишь приближенным. Это означает, что значение, которое мы видим здесь в 0,3, не совсем то, что должно быть.
Еще один, на мой взгляд, более крупный спор: откуда весь этот синий цвет? Все три из наших известных точек данных RGB имеют B = 0. Кажется немного странным внезапно представить целую кучу синего цвета, для которого у нас, похоже, нет никаких доказательств. Проверьте этот график компонентов RGB в интерполяции Патрика HSV:
Причина синего в том, что при переключении цветовых пространств мы специально выбрали модель, в которой, если вы продолжите переходить от зеленого, вы неизбежно получите синий. В то же время нам пришлось отбросить одну из наших точек данных оттенка, и мы решили заполнить ее линейной экстраполяцией из двух других, что означает, что мы do просто сохраняем при движении, от зеленого до синего до холмов и далеко.
Еще раз, это не неверно, и у нас может быть веская причина сделать это таким образом. Но, на мой взгляд, это немного больше, чем предыдущий кусочно-линейный пример, из-за этой экстраполяции.
Так это единственный способ сделать это в HSV? Конечно, нет. всегда больше вариантов.
Например, вместо того, чтобы выбирать значения H и S на уровне 1,0 для максимизации линейности, как насчет того, чтобы вместо этого выбрать их, чтобы минимизировать изменения в кусочно линейной интерполяции? Как это бывает, для S две стратегии совпадают: это 100 в обеих точках, поэтому мы также делаем 100 в конце. Два сегмента коллинеарны. Для H, тем не менее, мы просто оставляем это во втором сегменте. Это дает такой результат:
Это не так мило, как предыдущий, но мне кажется немного более правдоподобным. Еще раз, однако, это в значительной степени эстетическое суждение. Это не делает этот «правильный» ответ более, чем это делает ответ Патрика или любого другого «неправильным». Как я уже сказал в самом начале, «правильного» ответа нет. Все дело в том, чтобы делать выбор в соответствии с вашими потребностями в конкретной проблеме - и осознавать, что вы сделали этот выбор и как они влияют на ваш результат.