GAMES101 作业4 贝塞尔曲线 (Bézier Curve)

具体代码:

#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() < 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<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)[2] = 255;
    }
}

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

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(double t=0.0;t<=1.0;t+=0.0001)
    {
    	cv::Point2f point=recursive_bezier(control_points,t);
    	window.at<cv::Vec3b>(point.y,point.x)[1]=255;
    	
    	float x=point.x-std::floor(point.x);
    	float y=point.y-std::floor(point.y);
    	
    	int x_flag=x<0.5f? -1:1;
    	int y_flag=y<0.5f? -1:1;
    	
    	cv::Point2f p00=cv::Point2f(std::floor(point.x)+0.5f,std::floor(point.y)+0.5f);
    	cv::Point2f p01=cv::Point2f(std::floor(point.x+x_flag*1.0f)+0.5f,std::floor(point.y)+0.5f);
    	cv::Point2f p10=cv::Point2f(std::floor(point.x)+0.5f,std::floor(point.y+y_flag*1.0f)+0.5f);
    	cv::Point2f p11=cv::Point2f(std::floor(point.x+x_flag*1.0f)+0.5f,std::floor(point.y+y_flag*1.0f)+0.5f);
    	
    	std::vector<cv::Point2f> vec;
    	vec.push_back(p01);
    	vec.push_back(p10);
    	vec.push_back(p11);
    	
    	cv::Point2f distance=p00-point;
    	float len=sqrt(distance.x*distance.x+distance.y*distance.y);
    	
    	for(auto p:vec)
    	{
    		cv::Point2f d=p-point;
    		float l=sqrt(d.x*d.x+d.y*d.y);
    		float percent=len/l;
    		
    		cv::Vec3d color=window.at<cv::Vec3b>(p.y,p.x);
    		
    		color[1]=std::max(color[1],(double)255*percent);
    		window.at<cv::Vec3b>(p.y,p.x)=color;
    	}
    	
    	
    }

}

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;
}

得到效果

在这里插入图片描述

理论上通过递归是可以实现任何点数的贝塞尔曲线的
在这里插入图片描述
把这个数字改成5

在这里插入图片描述
这个也改成5

得到结果

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值