games101作业4


  • 代码部分:

    #include 
    #include 
    #include
    #include 
    
    std::vector control_points;
    
    void mouse_handler(int event, int x, int y, int flags, void *userdata) 
    {
        if (event == cv::EVENT_LBUTTONDOWN && control_points.size() < 4) 
        {
            std::cout << "Left button of the mouse is clicked - position (" << x << ", "
            << y << ")" << '\n';
            control_points.emplace_back(x, y);
        }     
    }
    
    void naive_bezier(const std::vector &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(point.y, point.x)[2] = 255;
        }
    
    }
    
    //递归,只剩一个点则停止
    cv::Point2f recursive_bezier(const std::vector &control_points, float t) 
    {
        // TODO: Implement de Casteljau's algorithm
        auto s = control_points.size();
        if (s == 1) return control_points[0];
        std::vectorresult;
        for (int i = 0; i < s - 1; ++i)
        {
            auto tmp = control_points[i] * ( 1 - t ) + control_points[i+1] * t;
            result.push_back(tmp);
        }
        return recursive_bezier( result, t );
    }
    
    void bezier(const std::vector &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 (double t = 0.0; t <= 1.0; t += 0.001)
        {
            cv::Point2f point = recursive_bezier(control_points, t);
            //点的颜色
            //window.at(point.y, point.x) = {0,255,0};
            //这种单独写是正确的,但无法同时调用出黄色
            window.at( point.y, point.x )[1] = 255;
        }
    }
    
    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() == 4) 
            {
                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;
    }
    
  • 说明:

    • Point2f(x,y):
      • x代表在图像中的列,y代表图像中的行
    • cv::Mat
      • 1、2 :
        行、列
      • 3:预定义格式:
        CV_(S|U|F)C
        bit_depth:图像深度(位数),代表8、16、32、64位
        S: signed int
        U: unsigned int
        F: float
        C: 存储的图片的通道数
        eg:单通道,GRAYIMG,灰度图像;
        双通道,图像压缩,傅里叶变化
        三通道,RGB
        四通道,带ALPHA透明度的RGB
    • void cv::nameWindow(const string& winname,int flags = WINDOW_AUTOSIZE) : 新建一个显示窗口
      • const string& winname: 新建的窗口的名称
      • int flags = WINDOW_AUTOSIZE: 窗口的标识
        • WINDOW_AUTOSIZE 窗口大小自动适应图片大小,并且不可手动更改。
        • WINDOW_NORMAL 用户可以改变这个窗口大小
        • WINDOW_OPENGL 窗口创建的时候会支持OpenGL
    • void cv::circle (InputOutputArray img, Point center, int radius, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
      • InputOutputArray img:在哪画圆
      • Point center:圆心
      • int radius:半径
      • const Scalar &color:圆的颜色
      • int thickness=1:粗细
      • int lineType=LINE_8:圆边界类型
      • int shift=0:中心坐标和半径值中的小数位数