柏林噪声C++

柏林噪声

随机噪声
在这里插入图片描述
如上图所示随机噪声没有任何规律可言,我们希望生成有一些意义的局部连续的随机图案

一维柏林噪声

在这里插入图片描述

假设希望生成一段局部连续的随机曲线,可以采用插值的方式:在固定点随机分配y值(一般是整数点),其他的点使用插值算法

方法一:线性插值的方式

公式如下:
在这里插入图片描述
【数字图像处理】二维(2D)线性插值的应用
y = a*y1 + (1-a)*y2

我们画图看看:
在这里插入图片描述

import math
import numpy as np
import matplotlib.pyplot as plt

perm = [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.0
    grad2 = perm[x2 % 255] * 2.0 - 255.0
    #x1和x2指向x的方向向量
    vec1 = x - x1
    vec2 = x - x2

    # x到x1的距离即vec1,利用公式3计算平滑参数
    t = 3 * pow(vec1, 2) - 2 * pow(vec1, 3)

    #梯度值与方向向量的乘积
    product1 = grad1 * vec1
    product2 = grad2 * vec2


    return product1 + t * (product2 - product1)

def linear1D(x):
    # 整数x1和x2的坐标
    x1 = math.floor(x)
    x2 = x1 + 1

    # y值 随机数
    grad1 = perm[x1 % 255] * 2.0 - 255.0
    grad2 = perm[x2 % 255] * 2.0 - 255.0

    t=x - x1

    return 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.0
    grad2 = perm[x2 % 255] * 2.0 - 255.0
    #x1和x2指向x的方向向量
    vec1 = x - x1
    vec2 = x - x2

    t=x - x1
    #梯度值与方向向量的乘积
    product1 = grad1 * vec1
    product2 = grad2 * vec2


    return 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,color='red')
    
    # 绘制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,color='deepskyblue')
    plt.plot(x, y1,color='green')
    plt.plot(x, y2,color='orange')
    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 ) y=ty2+(1t)y1=y1+t(y2y1)
t = x − x 1 t=x-x1 t=xx1

线性插值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 ) y=ty2w2+(1t)y1w1=y1w1+t(y2w2y1w1)
w是权重系数,也是柏林算法中的方向向量vec1 = x - x1
如图中黄色的线

柏林噪声

柏林噪声在此基础上再加强一步:
t = 3 t 2 − 2 t 3 t=3t^2 -2t^3 t=3t22t3

算法步骤:
input: x

  1. 计算周围的点:x1 , x2
  2. 计算x1 , x2 梯度 : grad1, grad2 随机取[0,255]
  3. 方向向量: (vec1 =x-x1 ;vec2 = x-x2)
  4. 梯度值与方向向量的乘积 product=grad*vec
  5. 计算系数 t=3t^2 -2t^3
  6. 插值: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,color='orange')
    ax.plot(x, y1,color='deepskyblue')
    # 设置坐标轴范围
    ax.set_xlim([-15, 15])
    ax.set_ylim([-15, 15])

    # 显示图像
    plt.show()

在这里插入图片描述

二维柏林噪声

头文件

#pragma once
#include<array>
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:
	template<typename STLIterator>
	inline 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::array<int, 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);
}

