Games101-作业4-贝塞尔曲线(含提高)
分析
这次作业比较简单。
按照说明明白两个函数的用途即可:
- recursive_bezier:使用de Casteljau算法对控制点和t生成一个贝塞尔曲线点,递归算法。
- bezier:生成不同的t并传给recursive_bezier函数,根据返回值画出点。
- native_bezier:写好的函数。直接用代数展开式算出点的位置,用来检验结果。
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; t += 0.001)
{
auto point = recursive_bezier(control_points, t);
window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
}
}
recursize_bezier
重点是递归的写法。
cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t)
{
// TODO: Implement de Casteljau's algorithm
// 递归出口条件:一阶贝塞尔曲线
auto& p = control_points;
if (p.size() == 2)
return (1 - t) * p[0] + t * p[1];
std::vector<cv::Point2f> b;
for (int i = 0; i < p.size()-1; i++)
b.push_back((1 - t) * p[i] + t * p[i + 1]);
return recursive_bezier(b, t);
}
结果
把native_bezier打开,法线曲线吻合。
反走样
要求:实现对Bézier 曲线的反走样(对于一个曲线上的点,不只把它对应于一个像
素,你需要根据到像素中心的距离来考虑与它相邻的像素的颜色)。
根据要求中的提示,每得到一个曲线上的点时,我们就根据它到自己周围的3×3个像素中心的距离d来为这些像素填色以达到平滑过渡的效果(每个像素的颜色是255*ratio,d的范围是[0,3/√2],ratio的范围是[0,1],那么ratio关于d的函数就是ratio=1-√2/3d),重复计算的点就按照该点的颜色最大值算,这样就不会在线段中间出现暗点了
void bezier2(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; t += 0.001)
{
auto point = recursive_bezier(control_points, t);
window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
int x = point.x, y = point.y;// 像素位置
for (int dx = -1; dx <= 1; dx++)
{
for (int dy = -1; dy <= 1; dy++)
{
if (x + dx > 700 || x + dx < 0 || y + dy > 700 || y + dy < 0) continue;
double d = std::sqrt(std::pow(point.x - (x + dx+0.5), 2) + std::pow(point.y -(y + dy+0.5), 2));
double ratio = 1 - sqrt(2) * d / 3;
window.at<cv::Vec3b>(point.y + dy, point.x + dx)[1] = std::fmax(window.at<cv::Vec3b>(point.y + dy, point.x + dx)[1], 255 * ratio);
}
}
}
}
反走样前:
反走样后: