外贸网站建设公司,茶叶 企业 网站建设,赣县网站制作,别人的做网站柏林噪声
随机噪声 如上图所示随机噪声没有任何规律可言#xff0c;我们希望生成有一些意义的局部连续的随机图案
一维柏林噪声 假设希望生成一段局部连续的随机曲线#xff0c;可以采用插值的方式#xff1a;在固定点随机分配y值#xff08;一般是整数点#xff09;我们希望生成有一些意义的局部连续的随机图案
一维柏林噪声 假设希望生成一段局部连续的随机曲线可以采用插值的方式在固定点随机分配y值一般是整数点其他的点使用插值算法
方法一线性插值的方式
公式如下 【数字图像处理】二维2D线性插值的应用 y a*y1 (1-a)*y2
我们画图看看
import math
import numpy as np
import matplotlib.pyplot as pltperm [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]def perlin1D(x):# 整数x1和x2的坐标x1 math.floor(x)x2 x1 1# x1和x2的梯度值grad1 perm[x1 % 255] * 2.0 - 255.0grad2 perm[x2 % 255] * 2.0 - 255.0#x1和x2指向x的方向向量vec1 x - x1vec2 x - x2# x到x1的距离即vec1利用公式3计算平滑参数t 3 * pow(vec1, 2) - 2 * pow(vec1, 3)#梯度值与方向向量的乘积product1 grad1 * vec1product2 grad2 * vec2return product1 t * (product2 - product1)def linear1D(x):# 整数x1和x2的坐标x1 math.floor(x)x2 x1 1# y值 随机数grad1 perm[x1 % 255] * 2.0 - 255.0grad2 perm[x2 % 255] * 2.0 - 255.0tx - x1return grad1 t * (grad2 - grad1)def linear1D_plus(x):# 整数x1和x2的坐标x1 math.floor(x)x2 x1 1# x1和x2的梯度值grad1 perm[x1 % 255] * 2.0 - 255.0grad2 perm[x2 % 255] * 2.0 - 255.0#x1和x2指向x的方向向量vec1 x - x1vec2 x - x2tx - x1#梯度值与方向向量的乘积product1 grad1 * vec1product2 grad2 * vec2return product1 t * (product2 - product1)def draw1D():# 绘制散点图x0[]y0[]for i in range(11):x0.append(i)y0.append( perm[i] * 2.0 - 255.0)plt.scatter(x0, y0,colorred)# 绘制1D的图像x np.linspace(0, 10, 100)y np.zeros(100)y1 np.zeros(100)y2 np.zeros(100)for i in range(100):y[i] perlin1D(x[i])y1[i] linear1D(x[i])y2[i] linear1D_plus(x[i])# 绘制图像plt.plot(x, y,colordeepskyblue)plt.plot(x, y1,colorgreen)plt.plot(x, y2,colororange)plt.show()draw1D()
线性插值
x取[0,10]这个区间y在整数点随机取值非整数点使用线性插值 ps 随机值使用伪随机数perm柏林噪声在图像领域使用颜色的取值范围是[0,255]所以perm的值也是[0,255] 上图红色的点是整数点随机取值的结果绿色的线是线性插值。 y t ∗ y 2 ( 1 − t ) ∗ y 1 y 1 t ( y 2 − y 1 ) y t*y2 (1-t)*y1 y1 t(y2- y1 ) yt∗y2(1−t)∗y1y1t(y2−y1) t x − x 1 tx-x1 tx−x1
线性插值plus
我们希望它更平滑一点如果插值点x的值y与附近点x1,x2的位置相关 所以改进上述算法 y t ∗ y 2 ∗ w 2 ( 1 − t ) ∗ y 1 ∗ w 1 y 1 ∗ w 1 t ( y 2 ∗ w 2 − y 1 ∗ w 1 ) y t*y2*w2 (1-t)*y1*w1 y1*w1 t(y2*w2 - y1*w1 ) yt∗y2∗w2(1−t)∗y1∗w1y1∗w1t(y2∗w2−y1∗w1) w是权重系数也是柏林算法中的方向向量vec1 x - x1 如图中黄色的线
柏林噪声
柏林噪声在此基础上再加强一步 t 3 t 2 − 2 t 3 t3t^2 -2t^3 t3t2−2t3
算法步骤 input: x
计算周围的点x1 , x2计算x1 , x2 梯度 : grad1 grad2 随机取[0,255]方向向量: (vec1 x-x1 ;vec2 x-x2)梯度值与方向向量的乘积 productgrad*vec计算系数 t3t^2 -2t^3插值y product1 t * (product2 - product1) output :y
根据上述原理 可以画一个不规则的圆形
def drawCircle():#画圆形# 创建一个坐标系fig, ax plt.subplots()# 定义圆心和半径center (0, 0)radius 10# 生成圆的数据theta np.linspace(0, 2*np.pi, 100)x radius * np.cos(theta) center[0]y radius * np.sin(theta) center[1]y1 np.zeros(100)for i in range(100):y1[i] y[i] perlin1D(theta[i]*5)/255*2# 画出圆形ax.plot(x, y,colororange)ax.plot(x, y1,colordeepskyblue)# 设置坐标轴范围ax.set_xlim([-15, 15])ax.set_ylim([-15, 15])# 显示图像plt.show()二维柏林噪声
头文件
#pragma once
#includearray
class PerlinNoise2D
{
public:PerlinNoise2D();~PerlinNoise2D();float BasePerlinNoise2D(float x , float y); //输出数值的范围应该是[-1,1]float Octave2D_01(float x, float y, int octaves, float persistence 0.5);//输出数值的范围限定在[0,1]
private:templatetypename STLIteratorinline void shuffle(STLIterator begin, STLIterator end);/*生成最大值为max的随机数*/int random(int max);/*input: 方向向量(x,y) 哈希值 hash根据哈希值可以达到随机梯度输出随机梯度与方向向量的乘积*/inline float Grad(int hash, float x, float y);inline float Grad2(int hash, float x, float y);inline float Fade(const float t);inline float Lerp(const float a, const float b, const float t);inline float RemapClamp_01(float x);float Octave2D(float x, float y, int octaves, float persistence 0.5);
private:std::arrayint, 256 m_permutation;};
cpp
#include PerlinNoise2D.h
#include random
#include numeric
PerlinNoise2D::PerlinNoise2D()
{std::iota(m_permutation.begin(), m_permutation.end(), 0);shuffle(m_permutation.begin(), m_permutation.end());
}PerlinNoise2D::~PerlinNoise2D()
{}int PerlinNoise2D::random(int max)
{return (std::random_device{}() % (max)1);
}/*
洗牌算法
*/
templatetypename STLIterator
inline void PerlinNoise2D::shuffle(STLIterator begin, STLIterator end)
{if (begin end){return;}using difference_type typename std::iterator_traitsSTLIterator::difference_type;for (STLIterator it begin 1; it end; it){int n random(static_castint(it - begin));std::iter_swap(it, begin static_castdifference_type(n));}}inline float PerlinNoise2D::Grad(int hash, float x, float y)
{float z 0.34567;switch (hash 0xF){case 0x0: return x y;case 0x1: return -x y;case 0x2: return x - y;case 0x3: return -x - y;case 0x4: return x z;case 0x5: return -x z;case 0x6: return x - z;case 0x7: return -x - z;case 0x8: return y z;case 0x9: return -y z;case 0xA: return y - z;case 0xB: return -y - z;case 0xC: return y x;case 0xD: return -y z;case 0xE: return y - x;case 0xF: return -y - z;default: return 0; // never happens}
}inline float PerlinNoise2D::Grad2(int hash, float x, float y)
{const double PI 3.14159265359;const int numPoints 36;hash hash % numPoints;double angle 2 * PI * hash / numPoints;double gradx cos(angle);double grady sin(angle);return gradx * x grady*y;
}inline float PerlinNoise2D::Fade(const float t)
{return t * t * t * (t * (t * 6 - 15) 10);
}inline float PerlinNoise2D::Lerp(const float a, const float b, const float t)
{return (a (b - a) * t);
}
float PerlinNoise2D::BasePerlinNoise2D(float x, float y)
{//得到周围四个点int _x std::floor(x);int _y std::floor(y);int ix _x 255;int iy _y 255;//hash函数得到随机索引值int AA m_permutation[(m_permutation[ix 255] iy) 255];int BA m_permutation[(m_permutation[(ix 1) 255] iy) 255];int AB m_permutation[(m_permutation[ix 255] iy1) 255];int BB m_permutation[(m_permutation[ix1 255] iy1) 255];//根据索引值 得到方向向量和随机梯度的向量积float fx x - _x;float fy y - _y;float g1 Grad2(AA,fx,fy);float g2 Grad2(BA, fx - 1, fy);float g3 Grad2(AB, fx, fy - 1);float g4 Grad2(BB, fx - 1, fy - 1);//插值float u Fade(fx);float v Fade(fy);float x1 Lerp(g1, g2, u);float x2 Lerp(g3, g4, u);return Lerp(x1, x2, v);
}float PerlinNoise2D::Octave2D(float x, float y, int octaves, float persistence)
{float result 0.0;float amplitude 1.0;for (int i 0; i octaves; i){result (BasePerlinNoise2D(x, y) * amplitude);x * 2;y * 2;amplitude * persistence;}return result;
}inline float PerlinNoise2D::RemapClamp_01(float x)
{if (x -1.0) {return 0.0;}else if (1.0 x){return 1.0;}return (x * 0.5 0.5);
}float PerlinNoise2D::Octave2D_01(float x, float y, int octaves, float persistence )
{return RemapClamp_01(Octave2D(x,y, octaves));
}测试
class PerlinNoiseTest
{
public:PerlinNoiseTest() {};~PerlinNoiseTest() {};void drawImage(float frequency4.0, int octaves2,int width 400, int height 400);
};#include PerlinNoiseTest.h
#include PerlinNoise2D.h
#include opencv2/opencv.hpp
# include algorithm
#include iostream
using namespace cv;
void PerlinNoiseTest::drawImage(float frequency, int octaves, int width , int height )
{// 创建一个空白图像cv::Mat image(height, width, CV_8UC3, cv::Scalar(255, 255, 255));frequency std::clamp((double)frequency, 0.1, 64.0);const double fx (frequency / width);const double fy (frequency / height);int maxcolor 0;PerlinNoise2D perlin;for (std::int32_t y 0; y height; y){for (std::int32_t x 0; x width; x){int color 255*perlin.Octave2D_01((x * fx), (y * fy), octaves);maxcolor max(maxcolor , color);image.atcv::Vec3b(y, x) cv::Vec3b(color, color, color); // 绘制像素点}}std::cout maxcolor: maxcolor;imshow(Generated Texture, image);imwrite(D:\\code\\noise\\image\\PerlinNoiseTest.jpg, image);waitKey(0);
}int main() {PerlinNoiseTest perlinTest;perlinTest.drawImage(20,1,400,400);}参考文献
Using Perlin Noise to Generate 2D Terrain and Water FastNoiseSIMD github libnoise 柏林噪声 一篇文章搞懂柏林噪声算法附代码讲解
游戏开发技术杂谈2理解插值函数lerp
[Nature of Code] 柏林噪声 https://adrianb.io/2014/08/09/perlinnoise.html