games 101 作业4

games 101 作业4

      • 题目
      • 题解
      • 作业答案

题目

Bézier 曲线是一种用于计算机图形学的参数曲线。在本次作业中,你需要实
现 de Casteljau 算法来绘制由 4 个控制点表示的 Bézier 曲线 (当你正确实现该
算法时,你可以支持绘制由更多点来控制的 Bézier 曲线)。
你需要修改的函数在提供的 main.cpp 文件中。
• bezier:该函数实现绘制 Bézier 曲线的功能。它使用一个控制点序列和一个
OpenCV::Mat 对象作为输入,没有返回值。它会使 t 在 0 到 1 的范围内进
行迭代,并在每次迭代中使 t 增加一个微小值。对于每个需要计算的 t,将
调用另一个函数 recursive_bezier,然后该函数将返回在 Bézier 曲线上 t
处的点。最后,将返回的点绘制在 OpenCV ::Mat 对象上。
• recursive_bezier:该函数使用一个控制点序列和一个浮点数 t 作为输入,
实现 de Casteljau 算法来返回 Bézier 曲线上对应点的坐标。
De Casteljau 算法说明如下:

  1. 考虑一个 p0, p1, … pn 为控制点序列的 Bézier 曲线。首先,将相邻的点连接
    起来以形成线段。
  2. 用 t : (1 − t) 的比例细分每个线段,并找到该分割点。
  3. 得到的分割点作为新的控制点序列,新序列的长度会减少一。
  4. 如果序列只包含一个点,则返回该点并终止。否则,使用新的控制点序列并
    转到步骤 1。
    使用 [0,1] 中的多个不同的 t 来执行上述算法,你就能得到相应的 Bézier 曲
    线

提升部分
实现对 Bézier 曲线的反走样。(对于一个曲线上的点,不只把它对应于一个像
素,你需要根据到像素中心的距离来考虑与它相邻的像素的颜色。)

题解

本次作业的难度适中,用递归的方式实现n次贝塞尔曲线。

根据算法说明以及贝塞尔函数的定义,实现如下算法:给定若干个点和t,返回这若干个控制点构成的贝塞尔曲线中t时刻的点。

cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t) 
{
    if (control_points.size() == 1)
        return control_points[0];
    std::vector<cv::Point2f> new_control_points;
    for (int i = 0; i < control_points.size() -1; i++)
    {
        cv::Point2f p = t * control_points[i] + (1 - t) * control_points[i + 1];
        new_control_points.emplace_back(p);
    }
    return recursive_bezier(new_control_points,t);
}

然后t 从0到1,步进值可自定义,本代码中设置为0.001,也就是一条贝塞尔由1001个点组成,每个点的G通道设置为255,也就是线条颜色为绿色。

void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window) 
{
    // TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's 
    // recursive Bezier algorithm.

    int neighborXIndex[8] = { 0,1,0,-1,-1,1,-1,1};
    int neighborYIndex[8] = { 1,0,-1,0.1,1,-1,-1};
    for (double t = 0.0; t <= 1.0; t += 0.001)
    {
        auto point = recursive_bezier(control_points,t);
        window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
    }
}

提升:抗锯齿
根据点的位置到所在像素中心点距离,以及到相邻像素中心点的距离,计算相邻像素的颜色值。(可以是四邻或者八邻,下面以四邻距离说明)
在这里插入图片描述
假设当前像素Q点的颜色值为 c o l o r Q color_{Q} colorQ
则ABCD的颜色值分别为
c o l o r A = ∣ P Q ∣ / ∣ P A ∣ ∗ c o l o r Q color_{A}=|PQ|/|PA| * color_{Q} colorA=PQ∣/∣PAcolorQ
c o l o r B = ∣ P Q ∣ / ∣ P B ∣ ∗ c o l o r Q color_{B}=|PQ|/|PB| * color_{Q} colorB=PQ∣/∣PBcolorQ
c o l o r C = ∣ P Q ∣ / ∣ P C ∣ ∗ c o l o r Q color_{C}=|PQ|/|PC| * color_{Q} colorC=PQ∣/∣PCcolorQ
c o l o r D = ∣ P Q ∣ / ∣ P D ∣ ∗ c o l o r Q color_{D}=|PQ|/|PD| * color_{Q} colorD=PQ∣/∣PDcolorQ
代码如下:

