Интерполировать градиентный шум в Julia

Я пытаюсь реализовать и изучить код здесь, но у меня возникают проблемы с интерполировать это. Это мой код из моей реализации в Julia:

lerp(a, b, w) = a * (1 - w) + b * w

function Noise(x, y)
    n = x + y * 53;
    n = (n << 13) $ n;
    return (1.0 - ( (n * ((n * n * 15731) + 789221) +  1376312589) & 0x7fffffff) / 1073741824.0);
end

function coherentNoise(x,y)
   x₁ = convert(Int64,modf(x)[2])
   y₁ = convert(Int64,modf(y)[2])
   xᵣ = x - x₁
   yᵣ = y - y₁
   q1 = Noise(x₁-1,y₁+1)
   q2 = Noise(x₁+1,y₁+1)
   q3 = Noise(x₁-1,y₁-1)
   q4 = Noise(x₁-1,y₁+1)

   v = lerp(q1,q2,xᵣ)
   v1 = lerp(q3,q4,xᵣ)
   return abs(lerp(v,v1,yᵣ))
   #value = bilinear(q1,q2,q3,q4,x₁,x₁-1,x₁+1,y₁,y₁-1,y₁+1)
   #return abs(value)
end


arr = Array{Float64}(height,width)

for x = 1:height
    for y = 1:width
        nx = x/60
        ny = y/60
        arr[x,y]=coherentNoise(nx,ny)
    end
end

вот результат:

введите здесь описание изображения

Я пробовал также использовать эту функцию билинейной интерполяции, но получил худший результат.

# bilinear interpolation
function bilinear(Q1,Q2,Q3,Q4,x,x1,x2,y,y1,y2)
    R1 = ((x2-x)/(x2-x1))*Q3 + ((x-x1)/(x2-x1))*Q4
    R2 = ((x2-x)/(x2-x1))*Q1 + ((x-x1)/(x2-x1))*Q2
    P = ((y2-y)/(y2-y1))*R1 + ((y-y1)/(y2-y1))*R2
    return P
end

результат:

введите здесь описание изображения

Я не знаю, проблема в функции theNoise или в чем-то еще.

Обновлять

Я получаю наилучшие результаты, используя билинейную интерполяцию со следующей функцией генератора шума:

function coherentNoise(x,y,n::Int64)
    #octa3e
    o = 0.25
    #octave x and y
    x /=n
    y /=n 
    #decimal value
    x₁ = x < 0 ? x : x-o
    y₁ = y < 0 ? y : y-o
    x₂ = x+o
    y₂ = y+o
    #calculate corners data
    q1 = abs(Noise(floor(Int64,x₁),floor(Int64,y₂)))
    q2 = abs(Noise(floor(Int64,x₂),floor(Int64,y₂)))
    q3 = abs(Noise(floor(Int64,x₁),floor(Int64,y₁)))
    q4 = abs(Noise(floor(Int64,x₂),floor(Int64,y₁)))
    #bilenear interpolation

    value = bilinear(q2,q1,q4,q3,x,x₁,x₂,y,y₁,y₂)
    return abs(value)
end

Результат:

введите здесь описание изображения

Я думаю, что проблема в том, как я выбираю точки для билинейной интерполяции, не знаю, как это сделать правильно.

Обновление 2:

Это код для создания изображений:

for x = 1:height
    for y = 1:width
        arr[x,y]=coherentNoise(x,y,50)
    end
end

imwrite(convert(Image,arr),"desktop/projects/julia/Noise/test2.png")

Обновление 3

Благодаря ответу Дэна Гетца я получаю лучший результат, но с некоторыми странными "червями"

выход:

введите здесь описание изображения


