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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

使用Python实现实时金价监控并自动提醒功能

《使用Python实现实时金价监控并自动提醒功能》在日常投资中,很多朋友喜欢在一些平台买点黄金,低买高卖赚点小差价,但黄金价格实时波动频繁,总是盯着手机太累了,于是我用Python写了一个实时金价监控... 目录工具能干啥?手把手教你用1、先装好这些"食材"2、代码实现讲解1. 用户输入参数2. 设置无头浏

Gradle在国内配置镜像加速的实现步骤

《Gradle在国内配置镜像加速的实现步骤》在国内使用Gradle构建项目时,最大的痛点就是依赖下载贼慢,甚至卡死,下面教你如何配置国内镜像加速Gradle下载依赖,主要是通过改写repositori... 目录引言一、修改 build.gradle 或 settings.gradle 的 reposito

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何