void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window) 
{
    // TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's 
    // recursive Bezier algorithm.

    int neighborXIndex[4] = { 0,1,0,-1};
    int neighborYIndex[4] = { 1,0,-1,0};
    for (double t = 0.0; t <= 1.0; t += 0.001)
    {
        auto point = recursive_bezier(control_points,t);
        window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
        int x = point.x;
        int y = point.y;
        cv::Point2f p1(x + 0.5, y + 0.5);
        float d1 = std::sqrt(std::pow(point.x - p1.x, 2) + std::pow(point.y - p1.y, 2));

        for (int i = 0; i < 4; i++)
        {
            cv::Point2f p(x+ neighborXIndex[i]*0.5,y+ neighborYIndex[i]*0.5);
            float d = std::sqrt(std::pow(point.x - p.x, 2) + std::pow(point.y - p.y, 2));
            window.at<cv::Vec3b>(y + neighborYIndex[i], x + neighborXIndex[i])[1] = d1 / d * 255;
        }
    }

}

总结
贝塞尔函数的定义比较简单,n次贝塞尔的函数的定义公式如下:
B ( t ) = ∑ i = 0 n ( n i ) P i ( 1 − t ) n − i 1 t i B(t)=\sum_{i=0}^n\binom{n}{i} P_i(1-t)^{n-i_1} t^i B(t)=i=0n(in)Pi(1t)ni1ti
所以也可以不用递归,而是通过这个公式实现N次贝塞尔函数。
一条贝塞尔打断成两端贝塞尔,同时保持断点初过渡平滑,可以参考博文

作业答案

本次作业的答案放在的git仓库中:作业地址

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

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

相关文章

鸿蒙ArkUI-X平台差异化:【运行态差异化(@ohos.deviceInfo)】

平台差异化 简介 跨平台使用场景是一套ArkTS代码运行在多个终端设备上&#xff0c;如Android、iOS、OpenHarmony&#xff08;含基于OpenHarmony发行的商业版&#xff0c;如HarmonyOS Next&#xff09;。当不同平台业务逻辑不同&#xff0c;或使用了不支持跨平台的API&#xf…

python纯脚本搬砖DNF之深度学习,工作室适用

声明&#xff1a; 本文章仅作学习交流使用,对产生的任何影响&#xff0c;本人概不负责. 转载请注明出处:https://editor.csdn.net/md?articleId103674748 主要功能 脚本已初步完成&#xff0c;可以上机实战了 1.搬砖研究所、海伯伦&#xff08;持续更新中&#xff09; 2.自…

【知识拓展】LocalTunnel-高性价比的内网穿透工具(2)

前言 上一篇通过ngrok进行内网穿透&#xff0c;有几个问题&#xff1a; ①需要注册&#xff0c;而且注册需要科学上网&#xff0c;相对麻烦 ②安装配置相对麻烦&#xff0c;authtoekn有限制 上述相对&#xff0c;指的是在非生产环境中做一个简单内网穿透&#xff0c;相对于…

C++系列-C/C++内存管理方式

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” C/C内存分布 在这篇文章开始之前&#xff0c;我们先以一道题目来进行引入&#xff1a; int glovalvar 1; static int staticGlovalvar 1; void Test() {static int staticva…

内网安全--域渗透准备知识

目录 知识点&#xff1a; 0x01 0x02 0x03 系列点&#xff1a; Linux主机信息收集 windows主机信息收集 知识点&#xff1a; 0、域产生原因 1、内网域的区别 2、如何判断在域内 3、域内常见信息收集 4、域内自动化工具收集 -局域网&工作组&域环境区别 -域…

Liunx系统中修改文件的创建时间以及访问时间

在Linux系统中&#xff0c;可以使用touch命令来修改文件的时间戳。以下是一些常用的touch命令选项&#xff1a; &#xff08;其实在MacOS中也适用&#xff09; 修改访问时间&#xff08;Access Time&#xff09;和修改时间&#xff08;Modification Time&#xff09;&#xf…

百亿级流量红包系统,如何做架构?(字节面试真题)

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的架构类/设计类的场景题&#xff1a; 1.如何设计高并发红包系统 &#xff0…

在没有dubbo-admin情况下如何判断zk中注册的dubbo服务是否注册成功

通常我们都是通过dubbo-admin来查看dubbo服务是否注册成功&#xff0c;那么如果没有部署dubbo-admind的情况下&#xff0c;我们如何来判断dubbo服务是否注册成功&#xff1a; 一、首先我们进入到zookeeper bin目录下使用以下指令连接到zk: ./zkCli.sh -server ip:port ip&…

Nginx配置文件简介与配置实例(负载均衡、动静分离、高可用集群)- 细节狂魔

文章目录 前言Nginx配置文件组成Nginx配置文件三个部分第一部分&#xff1a;全局块第二部分&#xff1a;events 块第三部分&#xff1a;http 块http 全局块server 块location 块 Nginx 配置实例实例1 - 反向代理预期实现效果具体实现 实例2 - 反向代理实现效果准备工作一&#…