person exsnake    schedule 16.10.2016    source источник
comment
не возражаете ли вы показать код, который создает эти графики? :)   -  person Tasos Papastylianou    schedule 17.10.2016
comment
@TasosPapastylianou Добавил в обновлении 2.   -  person exsnake    schedule 17.10.2016
comment
В coherentNoise(x,y) в первом листинге q1 = Noise(x₁-1,y₁+1) должно быть q1 = Noise(x₁,,y₁+1) без -1. x₁ и y₁ шагают на 1, когда x и y изменяются медленно, и цель состоит в том, чтобы интерполировать функцию Noise из углов 1 квадрата, а не 2 квадратов (то же самое относится к следующим аналогичным линиям).   -  person Dan Getz    schedule 18.10.2016
comment
В coherentNoise(x,y) в первом листинге q1 и q4 одинаковы и должны находиться в разных углах. Хорошо ... Переписанный coherentNoise в ответе.   -  person Dan Getz    schedule 18.10.2016
comment
Шум червя кажется мне результатом ограничения значений положительными, т.е. отрицательные значения представлены черным цветом. Попробуйте сделать образ из 0.5*(arr+1.0). Лучше?   -  person Dan Getz    schedule 18.10.2016
comment
Я! теперь он работает! Спасибо большое. Не могли бы вы объяснить мне еще немного 0.5*(arr+1.0). И почему функция шума возвращает отрицательные числа, если они являются проблемой? Спасибо! опять таки   -  person exsnake    schedule 18.10.2016
comment
Функция Noise возвращает случайное число от -1,0 до 1,0, а coherentNoise плавно интерполирует его между точками сетки. Таким образом, изображение имеет плавные числа от -1,0 до 1,0. Для изображений необходимо выбрать уровень яркости, который обычно представлен числом от 0,0 до 1,0. Таким образом, 0.5*(arr+1.0) преобразует масштаб (-1,0,1,0) в масштаб (0,0,1,0).   -  person Dan Getz    schedule 18.10.2016
comment
@DanGetz Спасибо за помощь!   -  person exsnake    schedule 18.10.2016


Ответы (1)


Без возможности тестирования кода это должно потребовать проверки. В принципе, мне кажется, ваша интуиция, что проблема в выборе точек интерполяции, верна. Это попытка исправить это (см. Также комментарии).

function coherentNoise(x,y)
   x₁,xᵣ = floor(Int64,x),mod(x,1)
   y₁,yᵣ = floor(Int64,y),mod(y,1)
   q00 = Noise(x₁,y₁)
   q10 = Noise(x₁+1,y₁)
   q01 = Noise(x₁,y₁+1)
   q11 = Noise(x₁+1,y₁+1)

   v0 = lerp(q00,q10,xᵣ)
   v1 = lerp(q01,q11,xᵣ)
   noise = lerp(v0,v1,yᵣ)
   return noise
end

Примечания:

  • qs переименован в q00 и так далее, чтобы указать, какой угол по смещению на X (первое число) и Y (второе число).
  • Идентичные q1 и q4 исправлены.
  • floor и mod( ,1) используются вместо modf, поскольку они выбирают постоянное направление округления (вниз) независимо от знака.
  • Функция Noise должна вводить аннотацию своих параметров, чтобы ограничить их значениями Int32, и ; в конце строки в этой функции не требуется. Это хеш-функция, и тот же эффект можно легко закодировать с помощью хеш-функции Джулии и небольшой оболочки.

Например:

Noise(x,y) = 1.0-2.0*hash((x,y))/typemax(UInt)

это более стилизованная под Джулия замена для Noise.

Если вы попробуете это и прокомментируете ошибки, мы можем попытаться исправить функцию.

person Dan Getz    schedule 18.10.2016
comment
Теперь я получаю сглаженные результаты, но странные. Обновлю вопрос. Спасибо за шумовую функцию. - person exsnake; 18.10.2016
comment
Обновлено, я не знаю, почему у меня такой червячный шум. Должен быть метод интерполяции, если вы видите, что черви из первого списка тоже присутствуют. Так почему бы не использовать билинейную интерполяцию из первого обновления? - person exsnake; 18.10.2016