GAMES202——作业5 实时光线追踪降噪(联合双边滤波、多帧的投影与积累、À-Trous Wavelet 加速单帧降噪)

本文主要是介绍GAMES202——作业5 实时光线追踪降噪(联合双边滤波、多帧的投影与积累、À-Trous Wavelet 加速单帧降噪),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

任务

        1.实现单帧降噪

        2.实现多帧投影

        3.实现多帧累积

        Bonus:使用À-Trous Wavelet 加速单帧降噪

实现

        单帧降噪

        这里实现比较简单,直接根据给出的联合双边滤波核的公式就能实现

        

Buffer2D<Float3> Denoiser::Filter(const FrameInfo &frameInfo) {int height = frameInfo.m_beauty.m_height;int width = frameInfo.m_beauty.m_width;Buffer2D<Float3> filteredImage = CreateBuffer2D<Float3>(width, height);int kernelRadius = 16;
#pragma omp parallel forfor (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// TODO: Joint bilateral filterint x_min = std::max(0,x-kernelRadius);int x_max = std::min(width-1,x+kernelRadius);int y_min = std::max(0,y-kernelRadius);int y_max = std::min(height-1,y+kernelRadius);auto center_color = frameInfo.m_beauty(x,y);auto center_normal = frameInfo.m_normal(x,y);auto center_positon = frameInfo.m_position(x,y);Float3 finalColor;float weight = 0.0f;for(int i = x_min ; i<=x_max ; i++){for(int j = y_min ; j<=y_max ; j++){auto position = frameInfo.m_position(i,j);auto normal = frameInfo.m_normal(i,j);auto color = frameInfo.m_beauty(i,j);//firstfloat distance2 = SqrDistance(position,center_positon);float P = distance2 / ( 2 * m_sigmaCoord * m_sigmaCoord);//secondauto color2 = SqrDistance(color,center_color);float C = color2 / (2 * m_sigmaColor * m_sigmaColor);//thirdauto N = SafeAcos(Dot(center_normal,normal));N *=N;N / (2.0 * m_sigmaNormal * m_sigmaNormal);  //youwenti//  std::cout << N << std::endl;// auto normal2 = SafeAcos(Dot(center_normal,normal));// normal2 *= normal2;// auto N = normal2 / ( 2 * m_sigmaNormal * m_sigmaNormal);//forthfloat D = 0.0;//not self to makesure not/0if(P > 0.0f){auto direction = Normalize( position - center_positon );float plane = Dot(direction , center_normal);float plane2 = plane * plane;D = plane2 / ( 2 * m_sigmaPlane * m_sigmaPlane);}//finalfloat temp = std::exp(-P-C-N-D);finalColor += color * temp;weight += temp;}}filteredImage(x,y) = finalColor / weight;// filteredImage(x, y) = Float3(0.0);}}return filteredImage;
}

        帧的投影

        

        根据上面的式子,能够求出世界坐标系在上一帧的屏幕坐标的位置。求出位置后,需要先判断这个位置是否超出了屏幕坐标。如果在屏幕内,判断是否为同一个物体,如果不是就不能采用上一帧的信息,否则会造成拖影现象。

        

