当前位置:   article > 正文

GAMES101作业4-贝塞尔曲线&OpenCV图像处理_图像rgb的曲线是贝塞尔曲线么

图像rgb的曲线是贝塞尔曲线么

目录

作业内容

实现代码

分段解析

mouse_handler()函数

 cv处理鼠标事件

naive_bezier()

recursive_bezier()递归找出点轨迹

main()函数

cvtColor()

图像色彩模式

参考


作业内容

实现代码

  1. #include <chrono>
  2. #include <iostream>
  3. #include <opencv2/opencv.hpp>
  4. std::vector<cv::Point2f> control_points;//控制点-动态数组
  5. void mouse_handler(int event, int x, int y, int flags, void *userdata)
  6. {
  7. if (event == cv::EVENT_LBUTTONDOWN && control_points.size() < 4)
  8. {
  9. std::cout << "Left button of the mouse is clicked - position (" << x << ", "
  10. << y << ")" << '\n';
  11. control_points.emplace_back(x, y);
  12. }
  13. }
  14. void naive_bezier(const std::vector<cv::Point2f> &points, cv::Mat &window)
  15. {
  16. auto &p_0 = points[0];
  17. auto &p_1 = points[1];
  18. auto &p_2 = points[2];
  19. auto &p_3 = points[3];
  20. for (double t = 0.0; t <= 1.0; t += 0.001)
  21. {
  22. auto point = std::pow(1 - t, 3) * p_0 + 3 * t * std::pow(1 - t, 2) * p_1 +
  23. 3 * std::pow(t, 2) * (1 - t) * p_2 + std::pow(t, 3) * p_3;
  24. window.at<cv::Vec3b>(point.y, point.x)[2] = 255;
  25. }
  26. }
  27. cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t)
  28. {
  29. int n = control_points.size();
  30. if (n == 1) return control_points[0];
  31. std::vector<cv::Point2f> res_control_points;
  32. for (int i = 0; i <n-1; i++) {
  33. res_control_points.push_back(cv::Point2f(
  34. (1 - t) * control_points[i].x + t * control_points[i + 1].x,
  35. (1 - t) * control_points[i].y + t * control_points[i + 1].y));
  36. }
  37. return recursive_bezier(res_control_points, t);
  38. }
  39. void bezier(const std::vector<cv::Point2f> &control_points, cv::Mat &window)
  40. {
  41. // TODO: Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's
  42. // recursive Bezier algorithm.
  43. for (double t = 0.0; t <= 1.0; t += 0.001)
  44. {
  45. cv::Point2f point = recursive_bezier(control_points, t);
  46. window.at<cv::Vec3b>(point.y, point.x)[1] = 255;
  47. }
  48. }
  49. int main()
  50. {
  51. cv::Mat window = cv::Mat(700, 700, CV_8UC3, cv::Scalar(0));
  52. cv::cvtColor(window, window, cv::COLOR_BGR2RGB);
  53. cv::namedWindow("Bezier Curve", cv::WINDOW_AUTOSIZE);
  54. cv::setMouseCallback("Bezier Curve", mouse_handler, nullptr);
  55. int key = -1;
  56. while (key != 27)
  57. {
  58. for (auto &point : control_points)
  59. {
  60. cv::circle(window, point, 3, {255, 255, 255}, 3);
  61. }
  62. if (control_points.size() == 4)
  63. {
  64. naive_bezier(control_points, window);
  65. bezier(control_points, window);
  66. cv::imshow("Bezier Curve", window);
  67. cv::imwrite("my_bezier_curve.png", window);
  68. key = cv::waitKey(0);
  69. return 0;
  70. }
  71. cv::imshow("Bezier Curve", window);
  72. key = cv::waitKey(20);
  73. }
  74. return 0;
  75. }

分段解析

