柏林噪聲C++

柏林噪聲

隨機噪聲
在這里插入圖片描述
如上圖所示隨機噪聲沒有任何規律可言,我們希望生成有一些意義的局部連續的隨機圖案

一維柏林噪聲

在這里插入圖片描述

假設希望生成一段局部連續的隨機曲線,可以采用插值的方式:在固定點隨機分配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.0t=x - 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 - x2t=x - 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,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=t?y2+(1?t)?y1=y1+t(y2?y1)
t = x ? x 1 t=x-x1 t=x?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 ) y=t?y2?w2+(1?t)?y1?w1=y1?w1+t(y2?w2?y1?w1)
w是權重系數,也是柏林算法中的方向向量vec1 = x - x1
如圖中黃色的線

柏林噪聲

柏林噪聲在此基礎上再加強一步:
t = 3 t 2 ? 2 t 3 t=3t^2 -2t^3 t=3t2?2t3

算法步驟:
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.pswp.cn/news/206880.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/206880.shtml
英文地址,請注明出處:http://en.pswp.cn/news/206880.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【數據分析實戰】酒店行業華住集團門店分布與評分多維度分析

文章目錄 1. 寫在前面2. 數據集展示3. 多維度分析3.1 門店檔次多元化&#xff1a;集團投資戰略觀察3.1.1 代碼實現3.1.2 本人淺薄理解 3.2 門店分布&#xff1a;各省市分布概覽3.2.1 代碼實現3.2.2 本人淺薄理解 3.3 門店分級評分&#xff1a;服務水平的多維度觀察3.3.1 代碼實…

F5怎么樣?從負載均衡到云原生的進階之路

從Web時代開始至云原生時代的應用服務交付的市場&#xff0c;技術與人的變化就是關注的焦點。從單純的Web負載均衡到復雜的企業應用交付&#xff0c;從單體應用到分布式、微服務架構&#xff0c;F5為企業技術架構更好、更優、更安全的運行做出了極大的努力。那么F5怎么樣&#…

Vue 循環走馬燈

1、使用 transform: translateX()&#xff0c;循環將滾動內容在容器內偏移&#xff0c;超出容器部分隱藏&#xff1b; 2、避免滾動到末尾時出現空白&#xff0c;需要預留多幾個。 3、一次循環偏移的距離scrollLoopWidth 可能受樣式影響需要做些微調&#xff0c;比如單個item的…

題目:分糖果(藍橋OJ 2928)

題目描述&#xff1a; 解題思路&#xff1a; 本題采用貪心思想 圖解 題解&#xff1a; #include<bits/stdc.h> using namespace std;const int N 1e6 9; char s[N];//寫字符串數組的一種方法,像數組一樣***int main() {int n, x;cin >> n >> x;for(int …

CSS新手入門筆記整理:元素類型相互轉換

元素類型 塊元素&#xff08;block&#xff09; 獨占一行&#xff0c;排斥其他元素跟其位于同一行&#xff0c;包括塊元素和行內元素。塊元素內部可以容納其他塊元素和行內元素。可以定義 width&#xff0c;也可以定義 height。可以定義 4 個方向的 margin。 行內元素&#xf…

使用navicat(或者其他數據庫管理工具)、powerdesigner導出數據字典

適合先有數據庫結構&#xff0c;后需要導出數據字典的情況&#xff0c;多數在發開完成交文檔或者用戶有庫的情況下 有條件的話推薦用powerdesigner導出&#xff0c;比較好看 如果用powerdesigner導出的注釋不對&#xff0c;是因為數據庫的編碼不對 1、使用navicat導出 在該數…

代碼隨想錄算法訓練營第45天| 70. 爬樓梯 (進階) 322. 零錢兌換 279.完全平方數

JAVA代碼編寫 70. 爬樓梯&#xff08;進階版) 卡碼網&#xff1a;57. 爬樓梯&#xff08;第八期模擬筆試&#xff09; 題目描述 假設你正在爬樓梯。需要 n 階你才能到達樓頂。 每次你可以爬至多m (1 < m < n)個臺階。你有多少種不同的方法可以爬到樓頂呢&#xff1f…

菜鳥學習日記(python)——推導式

python中的推導式是一種獨特的數據處理方式&#xff0c;可以從一個數據序列去構建另一個新的數據序列的結構體。 它包括以下推導式&#xff1a; 列表&#xff08;list&#xff09;推導式字典&#xff08;dict&#xff09;推導式集合&#xff08;set&#xff09;推導式元組&am…

Multi-Cell Downlink Beamforming: Direct FP, Closed-Form FP, Weighted MMSE

這里寫自定義目錄標題 Direct FPClosed-Form FPthe Lagrangian functionthe Lagrange dual function: maximizing the Lagrangianthe Lagrange dual problem: minimizing the Lagrange dual functionClosed-Form FP Weighted MMSE原論文 Lagrange dual5.1.1 The Lagrangian5.1.…

阿里云服務器經濟型、通用算力型、計算型、通用型、內存型實例區別及選擇參考

當我們通過阿里云的活動購買云服務器會發現&#xff0c;相同配置的云服務器往往有多個不同的實例可選&#xff0c;而且價格差別也比較大&#xff0c;例如同樣是4核8G的配置的云服務器&#xff0c;經濟型e實例活動價格只要1500.48/1年起&#xff0c;通用算力型u1實例要1795.97/1…

nvidia安裝出現7-zip crc error解決辦法

解決辦法&#xff1a;下載network版本&#xff0c;重新安裝。&#xff08;選擇自己需要的版本&#xff09; 網址&#xff1a;CUDA Toolkit 12.3 Update 1 Downloads | NVIDIA Developer 分析原因&#xff1a;local版本的安裝包可能在下載過程中出現損壞。 本人嘗試過全網說的…

linux 系統安全基線 安全加固操作

目錄 用戶口令設置 root用戶遠程登錄限制 檢查是否存在除root之外UID為0的用戶 ???????root用戶環境變量的安全性 ???????遠程連接的安全性配置 ???????用戶的umask安全配置 ???????重要目錄和文件的權限設置 ???????找未授權的SUID…

json轉yolo格式

json轉yolo格式 視覺分割得一些標注文件是json格式&#xff0c;比如&#xff0c;舌頭將這個舌頭區域分割出來&#xff08;用mask二值圖的形式&#xff09;&#xff0c;對舌頭的分割第一步是需要檢測出來&#xff0c;缺少數據集&#xff0c;可以使用分割出來的結果&#xff0c;將…

無公網IP環境如何SSH遠程連接Deepin操作系統

文章目錄 前言1. 開啟SSH服務2. Deppin安裝Cpolar3. 配置ssh公網地址4. 公網遠程SSH連接5. 固定連接SSH公網地址6. SSH固定地址連接測試 前言 Deepin操作系統是一個基于Debian的Linux操作系統&#xff0c;專注于使用者對日常辦公、學習、生活和娛樂的操作體驗的極致&#xff0…

數據儀表盤設計:可視化數據指標和報告

寫在開頭 在信息爆炸的時代,數據不再是簡單的數字和圖表,而是一種有機的信息體系。如何將這些琳瑯滿目的數據以一種直觀而高效的方式展示,成為企業決策者和分析師們共同關注的問題。本文將帶您深入學習如何設計和創建數據儀表盤,使數據指標和報告以一目了然的方式呈現。 …

Python---time庫

目錄 時間獲取 時間格式化 程序計時 time庫包含三類函數&#xff1a; 時間獲取&#xff1a;time() ctime() gmtime() 時間格式化&#xff1a;strtime() strptime() 程序計時&#xff1a;sleep() perf_counter() 下面逐一介紹&#…

H3.3K27M彌漫性中線膠質瘤的反義寡核苷酸治療

今天給同學們分享一篇實驗文章“Antisense oligonucleotide therapy for H3.3K27M diffuse midline glioma”&#xff0c;這篇文章發表在Sci Transl Med期刊上&#xff0c;影響因子為17.1。 結果解讀&#xff1a; CRISPR-Cas9消耗H3.3K27M恢復了H3K27三甲基化&#xff0c;并延…

Echarts地圖案例及常見問題

前言 ECharts 是一個使用 JavaScript 實現的開源可視化庫,它可以幫助用戶以簡單的方式創建復雜的時間序列、條形圖、餅圖、地圖等圖形。 Echarts繪制地圖的案例 展示了中國各省份的人口數量 var myChart = echarts.init(document.getElementById(main)); var option = {t…

【TailwindCSS】

TailwindCSS作為一種現代化的CSS框架&#xff0c;以其高度的定制性和靈活性受到前端開發者的青睞。本文旨在提供一份詳細的TailwindCSS使用教程&#xff0c;特別適用于Vite和Vue框架的組合。 我們將從安裝開始&#xff0c;深入探討如何在項目中有效利用TailwindCSS的各項功能&…

在AWS Lambda上部署標準FFmpeg工具——Docker方案

大綱 1 確定Lambda運行時環境1.1 Lambda系統、鏡像、內核版本1.2 運行時1.2.1 Python1.2.2 Java 2 啟動EC23 編寫調用FFmpeg的代碼4 生成docker鏡像4.1 安裝和啟動Docker服務4.2 編寫Dockerfile腳本4.3 生成鏡像 5 推送鏡像5.1 創建存儲庫5.2 給EC2賦予角色5.2.1 創建策略5.2.2…