void Denoiser::Reprojection(const FrameInfo &frameInfo) {int height = m_accColor.m_height;int width = m_accColor.m_width;Matrix4x4 preWorldToScreen =m_preFrameInfo.m_matrix[m_preFrameInfo.m_matrix.size() - 1];Matrix4x4 preWorldToCamera =m_preFrameInfo.m_matrix[m_preFrameInfo.m_matrix.size() - 2];
#pragma omp parallel forfor (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// TODO: Reprojectauto id = frameInfo.m_id(x,y);auto world_pos = frameInfo.m_position(x,y);m_valid(x, y) = false;m_misc(x, y) = Float3(0.f);// std::cout << id  << std::endl;if(id == -1)continue;auto world_to_local = Inverse(frameInfo.m_matrix[id]);auto local_to_pre_world = m_preFrameInfo.m_matrix[id];auto local_pos = world_to_local(world_pos,Float3::EType::Point);auto pre_world_pos = local_to_pre_world(local_pos,Float3::EType::Point);auto pre_screen_coord = preWorldToScreen(pre_world_pos,Float3::EType::Point);if(pre_screen_coord.x<0 || pre_screen_coord.x>=width || pre_screen_coord.y<0 || pre_screen_coord.y >=height){continue;}else{auto pre_id = m_preFrameInfo.m_id(int(pre_screen_coord.x),int(pre_screen_coord.y));if(pre_id == id){m_valid(x,y) = true;m_misc(x,y) = m_accColor(int(pre_screen_coord.x),int(pre_screen_coord.y));}}}}std::swap(m_misc, m_accColor);
}

        帧的累积

        

        先判断某个像素是否存在于上一帧里,如果存在,那么就按照α来进行插值沿用上一帧。如果不存在,说明该像素不能以上一帧进行参考,将α设置为1,只用自己这一帧。

        对于Clamp部分,首先需要计算 Ci 在 7×7 的邻域内的均值 µ 和方差 σ, 然后我们将上一帧的颜色限制在 (µ − kσ, µ + ) 范围内。

void Denoiser::TemporalAccumulation(const Buffer2D<Float3> &curFilteredColor) {int height = m_accColor.m_height;int width = m_accColor.m_width;int kernelRadius = 3;
#pragma omp parallel forfor (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// TODO: Temporal clampFloat3 color = m_accColor(x, y);float alpha = 1.0f; if(m_valid(x,y)){alpha = m_alpha;int x_min = std::max(0,x-kernelRadius);int x_max = std::min(width-1,x+kernelRadius);int y_min = std::max(0,y-kernelRadius);int y_max = std::min(height-1,y+kernelRadius);auto mu = Float3(0.0);auto sigma = Float3(0.0);for(int i =x_min;i<=x_max;i++){for(int j=y_min;j<=y_max;j++){mu += curFilteredColor(i,j);sigma += Sqr(curFilteredColor(i,j)-curFilteredColor(x,y));}}int count = kernelRadius * 2 + 1;count *= count;mu = mu / float(count);sigma = SafeSqrt( sigma / float(count));// mu = mu / ( (x_max-x_min) * (y_max - y_min) );// sigma = sigma / ( (x_max-x_min) * (y_max - y_min) );color = Clamp(color,mu - sigma * m_colorBoxK,mu + sigma * m_colorBoxK );}// TODO: Exponential moving averagem_misc(x, y) = Lerp(color, curFilteredColor(x, y), alpha);}}std::swap(m_misc, m_accColor);
}

        À-Trous Wavelet 加速单帧降噪

        课程里给出了一维的解释。由于没有学过信号与系统,这里我的简单理解是离得越远,点的贡献就越小,那么在远的地方就选一个点来代表其附近区域的贡献。

Buffer2D<Float3> Denoiser::AFilter(const FrameInfo &frameInfo) {int height = frameInfo.m_beauty.m_height;int width = frameInfo.m_beauty.m_width;Buffer2D<Float3> filteredImage = CreateBuffer2D<Float3>(width, height);int kernelRadius = 16;
#pragma omp parallel forfor (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// TODO: Joint bilateral filterint x_min = std::max(0,x-kernelRadius);int x_max = std::min(width-1,x+kernelRadius);int y_min = std::max(0,y-kernelRadius);int y_max = std::min(height-1,y+kernelRadius);auto center_color = frameInfo.m_beauty(x,y);auto center_normal = frameInfo.m_normal(x,y);auto center_positon = frameInfo.m_position(x,y);Float3 finalColor;float weight = 0.0f;int passes = 6;for(int pass = 0;pass < passes;pass++){for(int filterX = -3 ; filterX <=3; filterX++){for(int filterY = -3 ; filterY <= 3; filterY++){int m = x + std::pow(2,pass)*filterX;int n = y + std::pow(2,pass)*filterY;auto position = frameInfo.m_position(m,n);auto normal = frameInfo.m_normal(m,n);auto color = frameInfo.m_beauty(m,n);//firstfloat distance2 = SqrDistance(position,center_positon);float P = distance2 / ( 2 * m_sigmaCoord * m_sigmaCoord);//secondauto color2 = SqrDistance(color,center_color);float C = color2 / (2 * m_sigmaColor * m_sigmaColor);//thirdauto N = SafeAcos(Dot(center_normal,normal));N *=N;N / (2.0 * m_sigmaNormal * m_sigmaNormal);  //youwenti//forthfloat D = 0.0;//not self to makesure not/0if(P > 0.0f){auto direction = Normalize( position - center_positon );float plane = Dot(direction , center_normal);float plane2 = plane * plane;D = plane2 / ( 2 * m_sigmaPlane * m_sigmaPlane);}//finalfloat temp = std::exp(-P-C-N-D);finalColor += color * temp;weight += temp;}}}filteredImage(x,y) = finalColor / weight;// filteredImage(x, y) = Float3(0.0);}}return filteredImage;
}