mouse_handler()函数

  1. void mouse_handler(int event, int x, int y, int flags, void *userdata)
  2. {
  3. //event是鼠标事件:滑动,点击,双击等动作
  4. //x 鼠标点击点的横坐标
  5. //y 鼠标点击点的纵坐标
  6. //flags 鼠标拖拽以及键盘和鼠标联合事件:鼠标拖拽,按住ctrl不放等
  7. if (event == cv::EVENT_LBUTTONDOWN && control_points.size() < 4)
  8. {
  9. std::cout << "Left button of the mouse is clicked - position (" << x << ", "
  10. << y << ")" << '\n';
  11. control_points.emplace_back(x, y);
  12. }
  13. }

可以观察在用鼠标操作时,窗口会根据这个回调函数输出命令:

 cv处理鼠标事件

setMouseCallback()函数是用来处理鼠标动作的函数,我们可以利用它来做有用的操作来处理鼠标动作,首先需要创建一个回调函数,当鼠标事件触发时,该函数执行。

Even包含:滑动,点击,放开,双击等;

详见参考:OpenCV处理鼠标事件方法_bubble_story的博客

naive_bezier()

  1. void naive_bezier(const std::vector<cv::Point2f> &points, cv::Mat &window)
  2. {
  3. auto &p_0 = points[0];
  4. auto &p_1 = points[1];
  5. auto &p_2 = points[2];
  6. auto &p_3 = points[3];
  7. for (double t = 0.0; t <= 1.0; t += 0.001)
  8. {
  9. auto point = std::pow(1 - t, 3) * p_0 + 3 * t * std::pow(1 - t, 2) * p_1 +
  10. 3 * std::pow(t, 2) * (1 - t) * p_2 + std::pow(t, 3) * p_3;
  11. //img.at<cv::Vec3b>(int y, int x)代表(x, y)坐标的颜色明度
  12. //img.at<cv::Vec3b>(int y, int x)[] 012分别对应RGB值
  13. window.at<cv::Vec3b>(point.y, point.x)[2] = 255;
  14. }
  15. }

recursive_bezier()递归找出点轨迹

  1. cv::Point2f recursive_bezier(const std::vector<cv::Point2f> &control_points, float t)
  2. {
  3. // TODO: Implement de Casteljau's algorithm
  4. //recrusive - 递归 这里是一个递归贝塞尔,要用到循环
  5. /*递归性质:
  6. 1.控制点有三个;
  7. 2.控制点形成两个线段,每个线段有一个点在运动,得到两个点;
  8. 3.两个点在形成一个线段,这个线段也有一个点运动,得到一个点;
  9. 4.最后这个点的运动轨迹就构成了贝塞尔曲线啦!
  10. 5.假设我们得到n个控制点,形成n-1条线段 ——> 得到n-1个控制点,形成n-2个线段...
  11. 循环,一直到最后一个线段上的一个控制点,这个控制点的轨迹就是曲线。
  12. 于是,我们就需要递归循环了。
  13. */
  14. //在实现递归前需要确定两个变量:1.控制点的数量n 2.t的值
  15. int n = control_points.size();
  16. //如果n==1,则返回该点并终止
  17. if (n == 1) return control_points[0];
  18. //需要有个储存n-1控制点的动态数组vector,形式参考 std::vector<cv::Point2f> &control_points
  19. std::vector<cv::Point2f> res_control_points;
  20. //开始递归
  21. for (int i = 0; i <n-1; i++) {
  22. //添加新的n-1个控制点,根据公式给出坐标,push_back()是给vector容器末尾添加新元素
  23. res_control_points.push_back(cv::Point2f(
  24. (1 - t) * control_points[i].x + t * control_points[i + 1].x,
  25. (1 - t) * control_points[i].y + t * control_points[i + 1].y));
  26. }
  27. return recursive_bezier(res_control_points, t);
  28. }

关于贝塞尔曲线可以参考文章,讲的很好: 从零开始学图形学:10分钟看懂贝塞尔曲线 - 知乎 (zhihu.com)

