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

news2024/9/22 9:52:44

任务

        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 for
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // TODO: Joint bilateral filter
            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 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);
                    //first
                    float distance2 = SqrDistance(position,center_positon);
                    float P = distance2 / ( 2 * m_sigmaCoord * m_sigmaCoord);
                    //second
                    auto color2 = SqrDistance(color,center_color);
                    float C = color2 / (2 * m_sigmaColor * m_sigmaColor);
                    //third

                    auto 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);

                    //forth
                    float D = 0.0;
                    //not self to makesure not/0
                    if(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);
                    }


                    //final
                    float 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 for
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // TODO: Reproject
            auto 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 for
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // TODO: Temporal clamp
            Float3 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 average

            m_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 for
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // TODO: Joint bilateral filter
            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 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);
                        //first
                       float distance2 = SqrDistance(position,center_positon);
                       float P = distance2 / ( 2 * m_sigmaCoord * m_sigmaCoord);
                        //second
                       auto color2 = SqrDistance(color,center_color);
                       float C = color2 / (2 * m_sigmaColor * m_sigmaColor);
                       //third

                       auto N = SafeAcos(Dot(center_normal,normal));
                       N *=N;
                       N / (2.0 * m_sigmaNormal * m_sigmaNormal);  //youwenti

                        //forth
                       float D = 0.0;
                      //not self to makesure not/0
                        if(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);
                         }


                        //final
                        float 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;
}

结果

        原始输入数据

        

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

        原始输入数据

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科研小白教程|如何远程连接实验室服务器跑代码?

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a; 【计算机系统架构】从0开始构建一台现代计算机|时序逻辑、主存储器|第3章每日一言&#x1f33c;: 总之岁月漫长&#xff0c;然而值得等待。—…

国内可以免费使用的gpt网站【九月持续更新】

GPT Hub 是我最近使用的一款智能文本生成工具平台&#xff0c;它支持多种AI模型&#xff0c;包括最新的GPT-4模型&#xff0c;并且可以在国内网络环境中直接访问。以下是我在使用过程中发现的一些特点&#xff1a; 多功能支持&#xff1a;不仅支持代码生成&#xff0c;还涵盖了…

【主机入侵检测】Wazuh解码器之JSON解码器

前言 Wazuh 是一个开源的安全平台&#xff0c;它使用解码器&#xff08;decoders&#xff09;来从接收到的日志消息中提取信息。解码器将日志信息分割成字段&#xff0c;以便进行分析。Wazuh 解码器使用 XML 语法&#xff0c;允许用户指定日志数据应该如何被解析和规范化。解码…

Java基础(10)- 学生管理系统项目

