zoukankan      html  css  js  c++  java
  • Games101--Assignment4

    Assignment4的要求

    实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更多点来控制的Bézier 曲线)。
    • 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 曲
      线。

    具体步骤

    注意1的是OpenCV中的坐标系基于rows和columns,因为图像被编码为矩阵形式,矩阵索引先行后列,所以定义pixel的使用的是先y后x,y即为第几列,x即为第几行;
    注意2的是OpenCV使用的是BGR颜色存储顺序;

    recursive_bezier函数如下:

    cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t) 
    {
        // TODO: Implement de Casteljau's algorithm
        cv::Point2f ret;
        if(control_points.size()==1) ret=*control_points.begin();
        std::vector<cv::Point2f> old_points(control_points),new_points;
        while(old_points.size()!=1){
            for(int i=0;i<old_points.size()-1;i++){
                new_points.push_back(old_points[i]*(1-t)+old_points[i+1]*t);
            }
            old_points.clear();
            old_points=new_points;
            new_points.clear();
        }
        ret=*old_points.begin();
        return ret;
    }
    

    bezier函数如下:

    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.
        for (float t = 0.0; t <= 1.0; t += 0.001){
            auto p=recursive_bezier(control_points,t);
            //window.at<cv::Vec3b>(p.y, p.x)[0] = 255;  //B
            window.at<cv::Vec3b>(p.y, p.x)[1] = 255;  //G
            //window.at<cv::Vec3b>(p.y, p.x)[2] = 102;  //R
        }
    }
    

    使用6个控制点:

    #include <chrono>
    #include <iostream>
    #include <opencv2/opencv.hpp>
    std::vector<cv::Point2f> control_points;
    void mouse_handler(int event, int x, int y, int flags, void *userdata) 
    {
        if (event == cv::EVENT_LBUTTONDOWN && control_points.size() < 6) 
        {
            std::cout << "Left button of the mouse is clicked - position (" << x << ", "<< y << ")" << '
    ';
            control_points.emplace_back(x, y);
        }     
    }
    void naive_bezier(const std::vector<cv::Point2f> &points, cv::Mat &window) 
    {
        auto &p_0 = points[0];
        auto &p_1 = points[1];
        auto &p_2 = points[2];
        auto &p_3 = points[3];
        for (double t = 0.0; t <= 1.0; t += 0.001) 
        {
            auto point = std::pow(1 - t, 3) * p_0 + 3 * t * std::pow(1 - t, 2) * p_1 +
                     3 * std::pow(t, 2) * (1 - t) * p_2 + std::pow(t, 3) * p_3;
            //window.at<cv::Vec3b>(point.y, point.x)[0] = 255; //B
            window.at<cv::Vec3b>(point.y, point.x)[1] = 255; //G
            //window.at<cv::Vec3b>(point.y, point.x)[2] = 255; //R
        }
    }
    cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t) 
    {
        // TODO: Implement de Casteljau's algorithm
        cv::Point2f ret;
        if(control_points.size()==1) ret=*control_points.begin();
        std::vector<cv::Point2f> old_points(control_points),new_points;
        while(old_points.size()!=1){
            for(int i=0;i<old_points.size()-1;i++){
                new_points.push_back(old_points[i]*(1-t)+old_points[i+1]*t);
            }
            old_points.clear();
            old_points=new_points;
            new_points.clear();
        }
        ret=*old_points.begin();
        return ret;
    }
    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.
        for (float t = 0.0; t <= 1.0; t += 0.001){
            auto p=recursive_bezier(control_points,t);
            window.at<cv::Vec3b>(p.y, p.x)[0] = 255;  //B
            window.at<cv::Vec3b>(p.y, p.x)[1] = 204;  //G
            window.at<cv::Vec3b>(p.y, p.x)[2] = 102;  //R
        }
    }
    int main() 
    {
        cv::Mat window = cv::Mat(700, 700, CV_8UC3, cv::Scalar(0));
        cv::cvtColor(window, window, cv::COLOR_BGR2RGB);
        cv::namedWindow("Bezier Curve", cv::WINDOW_AUTOSIZE);
        cv::setMouseCallback("Bezier Curve", mouse_handler, nullptr);
        int key = -1;
        while (key != 27) 
        {
            for (auto &point : control_points) 
            {
                cv::circle(window, point, 3, {255, 255, 255}, 3);
            }
            if (control_points.size() == 6) 
            {
                //naive_bezier(control_points, window);
                bezier(control_points, window);
    
                cv::imshow("Bezier Curve", window);
                cv::imwrite("my_bezier_curve.png", window);
                key = cv::waitKey(0);
    
                return 0;
            }
            cv::imshow("Bezier Curve", window);
            key = cv::waitKey(20);
        }
    return 0;
    }
    

  • 相关阅读:
    设置DataGridView垂直滚动条
    在自定义MessageBox控件里添加键盘回车事件。
    通过访问注册表,表判断系统是否装excel
    让文本框里只能输入数字
    新晋菜鸟的错误
    jdbc连接数据库以及crud(简单易懂,本人亲测可用 有源代码和数据库)
    springboot 错误求解决
    maven 导包报错
    最短路径Dijkstra
    读写者问题
  • 原文地址:https://www.cnblogs.com/FlyerBird/p/13423368.html
Copyright © 2011-2022 走看看