结果

        原始输入数据

        

        采用加速降噪后,并使用帧的投影与累积生成的结果

        原始输入数据

        采用加速降噪后,并使用帧的投影与累积生成的结果

       第二幅图的变化不大,是因为滤波核小

        在示例给出的图中,很明显用了非常大的滤波核。

这篇关于GAMES202——作业5 实时光线追踪降噪(联合双边滤波、多帧的投影与积累、À-Trous Wavelet 加速单帧降噪)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135086

相关文章

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

Open3D 基于法线的双边滤波

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 输入参数: 输出参数: 参数影响: 2.2完整代码 三、实现效果 3.1原始点云 3.2滤波后点云 Open3D点云算法汇总及实战案例汇总的目录地址: Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客 一、概述         基于法线的双边

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

6.4双边滤波

目录 实验原理 示例代码1 运行结果1 实验代码2 运行结果2 实验原理 双边滤波(Bilateral Filtering)是一种非线性滤波技术,用于图像处理中去除噪声,同时保留边缘和细节。这种滤波器结合了空间邻近性和像素值相似性的双重加权,从而能够在去噪(平滑图像)的同时保留图像的边缘细节。双边滤波器能够在的同时,保持边缘清晰,因此非常适合用于去除噪声和保持图像特征。在Op

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

C和指针:结构体(struct)和联合(union)

结构体和联合 结构体 结构体包含一些数据成员,每个成员可能具有不同的类型。 数组的元素长度相同,可以通过下标访问(转换为指针)。但是结构体的成员可能长度不同,所以不能用下标来访问它们。成员有自己的名字,可以通过名字访问成员。 结构声明 在声明结构时,必须列出它包含的所有成员。 struct tag {member-list} variable-list ; 定义一个结构体变量x(包含

PyInstaller问题解决 onnxruntime-gpu 使用GPU和CUDA加速模型推理

前言 在模型推理时,需要使用GPU加速,相关的CUDA和CUDNN安装好后,通过onnxruntime-gpu实现。 直接运行python程序是正常使用GPU的,如果使用PyInstaller将.py文件打包为.exe,发现只能使用CPU推理了。 本文分析这个问题和提供解决方案,供大家参考。 问题分析——找不到ONNX Runtime GPU 动态库 首先直接运行python程序

三.海量数据实时分析-FlinkCDC实现Mysql数据同步到Doris

FlinkCDC 同步Mysql到Doris 参考:https://nightlies.apache.org/flink/flink-cdc-docs-release-3.0/zh/docs/get-started/quickstart/mysql-to-doris/ 1.安装Flink 下载 Flink 1.18.0,下载后把压缩包上传到服务器,使用tar -zxvf flink-xxx-

6.3中值滤波

目录 实验原理 示例代码1 运行结果1 示例代码2 运行结果2 实验原理 中值滤波(Median Filtering)是一种非线性滤波技术,常用于图像处理中去除噪声,特别是在保留边缘的同时减少椒盐噪声(salt-and-pepper noise)。OpenCV中的cv::medianBlur函数可以实现中值滤波。 函数原型 void medianBlur( InputAr

通信工程学习:什么是SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制

SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制        SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制是三种不同的调制方式,它们在通信系统中各有其独特的应用和特点。以下是对这三种调制方式的详细解释: 一、SSB单边带调制 1、SSB单边带调制的定义:        单边带调制(Single Sideband Modulation,SSB)是