JavaRedis-主从集群-分片-数据结构-回收处理-缓存问题

一、主从集群 1.主从集群 主从集群读写分离&#xff0c;主能读能写&#xff0c;从只能读&#xff0c;读的数据是同步主的 docker搭建&#xff1a; docker-compose 这里设置网络模式为model&#xff0c;就直接暴露在了宿主机中&#xff0c;就不用映射端口了 不改就是默认的桥…

PPT图片高清导出

PPT制作的图片高清导出 适用于windows系统 案例 例如想要导出下面这张图片 1. 保存为emf文件 2. 将emf文件导入画图软件 导入方法直接将emf文件拖进去就行&#xff0c;可以看到图片成功高清显示&#xff08;可以通过放缩检查是否模糊&#xff09;。 3. 修改分辨率 点击上方…

力扣刷题--448. 找到所有数组中消失的数字【简单】

题目描述 给你一个含 n 个整数的数组 nums &#xff0c;其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字&#xff0c;并以数组的形式返回结果。 示例 1&#xff1a; 输入&#xff1a;nums [4,3,2,7,8,2,3,1] 输出&#xff1a;[5,6…

吉林大学计科21级《软件工程》期末考试真题

文章目录 21级期末考试题一、单选题&#xff08;2分一个&#xff0c;十个题&#xff0c;一共20分&#xff09;二、问答题&#xff08;5分一个&#xff0c;六个题&#xff0c;一共30分&#xff09;三、分析题&#xff08;一个10分&#xff0c;一共2个&#xff0c;共20分&#xf…

JAVA方法引用,异常,File,IO流知识总结

文章目录 JAVA第六周学习笔记方法引用引用静态方法引用成员方法引用构造方法其他调用方式使用类名引用成员方法引用数组的构造方法 异常作用处理方式常见成员方法抛出异常finally自定义异常 File路径构造方法**判断、获取****创建 、删除****获取并遍历**练习 IO流体系字节流Fi…

yolov8报警图片写入minio服务器 Rabbitmq发送地址

OSError [WinError 1455]页面文件太小&#xff0c;无法完成操作”解决方案“_深度学习_yangshejun-GitCode 开源社区 (csdn.net) python对RabbitMQ的简单使用_python rabbitmq-CSDN博客 【Windows安装RabbitMQ详细教程】_rabbitmq windows-CSDN博客 Windows 10安装Minio 文件…

学 Go 具体能干什么?

学习 Go (Golang) 后&#xff0c;你可以从事许多不同的工作和项目&#xff0c;Go 语言以其高性能、并发处理和简洁的语法而闻名&#xff0c;特别适合以下几个领域&#xff1a; 1. 后端开发 Go 在后端开发中非常流行&#xff0c;特别适合构建高性能的 Web 服务和 API。 Web 框…

脑机接口习题

9-12章习题 填空题 EEG电极分为 主动电极 和 被动电极 &#xff0c;其中 被动电极 直接与放大器连接&#xff0c; 主动电极 包含一个1~10倍的前置放大。除抗混淆滤波器&#xff0c;放大系统也包含由电阻器、电容器构成的模拟滤波器&#xff0c;把信号频率内容限制在一个特定的…

【QT+VS】如何在现有VS项目中添加Qt界面?【全网最详细】

0. 前置步骤 参考如下链接文章中的 前3个步骤(1:下载Qt;2:安装Qt;3:安装Qt插件),完成环境的配置和安装。 深耕AI:如何联合Qt,VS,C++,来开发一个电脑版软件(简单有趣,详细) 本文的基础项目链接为: c++工程+图像分割预测+mmdet+实例分割+最新工程+简洁易懂+新手…

斯坦福2024人工智能指数报告 1

《人工智能指数报告》由斯坦福大学、AI指数指导委员会及业内众多大佬Raymond Perrault、Erik Brynjolfsson 、James Manyika、Jack Clark等人员和组织合著&#xff0c;旨在追踪、整理、提炼并可视化与人工智能&#xff08;AI&#xff09;相关各类数据&#xff0c;该报告已被大多…

Redis学习篇2:Redis在Spring中的应用

本文继上文开始讲述了Redis在IDEA中如何应用以及集成进入spring开发环境&#xff0c;以及如何使用Redis客户端。上一个文章&#xff1a;Redis学习篇1&#xff1a;初识Redishttps://blog.csdn.net/jialuosi/article/details/139057088 一、Redis在java中的客户端 二、SpringDat…