要求:
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 曲线上对应点的坐标。
我这里自己写的是可以适用于任意个控制点数的方案,修改控制点数就在main里面的while循环里if (control_points.size() == 4) 和mouse_handler函数里的 if (event == cv::EVENT_LBUTTONDOWN && control_points.size() < 4) 里改一下数字就好。(这次的作业好简单
int fact(int n) { //算阶乘
return (n == 0 || n == 1) ? 1 : n * fact(n - 1);
}
cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t)
{
// TODO: Implement de Casteljau's algorithm
int n = control_points.size();
cv::Point2f point_t(0, 0);
for (int i = 0; i < n; i++) {
float num = fact(n - 1) / fact(i) / fact(n - 1 - i) * pow(t, i) * pow(1 - t, n - 1 - i);
point_t += num * control_points[i];
}
return point_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.
int n = control_points.size();
bool isAnitialiasing = true;
for (double t = 0.0; t <= 1.0; t += 0.001) {
if (!isAnitialiasing) { //不用反走样的版本,简单粗暴
cv::Point2f point = recursive_bezier(control_points, t);
window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
}
else { //反走样
// 对周边取四个像素点都进行距离的计算和插值
auto dist = [&](float x, float y, float px, float py) {
return sqrt(pow(x - px, 2) + pow(y - py, 2));
};
cv::Point2f point = recursive_bezier(control_points, t);
float x_min = floor(point.x) + 0.5;
float y_min = floor(point.y) + 0.5;
float x_max = ceil(point.x) + 0.5;
float y_max = ceil(point.y) + 0.5;
float distanceCur = dist(point.x, point.y, x_min, y_min);
if (distanceCur < 1 && window.at<cv::Vec3b>(x_min, y_min)[1] < distanceCur * 255)
window.at<cv::Vec3b>(y_min, x_min)[1] = distanceCur * 255;
distanceCur = dist(point.x, point.y, x_min, y_max);
if (distanceCur < 1 && window.at<cv::Vec3b>(x_min, y_max)[1] < distanceCur * 255)
window.at<cv::Vec3b>(y_max, x_min)[1] = distanceCur * 255;
distanceCur = dist(point.x, point.y, x_max, y_min);
if (distanceCur < 1 && window.at<cv::Vec3b>(x_max, y_min)[1] < distanceCur * 255)
window.at<cv::Vec3b>(y_min, x_max)[1] = distanceCur * 255;
distanceCur = dist(point.x, point.y, x_max, y_max);
if (distanceCur < 1 && window.at<cv::Vec3b>(x_max, y_max)[1] < distanceCur * 255)
window.at<cv::Vec3b>(y_max, x_max)[1] = distanceCur * 255;
}
}
}