一、JavaBean编写 public class Student {private int id;private String name;private int age;private String sex;public Student() {}public Student(int id, String name, int age, String sex) {this.id id;this.name name;this.age age;this.sex sex;}public int g…

绝对定位导致内容自动换行问题解决

今天在做一个定位元素的时候遇到一个嵌套定位之后&#xff0c;使用绝对定位的元素的内容自动换行的问题&#xff0c;希望不换行只在一行显示。 可以通过添加 white-space: nowrap; 样式控制不换行 <div class"box"><div class"box1"><div …

深入剖析:中国国际大学生创新大赛中不可忽视的12个扣分点

深入剖析&#xff1a;中国国际大学生创新大赛中不可忽视的12个扣分点 前言1. 项目名称&#xff1a;第一印象的力量2. 项目逻辑&#xff1a;清晰的思路是关键3. 问题分析&#xff1a;深入挖掘痛点4. 需求分析&#xff1a;解决方案的导向5. 科研课题与评审维度的匹配6. 团队介绍&…

DataWhale AI夏令营-《李宏毅深度学习教程》笔记-task3

DataWhale AI夏令营-《李宏毅深度学习教程》笔记-task2 第五章 循环神经网络5.1 独热编码5.2 RNN架构5.3 其他RNN5.3.1 Elman 网络 &Jordan 网络5.3.2 双向循环神经网络 第五章 循环神经网络 循环神经网络RNN&#xff0c;RNN在处理序列数据和时间依赖性强的问题上具有独特…

渗透测试靶机--- DC系列 DC-6

渗透测试靶机— DC系列 DC-6 开启靶机&#xff0c;登录页面&#xff0c;平平无奇 扫描ip&#xff0c;端口&#xff0c;服务等信息 访问80&#xff0c;发现这里是WordPress站点 直接wpscan扫描一下用户名wpscan --url http://wordy -e u 这里可以将扫出来的五个用户名保存&…

WPF性能优化之UI虚拟化

文章目录 前言一、VirtualizingStackPanel1.1 虚拟化功能介绍1、在Window中添加一个ListBox控件。2、在设计视图中用鼠标选中ListBox控件并右健依次单击“编辑其他模板”&#xff0d;“编辑项的布局模板”&#xff0d;“编辑副本”。3、查看生成的模板代码。 1.2 虚拟化参数介绍…

如何提升网站权重?

提升网站权重的方法有很多&#xff0c;常规的方法包括内容优化、关键词研究、页面结构调整、提高用户体验等。但这些方法往往需要时间来见效。如果你希望在短时间内看到显著的提升&#xff0c;发外链是一个非常有效的策略。 外链是提升网站权重的有效方法&#xff0c;但需要注…

9月3c++

封装栈和队列 队列 #include <iostream> #include <cstring> using namespace std; class Myqueue { private:int data[256];int size0; public:Myqueue(){}//无参构造~Myqueue(){}//析构//拷贝赋值Myqueue & operator(const Myqueue &other){if(this!&a…

C++ ─── List的模拟实现

一&#xff0c; List的模拟实现 List 是一个双向循环链表,由于List的节点不连续&#xff0c;不能用节点指针直接作为迭代器&#xff0c;因此我们要对结点指针封装&#xff0c;来实现迭代器的作用。 迭代器有两种实现方式&#xff0c;具体应根据容器底层数据结构实现&#xff1…

15、VSCode自定义Markwown编辑环境

前言 &#xff1a;Visual Studio Code (VSCode) 是微软推出的一款开源编辑器&#xff0c;使用 Electron 打造&#xff0c;与 Atom 齐名&#xff0c;不过随着 Atom 社区的渐渐缩小&#xff0c;VSCode 的影响力开始越来越大了。VSCode 内置了 Markdown 语言及预览的支持&#xff…

每周12600元奖金池,邀你与昇腾算力共舞,openMind开发者盛宴启幕!

小伙伴们&#xff0c;是否瞬间被这个标题唤醒了在OpenI启智社区“我为开源打榜狂”黄金时代的温馨记忆&#xff1f;打榜活动虽已谢幕&#xff0c;但大家相伴度过12期的那份激情与创新的共鸣&#xff0c;促使OpenI启智社区在国产算力崛起的浪潮中勇立潮头&#xff0c;推出了“芯…

JavaScript是什么

前言 初始JavaScript JavaScript是什么 JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行, 现在也可以基于 node.js 在服务器端运行. JavaScript 最初只是为了完成简单的表单验证(验证数据合法性), 结果后…

git 回滚的三种方式

按照从旧到新的顺序 你依次提交了 1 2 3 4 5 现在你想回到1 如何操作 第一种方法 hard reset git reset --hard 执行命令后 你会发现 效果实现了 东西都回到了那次更改 但是2345的更改都没了 并且你会发现 你有更新 这是因为这个hard reset 只会改本地的 远程的不改 一更新就…

7.Lab Six —— Cow Fork

首先切换分支到cow git checkout cow make clean Implement copy-on write 实现写时复制&#xff0c;为了测试方案&#xff0c;以及提供了一个cowtest的xv6程序&#xff0c;位于user/cowtest.c当中 课程给了一个合理的攻克计划&#xff1a; 修改uvmcopy()将父进程的物理页映…

GO 下载依赖改成国内代理

改成我们国内可用的代理地址 在命令提示符输入&#xff1a; 1 go env -w GOPROXYhttps://goproxy.cn 然后再做各种操作就可以成功了 另外一个问题&#xff1a; 手动下载某些依赖包&#xff0c;但是goland一直无法识别。 删掉了GOPATH多余的路径。 另外&#xff0c;启用了…

STL—vector容器

目录 1、简单使用&#xff08;插入数据三种遍历方式&#xff09; 2、介绍 3、常用构造方法 3、扩容reserve和缩容shrink_to_fit 4、insert函数&#xff1a;在某个位置进行插入数据 5、vector使用库里面的find 6、vector< vector > 7、看源代码的技巧 1、简单使用&…

大二必做项目贪吃蛇超详解之下篇游戏核心逻辑实现

贪吃蛇系列文章 上篇win32库介绍中篇设计与分析下篇游戏主逻辑 可以在Gitee上获取贪吃蛇代码。 文章目录 贪吃蛇系列文章5. 核心逻辑实现分析5. 3 GameRun5. 3. 1 PrintScore5. 3. 2 CheckVK5. 3. 3 BuyNewNode5. 3. 4 NextIsFood5. 3. 4 EatFood5. 3. 5 NotFood5. 3. 6 Chec…