Я работаю над фильтром "искажения изображения" старой школы. По сути, у меня есть двумерный массив пикселей (игнорируя пока вопрос о том, являются ли они цветом, оттенками серого, плавающей точкой, RGBA и т. Д.) И другой двумерный массив векторов (с компонентами с плавающей запятой), причем изображение как минимум размером с векторный массив. В псевдокоде я хочу сделать это:
FOR EACH PIXEL (x,y)
vec = vectors[x,y] // Get vector
val = get(img, x + vec.x, y + vec.y) // Get input at <x,y> + vec
output[x,y] = val // Write to output
Подвох в том, что get()
необходимо билинейно сэмплировать входное изображение, поскольку векторы могут ссылаться на субпиксельные координаты. Но в отличие от билинейной выборки, скажем, в текстурном отображении, где мы можем преобразовать интерполяционную математику в цикл, так что все это просто добавляет, здесь считывания происходят из случайных мест. Итак, определение get()
выглядит примерно так:
FUNCTION get(in,x,y)
ix = floor(x); iy = floor(y) // Integer upper-left coordinates
xf = x - ix; yf = y - iy // Fractional parts
a = in[ix,iy]; b = in[iy+1,iy] // Four bordering pixel values
b = in[ix,iy+1]; d = in[ix+1,iy+1]
ab = lerp(a,b,xf) // Interpolate
cd = lerp(c,d,xf)
RETURN lerp(ab,cd,yf)
и lerp()
это просто
FUNCTION lerp(a,b,x)
RETURN (1-x)*a + x*b
Предполагая, что ни входное изображение, ни векторный массив не известны заранее, какие виды оптимизации высокого уровня возможны? (Примечание: «Использовать GPU» - это мошенничество.) Я могу подумать о том, чтобы переставить интерполяционную математику в get()
, чтобы мы могли кэшировать считывание пикселей и промежуточные вычисления для заданного (ix, iy). Таким образом, если последовательный доступ к одному и тому же подпиксельному квадру, мы можем избежать некоторой работы. Если векторный массив известен заранее, то мы можем изменить его так, чтобы координаты, переданные в get()
, были более локальными. Это также может помочь с локальностью кэша, но за счет того, что записи в output
будут повсюду. Но тогда мы не можем делать такие причудливые вещи, как масштабирование векторов на лету или даже перемещать эффект деформации из первоначального предварительно рассчитанного местоположения.
Единственная другая возможность - использовать векторные компоненты с фиксированной точкой, возможно, с очень ограниченными дробными частями. Например, если векторы имеют только 2-битные дробные компоненты, то есть только 16 подпиксельных областей, к которым можно получить доступ. Мы могли бы заранее рассчитать вес для них и вообще избежать большой части интерполяционной математики, но с ударом по качеству.
Есть еще идеи? Я хочу накопить несколько различных методов, прежде чем применять их и посмотреть, какой из них лучший. Если бы кто-то мог указать мне на исходный код быстрой реализации, это было бы здорово.