main()函数

  1. ...
  2. int main()
  3. {
  4. /*
  5. * 创建cv::Mat类对象
  6. * 700,700 - 矩阵的行和列
  7. * CV_8UC3 - CV_是CvMat矩阵对应的格式,8UC表示图像文件格式是Unsigned 8bits,后面的3表示通道数
  8. * Scalar() - 是将图像设置成单一灰度&颜色,顺序RGB:Scalar(255)表示红色,Scalar(0,0,255)表示蓝色
  9. */
  10. cv::Mat window = cv::Mat(700, 700, CV_8UC3, cv::Scalar(150,0,0));
  11. /*
  12. * OpenCV提供了cvtColor()函数用于在图像中不同色彩空间进行转换
  13. * OpenCV默认的色彩图像的颜色空间是BGR
  14. * cv::BGR2RGB - BGR to RGB 转换成scalar遵循的RGB
  15. 例如:如果没有这个,那么Scalar(150,0,0)输出的背景将会是蓝色
  16. */
  17. cv::cvtColor(window, window, cv::COLOR_BGR2RGB);
  18. cv::namedWindow("Bezier Curve", cv::WINDOW_AUTOSIZE);
  19. cv::setMouseCallback("Bezier Curve", mouse_handler, nullptr);
  20. int key = -1;
  21. while (key != 27)
  22. {
  23. for (auto &point : control_points)
  24. {
  25. /*cv2.circle(image, center_coordinates, radius, color, thickness)
  26. * image - 绘制到图像image上,这里是绘制在定义好的window窗口上
  27. * center_coordiantes - 圆心点
  28. * radius - 圆半径
  29. * color - 圆的颜色,这里{255,255,255}是白色
  30. * thickness - 线粗
  31. */
  32. cv::circle(window, point, 3, {255, 255, 255}, 3);
  33. }
  34. ...

cvtColor()

调用形式:

  1. void cv::cvtColor(
  2. cv::InputArray src, // 输入序列
  3. cv::OutputArray dst, // 输出序列
  4. int code, // 颜色映射码
  5. int dstCn = 0 // 输出的通道数 (0='automatic')
  6. );

支持多种颜色空间的转换,具体参考:【OpenCV3】颜色空间转换——cv::cvtColor()详解_PHILOS_THU的博客

图像色彩模式

(1)位图模式

最基本的格式,图象只有黑白,0或1,色彩图想转变成黑白图,要首先将图像转换成灰度模式再进行转换。

(2)灰度模式

使用256级的灰度来表示图像,一个像素相当于占用8为一个字节,每个像素值使用0到255的亮度值代表,其中0为黑色,255为白色,相当于从黑->灰->白的过渡。

(3)RGB模式

RGB模式的图像有3个颜色通道,分布为红(Red),绿(Green)和蓝(Bule),每个都占用8位一个字节来表示颜色信息,这样每个颜色的取值范围为0~255,那么就三种颜色就可以有多种组合。三个值相等 - 灰色;三个值都为0 - 黑色;三个值都为255 - 白色。

(4)HSB模式

根据日常生活中人眼的视觉对色彩的观察得而制定的一套色彩模式,最接近与人类对色彩的辨认的思考方式,所有的颜色都是用色彩三属性来描述

H:(色相):是指从物体反射或透过物体传播的颜色

S:(饱和度):是指颜色的强度或纯度,表示色相中灰色成分所占的比例

B:(亮度):是指颜色对相对明暗程度,通常 100%定义为白色;0%为黑色

参考

图像处理:c++ opensv数字图像处理3:通过鼠标点击操作获取图像的像素坐标和像素值_‭刘燚的博客

色彩模式:

学习opencv之cvtColor_Huo的藏经阁的博客-CSDN博客

鼠标事件:

OpenCV处理鼠标事件方法_bubble_story的博客

贝塞尔曲线:

从零开始学图形学:10分钟看懂贝塞尔曲线 - 知乎 (zhihu.com)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/264031
推荐阅读
相关标签
  

闽ICP备14008679号