/*
洗牌算法
*/
template<typename STLIterator>
inline void PerlinNoise2D::shuffle(STLIterator begin, STLIterator end)
{
	if (begin == end)
	{
		return;
	}
	using difference_type = typename std::iterator_traits<STLIterator>::difference_type;
	for (STLIterator it = begin + 1; it < end; ++it)
	{
		int n = random(static_cast<int>(it - begin));
		std::iter_swap(it, begin + static_cast<difference_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] + iy+1) & 255];
	int BB = m_permutation[(m_permutation[ix+1 & 255] + iy+1) & 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 frequency=4.0, int octaves=2,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.at<cv::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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/228301.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode力扣每日一题(Java):20、有效的括号

一、题目 二、解题思路 1、我的思路 我看到题目之后&#xff0c;想着这可能是力扣里唯一一道我能秒杀的题目了 于是一波操作猛如虎写出了如下代码 public boolean isValid(String s) {char[] c s.toCharArray();for(int i0;i<c.length;i){switch (c[i]){case (:if(c[i]…

Kotlin(十五) 高阶函数详解

高阶函数的定义 高阶函数和Lambda的关系是密不可分的。在之前的文章中&#xff0c;我们熟悉了Lambda编程的基础知识&#xff0c;并且掌握了一些与集合相关的函数式API的用法&#xff0c;如map、filter函数等。另外&#xff0c;我们也了解了Kotlin的标准函数&#xff0c;如run、…

Mybatis XML改查操作(结合上文)

"改"操作 先在UserInfoXMLMapper.xml 中 : <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><map…

2023金旗奖榜单隆重揭晓

2023年12月1日&#xff0c;2023品牌管理者年会暨第14届金旗奖品牌大赏圆满结束&#xff0c;为期两天的年会干货满满&#xff0c;四大专场八大主题演讲、两场圆桌论坛&#xff0c;汇集各领域大咖&#xff0c;巅峰交流品牌韧性增长之道&#xff0c;吸引来自海外内500多家企业品牌…

剪切板管理 Paste中文 for Mac

Paste是一个方便的剪贴板管理工具&#xff0c;它可以帮助你更好地组织、查找和管理剪贴板中的内容。它提供了历史记录、搜索、组织、格式处理和云同步等功能&#xff0c;使你能够更高效地使用剪贴板&#xff0c;并节省时间和精力。无论是在个人使用还是团队协作中&#xff0c;P…

学习git后,真正在项目中如何使用?

文章目录 前言下载和安装Git克隆远程仓库PyCharm链接本地Git创建分支修改项目工程并提交到本地仓库推送到远程仓库小结 前言 网上学习git的教程&#xff0c;甚至还有很多可视化很好的git教程&#xff0c;入门git也不是什么难事。但我发现&#xff0c;当我真的要从网上克隆一个…

图像的均方差和信噪比计算

图像的均方差和信噪比计算 一、均方差1、公式2、代码 二、信噪比1、公式2、代码 图像的均方差和信噪比公式及代码&#xff0c;代码基于opencv和C实现。 一、均方差 均方误差&#xff0c;英文简称&#xff1a;MSE&#xff0c;英文全称&#xff1a;“Mean Square Error”。 衡量…

相控阵天线(十五):进阶稀疏阵列天线(边缘稀疏阵列、稀疏子阵天线、旋转稀疏子阵天线)

目录 简介圆形边缘稀疏阵列矩形边缘稀疏阵列稀疏子阵天线旋转稀疏子阵天线 简介 前面的博客已经介绍过常见的平面阵有一些基本类型&#xff0c;本篇博客介绍一些实际工程中可能出现的阵列&#xff0c;包括椭圆阵列、子阵通过矩形拼接形成的矩形大阵列和圆形大阵列、子阵通过三…

CG-70A 双轴高精度倾角传感器准确测量水平角度的变化状况

产品概述 一款双轴高精度数字型&#xff08;RS485&#xff09;倾角传感器&#xff0c;其产品分辨率为0.0001&#xff0c;采用铝合金外壳&#xff0c;防护等级为IP67&#xff0c;可用来系统与准确地测量水平角度的变化状况。 功能特点 ★ 抗外界电磁干扰能力强、能承受大冲击…

Leetcode—198.打家劫舍【中等】

2023每日刷题&#xff08;五十二&#xff09; Leetcode—198.打家劫舍 算法思想 具体思路 首先&#xff0c;我们从上面的题目描述中抽象出题意。 ● 从一个非负整数数组中找到一个子序列&#xff0c;并且该子序列的和最大 ● 子序列中每个数的位置不能够相邻。举例来讲&…

智能优化算法应用:基于金枪鱼群算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于金枪鱼群算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于金枪鱼群算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.金枪鱼群算法4.实验参数设定5.算法结果6.参考…

Rust的eBFP框架Aya(一) - Linux内核网络基础

前言 在我的Rust入门及实战系列文章中已经说明&#xff0c; Rust是一门内存安全的高性能编程语言&#xff0c;从它的这些优秀特性来看&#xff0c;就是一门专为系统开发而诞生的语言。至于很多使用Rust来进行web开发的行为&#xff0c;不能说它们不好&#xff0c;只能说是杀鸡…

企业集团采购系统(供应商、询价、招投标)-源码

一、业务需求 企业招标询价供应商管理系统是一种专业的采购管理系统&#xff0c;旨在帮助企业实现供应商关系的管理和采购成本的控制。该系统涵盖了企业采购管理的各个方面&#xff0c;包括采购预算、供应商管理、产品管理、采购计划、询价、竞价、招标、采购订单、采购合同执…

python数据分析总结(pyecharts)

目录 安装依赖 Demo pyecharts.options 图表绘制 WordCloud.shape 安装依赖 pip install pyecharts Demo ### 对象式 from pyecharts.charts import Bar bar Bar() bar.add_xaxis([1,2,3,4,5]) bar.add_yaxis("数据1",[40,56,65,23,56]) bar.add_yaxis("数…

远程服务器QEMU+Ubuntu+GRUB+VNC最佳实践

远程服务器QEMUUbuntuGRUBVNC最佳实践 1. 准备2. QEMU启动安装Ubuntu2.1 服务器端2.2 本地端 3. 从服务器终端控制虚拟机GRUB与虚拟机终端 这段时间参与大量内核切换测试工作&#xff0c;实体机需要硬件自检太过笨重&#xff0c;因此主要通过QEMU验证正确性。有一个很大的问题是…

docker的资源控制

对容器使用宿主机的资源进行限制。例如&#xff1a;cpu、内容、磁盘I/O docker使用Linux自带的功能Cgroup功能进行控制 Cgroup是什么&#xff1f; Cgroup&#xff1a;Control grouos是Linux内核系统提供的一种可以限制、记录、隔离进程组所使用的物理资源机制。 docker借助…

Intel® Enclave Access Control and Data Structures(二)

文章目录 前言一、Overview of Enclave Execution Environment二、Terminology三、Access-control Requirements四、Segment-based Access Control五、Page-based Access Control5.1 Access-control for Accesses that Originate from non-SGX Instructions5.2 Memory Accesses…

原码,补码,反码(极简版)

原码补码反码 都有符号位&#xff0c;0表示正数&#xff0c;1表示负数 正数 正数的原码&#xff0c;补码&#xff0c;反码都相同 负数 负数的原码&#xff0c;最高位是1&#xff0c;其余的用正常二进制表示 负数的反码&#xff0c;对原码进行符号位不变&#xff0c;其余位…

网站高性能架构设计——web前端与池化

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、高性能浏览器访问 1.减少HTTP请求 HTTP协议是无状态的应用层协议&#xff0c;也就是说每次HTTP请求都需要建立通信链路、进行数据传输&#xf…

vue-baidu-map实现在地图上选择范围并解决相关问题

vue-baidu-map实现在地图上选择范围并解决相关问题 实现地图上选择不规则范围实现功能遇到的问题1、覆盖物多边形怎么才能盖住覆盖物点2、遇到其他问题 实现地图上选择不规则范围 这个功能比较简单&#xff0c;只需要使用vue-baidu-map插件的覆盖物多边形功能就行了。直接看文…
最新文章