第一节课

显示第一张图片

环境配置了一个早上,到10.48分配置完毕,有点难受。还好最后显示出第一张图片。

  1. #include<opencv2/opencv.hpp>
  2. #include<iostream>
  3. using namespace std;
  4. using namespace cv;
  5. int main()
  6. {
  7. //读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
  8. Mat src = imread("D:/images/011.jpg",IMREAD_GRAYSCALE);
  9. if (src.empty())
  10. {
  11. printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
  12. }
  13. //超过屏幕的图像无法显示时候调用此函数。
  14. namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
  15. imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat
  16. waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
  17. destroyAllWindows();//销毁前面创建的显示窗口
  18. return 0;
  19. }

第一节课小结

第一节课介绍了如何读取第一张图片,并且显示出来,通过调用imread函数读取照片,再调用imshow显示图片到窗口。同时,讲述了如何打印灰度图像,图片读取失败的处理方式,代码注释详细介绍了每条语句的意思

第二节课

显示第一张图片

1、色彩空间转换函数 cvtColor
2、图像的保存

  1. #include<opencv2/opencv.hpp>
  2. using namespace cv;
  3. class QuickDemo //创建一个QuickDemo对象
  4. {
  5. public:
  6. void colorSpace_Demo(Mat &imge); //定义一个类,里面包含输入一个图片,对图片操作
  7. };
  8. #include<quickopencv.h>
  9. void QuickDemo::colorSpace_Demo(Mat &image)
  10. {
  11. Mat gray, hsv;//定义2个矩阵类的图像gray和hsv,
  12. //图像转换函数,可以把image转成hsv,第三个参数是转成的类型
  13. cvtColor(image,hsv,COLOR_BGR2HSV);
  14. //图像转换函数,可以把image转成hsv,第三个参数是转成的类型
  15. cvtColor(image,gray,COLOR_BGR2GRAY);
  16. imshow("HSV",hsv);
  17. imshow("灰度",gray);
  18. imwrite("D:/hsv.jpg",hsv);//保存图片,前面是保存图的地址,后面是保存图的名称
  19. imwrite("D:/gray.jpg",gray);
  20. }
  21. #include<opencv2/opencv.hpp>
  22. #include<iostream>
  23. #include<quickopencv.h>
  24. using namespace std;
  25. using namespace cv;
  26. int main()
  27. {
  28. Mat src = imread("D:/images/1.jpg",IMREAD_ANYCOLOR);//B,G,R实际上0-255三色。3通道
  29. //读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
  30. if (src.empty())
  31. {
  32. printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
  33. return -1;
  34. }
  35. //超过屏幕的图像无法显示时候调用此函数。
  36. //创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
  37. namedWindow("输入窗口", WINDOW_FREERATIO);
  38. //表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat
  39. imshow("输入窗口", src);
  40. //在主函数中调用之前创建的类对象
  41. QuickDemo qd;
  42. qd.colorSpace_Demo(src);
  43. waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
  44. destroyAllWindows();//销毁前面创建的显示窗口
  45. return 0;
  46. }

第二节课小结

这节主要介绍了创建一个类对象,然后通过类对象调用函数,在main主函数中进行调用实现类对象中的功能,比如转换成HSV类型图片和GRAY类型图片,最后通过imwrite函数进行图像的保存。

第三节课

图像对象的创建与赋值

1、怎么操作mat
2、怎么访问每一个像素点
3、怎么创建一个空图或者mat

  1. void QuickDemo::mat_creation_demo(Mat &image)
  2. {
  3. Mat m1, m2;
  4. m1 = image.clone();
  5. image.copyTo(m2);
  6. //创建空白图像
  7. Mat m3 = Mat::ones(Size(400, 400), CV_8UC3);//创建8*8的CV8位的无符号的n通道的unsigned char
  8. //ones&zeros是初始化的方法
  9. m3 = Scalar(255, 0, 0);//给三个通道都赋值127 ,单通道赋值方法 m3 = 127;
  10. //m3初始为蓝色
  11. //数据的宽度和长度是由通道数决定的。
  12. //std::cout << "width:"<<m3.cols<<"height"<< m3.rows <<"channels"<<m3.channels()<< std::endl;
  13. //用来查看宽度,高度与通道数。
  14. /*std::cout << m3 << std::endl;*/
  15. Mat m4 = m3;//赋值M4就是M3 M4改变了,M3也改变了,没有产生新的自我(M4与M3同体)
  16. //M4为M3的克隆,M3还是原来的颜色,不会改变。(M4与M3不同体,各自是各自的颜色)
  17. Mat m4 = m3.clone();
  18. //m3.copyTo(m4);//把M3赋值给M4,M4就是蓝色
  19. m4 = Scalar(0, 255, 255);//改变m4的颜色为黄色 ,m4也改变
  20. imshow("图像3", m3);//标题和图像名称 显示图像m3 纯蓝色
  21. imshow("图像4", m4);//标题和图像名称
  22. }

第三节课小结

本节课介绍了如何创建一个Mat对象,通过创建新的Mat对象来创建用户的特定的底色画布,创建图像的基本类型有两种一种是ones一种是zeros,ones()中的第一个参数代表图像的大小,第二个参数代表创建几维的图像,UC代表无符号字符型,数组3代表通道数。克隆和赋值的区别,克隆就是产生一个新的对象,新对象改变属性,旧对象属性不变(各自为政)。赋值是二者同体,当新属性发生改变,旧属性也发生改变(二者同体)。

第四节课

图像像素的读写操作

如何遍历和修改每个像素点的数值,分为单通道和多通道。访问模式模式也有两种。第一种是数组访问模式,用最常规的数组下标访问像素值。

  1. void QuickDemo::pixel_visit_demo(Mat &image)
  2. {
  3. int dims = image.channels();
  4. int h = image.rows;
  5. int w = image.cols;
  6. for (int row = 0; row < h; row++)
  7. {
  8. for (int col = 0; col < w; col++)
  9. {
  10. if (dims == 1) //单通道的灰度图像
  11. {
  12. int pv = image.at<uchar>(row, col);//得到像素值
  13. image.at<uchar>(row, col) = 255 - pv;//给像素值重新赋值
  14. }
  15. if (dims == 3) //三通道的彩色图像
  16. {
  17. Vec3b bgr = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值
  18. image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
  19. image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
  20. image.at<Vec3b>(row, col)[2] = 255 - bgr[2];//对彩色图像读取它的像素值,并且对像素值进行改写。
  21. }
  22. }
  23. }
  24. namedWindow("像素读写演示", WINDOW_FREERATIO);
  25. imshow("像素读写演示", image);
  26. }

第二种为指针访问模式,指定一个指针为图片的首地址,通过循环遍历,指针++,一次往后推。

  1. void QuickDemo::pixel_visit_demo(Mat &image)
  2. {
  3. int dims = image.channels();
  4. int h = image.rows;
  5. int w = image.cols;
  6. for (int row = 0; row < h; row++)
  7. {
  8. uchar *current_row = image.ptr<uchar>(row);
  9. for (int col = 0; col < w; col++)
  10. {
  11. if (dims == 1) //单通道的灰度图像
  12. {
  13. int pv = *current_row;//得到像素值
  14. *current_row++ = 255 - pv;//给像素值重新赋值
  15. }
  16. if (dims == 3) //三通道的彩色图像
  17. {
  18. *current_row++ = 255 - *current_row; //指针每做一次运算,就向后移动一位
  19. *current_row++ = 255 - *current_row;
  20. *current_row++ = 255 - *current_row;
  21. }
  22. }
  23. }
  24. namedWindow("像素读写演示", WINDOW_FREERATIO);
  25. imshow("像素读写演示", image);
  26. }

第四节课小结

本节主要介绍了通过两种遍历的方式访问图像的像素值,并且改变图像的像素值。

第五节课

图像像素的操作

对图像的各个像素点实现加减乘除的操作。介绍了常用的除爆函数saturate_cast,防止数值过界。

  1. void QuickDemo::operators_demo(Mat &image)
  2. {
  3. Mat dst = Mat::zeros(image.size(), image.type());
  4. Mat m = Mat::zeros(image.size(), image.type());
  5. dst = image - Scalar(50, 50, 50);
  6. m = Scalar(50, 50, 50);
  7. multiply(image,m,dst);//乘法操作 api
  8. imshow("乘法操作", dst);
  9. add(image, m, dst);//加法操作 api
  10. imshow("加法操作", dst);
  11. subtract(image, m, dst);//减法操作 api
  12. imshow("减法操作", dst);
  13. divide(image, m, dst);//除法操作 api
  14. namedWindow("加法操作", WINDOW_FREERATIO);
  15. imshow("加法操作", dst);
  16. //加法操作底层
  17. int dims = image.channels();
  18. int h = image.rows;
  19. int w = image.cols;
  20. for (int row = 0; row < h; row++)
  21. {
  22. for (int col = 0; col < w; col++)
  23. {
  24. Vec3b p1 = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值
  25. Vec3b p2 = m.at<Vec3b>(row, col);
  26. dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);//saturate_cast用来防爆,小于0就是0,大于255就是255
  27. dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
  28. dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);//对彩色图像读取它的像素值,并且对像素值进行改写。
  29. }
  30. }
  31. imshow("加法操作", dst);
  32. }

第五节课小结

介绍了四种不同的API实现,并且演示了一种加法的算法。

第六节课

滚动条演示操作-调整图片亮度

本节介绍怎么通过createTrackbar来设置一个进度条,实现图片的亮度调节。

  1. Mat src, dst, m;
  2. int lightness = 50;//定义初始的亮度为50
  3. static void on_track(int ,void*)
  4. {
  5. m = Scalar(lightness,lightness,lightness);//创建调整亮度的数值
  6. subtract(src, m, dst);//定义亮度变化为减
  7. imshow("亮度调整", dst);//显示调整亮度之后的图片
  8. }
  9. void QuickDemo::tracking_bar_demo(Mat &image)
  10. {
  11. namedWindow("亮度调整",WINDOW_AUTOSIZE);
  12. dst = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
  13. m = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
  14. src = image;//给src赋值
  15. int max_value = 100;//定义最大值为100
  16. createTrackbar("Value Bar:", "亮度调整", &lightness, max_value,on_track);//调用函数实现功能。
  17. on_track(50, 0); //首次触发显示,也可不写这行代码,不写的画窗口首次显示全黑色
  18. }

第七节课

滚动条演示操作-传递参数

  1. static void on_lightness(int b ,void* userdata)
  2. {
  3. Mat image = *((Mat*)userdata);
  4. Mat dst = Mat::zeros(image.size(), image.type());
  5. Mat m = Mat::zeros(image.size(), image.type());
  6. m = Scalar(b,b,b);
  7. addWeighted(image,1.0,m,0,b,dst);//融合两张图
  8. imshow("亮度&对比度调整", dst);
  9. }
  10. static void on_contrast(int b, void* userdata)
  11. {
  12. Mat image = *((Mat*)userdata);
  13. Mat dst = Mat::zeros(image.size(), image.type());
  14. Mat m = Mat::zeros(image.size(), image.type());
  15. double contrast = b / 100.0;
  16. addWeighted(image, contrast, m, 0.0, 0, dst);//融合两张图
  17. imshow("亮度&对比度调整", dst);
  18. }
  19. void QuickDemo::tracking_bar_demo(Mat &image)
  20. {
  21. namedWindow("亮度&对比度调整",WINDOW_AUTOSIZE);
  22. int lightness = 50;
  23. int max_value = 100;
  24. int contrast_value = 100;
  25. createTrackbar("Value Bar:", "亮度&对比度调整", &lightness, max_value, on_lightness,(void*)(&image));
  26. createTrackbar("Contrast Bar:", "亮度&对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));
  27. on_lightness(50, &image);
  28. }

第八节课

键盘响应操作

本节介绍通过键盘输入,终端能够读取响应的信息。

  1. void QuickDemo::key_demo(Mat &image)
  2. {
  3. Mat dst= Mat::zeros(image.size(), image.type());
  4. while (true)
  5. {
  6. char c = waitKey(100);//停顿100ms 做视频处理都是1
  7. if (c == 27) { //esc 退出应用程序
  8. break;
  9. }
  10. if (c == 49)//key#1
  11. {
  12. std::cout <<"you enter key #1" << std::endl;
  13. cvtColor(image, dst, COLOR_BGR2GRAY);
  14. }
  15. if (c == 50)//key#1
  16. {
  17. std::cout << "you enter key #2" << std::endl;
  18. cvtColor(image, dst, COLOR_BGR2HSV);
  19. }
  20. if (c == 51)//key#1
  21. {
  22. std::cout << "you enter key #3" << std::endl;
  23. dst = Scalar(50, 50, 50);
  24. add(image,dst,dst);
  25. }
  26. imshow("键盘响应",dst);
  27. std::cout << c << std::endl;
  28. }
  29. }

第八节课小结

通过键盘输入,在终端得到响应,输入不同的键值,得到不一样的结果。

第九节课

opencv自带颜色操作

  1. void QuickDemo::color_style_demo(Mat &image)
  2. {
  3. int colormap[] = {
  4. COLORMAP_AUTUMN ,
  5. COLORMAP_BONE,
  6. COLORMAP_CIVIDIS,
  7. COLORMAP_DEEPGREEN,
  8. COLORMAP_HOT,
  9. COLORMAP_HSV,
  10. COLORMAP_INFERNO,
  11. COLORMAP_JET,
  12. COLORMAP_MAGMA,
  13. COLORMAP_OCEAN,
  14. COLORMAP_PINK,
  15. COLORMAP_PARULA,
  16. COLORMAP_RAINBOW,
  17. COLORMAP_SPRING,
  18. COLORMAP_TWILIGHT,
  19. COLORMAP_TURBO,
  20. COLORMAP_TWILIGHT,
  21. COLORMAP_VIRIDIS,
  22. COLORMAP_TWILIGHT_SHIFTED,
  23. COLORMAP_WINTER
  24. };
  25. Mat dst;
  26. int index = 0;
  27. while (true)
  28. {
  29. char c = waitKey(100);//停顿100ms 做视频处理都是1
  30. if (c == 27) { //esc 退出应用程序
  31. break;
  32. }
  33. if (c == 49)//key#1 按下按键1时,保存图片到指定位置
  34. {
  35. std::cout << "you enter key #1" << std::endl;
  36. imwrite("D:/gray.jpg", dst);
  37. }
  38. applyColorMap(image, dst, colormap[index%19]);//循环展示19种图片
  39. index++;
  40. imshow("循环播放", dst);
  41. }
  42. }

第十节课

图像像素的逻辑操作

本节介绍如何对图像的像素进行操作,包括与、或、非、异或,矩形在图像中的绘制。

  1. void QuickDemo::bitwise_demo(Mat &image)
  2. {
  3. Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
  4. Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
  5. //在M1图像中的X=100,Y=100的坐标点 画一个长80,宽80的矩形
  6. //-1表示填充,>=0表示只画矩形边框 数值越大,矩形边框线越粗
  7. rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
  8. rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
  9. imshow("m1", m1);
  10. imshow("m2", m2);
  11. Mat dst;
  12. //像素与操作,就是把 M1的 Scalar(255, 255, 0) 和 M2的 Scalar(0, 255, 255)里的3个数进行与操作
  13. //bitwise_and(m1, m2, dst);
  14. bitwise_and(m1, m2, dst);//位操作与
  15. bitwise_or(m1, m2, dst);//位操作或
  16. bitwise_not(image, dst);//取反操作
  17. bitwise_xor(m1, m2, dst);//异或操作
  18. bitwise_xor(m1, m2, dst);
  19. imshow("像素位操作", dst);
  20. }

rectangle(m1,Rect(100,100,80,80),Scalar(255,255,0),-1,LINE_8,0);
这个函数:
参数1:是图片名称,
参数2:是矩形的起始&末尾位置,
参数3:Scalar表示将要绘制图像的颜色,
参数4:表示小于0表示填充,大于0表示绘制,
参数5:表示四邻域或者八邻域的绘制,
参数6:表示中心坐标或者半径坐标的小数位数。

第十一节课

通道的分离与合并

本节介绍如何把不同的通道给分离,归并,使得能显现出来不同的通道颜色。

  1. void QuickDemo::channels_demo(Mat &image)
  2. {
  3. std::vector<Mat>mv;
  4. split(image, mv); //分离 0,1,2三个通道分别代表BGR。
  5. //imshow("蓝色", mv[0]);
  6. //imshow("绿色", mv[1]);
  7. //imshow("红色", mv[2]);
  8. //关闭2个通道意味着开启一个通道。
  9. Mat dst;
  10. mv[0] = 0;
  11. mv[2] = 0;
  12. merge(mv, dst);
  13. imshow("蓝色", dst); //合并
  14. int from_to[] = { 0,2,1,1,2,0 };
  15. //把通道相互交换,第0->第2,第一->第一,第二->第0
  16. mixChannels(&image,1,&dst,1,from_to,3);//混合 3表示3个通道
  17. //参数1指针引用图像->参数2引用到dst
  18. imshow("通道混合", dst);
  19. }

第十一节课小结

M[0],M[1],M[2]分别代表BGR个不同的通道。要开启某个通道只需要关闭另外的一个通道即可。
第二个内容为通道的合并,将不同通道的像素值进行转换操作,使图片呈现出不同的效果。

第十二节课

图像色彩空间转换

本节内容实现任务是提取任务的轮廓,首先把RGB色彩空间的图片转换到HSV空间中,其次,提取图片的mask,通过使用inrangle提取hsv色彩空间的颜色。
HSV色彩空间的颜色
image.png

  1. void QuickDemo::inrange_demo(Mat &image)
  2. {
  3. Mat hsv;
  4. cvtColor(image, hsv, COLOR_BGR2HSV);
  5. Mat mask;
  6. inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);
  7. //35,43,46根据图片中绿色最低来确定最小值。
  8. //77,255,255 提取
  9. //参数1低范围,参数2高范围
  10. //将hsv中的由低到高的像素点提取出来并且存储到mask当中。
  11. imshow("mask",hsv);
  12. Mat redback = Mat::zeros(image.size(), image.type());
  13. redback = Scalar(40, 40, 200);
  14. bitwise_not(mask, mask); //取反
  15. imshow("mask", mask);
  16. image.copyTo(redback, mask);//把redback复制到mask,mask通过inRange得到。
  17. imshow("roi提取", hsv);
  18. }

第十三节课

图像像素值统计

分别定义双精度型变量 minv和maxv。指针变量minLoc,maxLoc;
因为这图片是多通道的,所以使用一个容器装取数值,并且用split分离图片到MV中
通过for循环操作,遍历图片信息,并且打印信息到终端。图像信息包括,方差,均值,大小。

  1. void QuickDemo::pixel_statistic_demo(Mat &image)
  2. {
  3. double minv, maxv;//定义最值
  4. Point minLoc, maxLoc;//定义最值地址
  5. std::vector<Mat>mv;//mv是一个Mat类型的容器 装在这个容器内
  6. split(image, mv);
  7. for (int i = 0; i < mv.size(); i++)
  8. {
  9. //分别打印各个通道的数值
  10. minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());//求出图像的最大值和最小值。
  11. std::cout <<"No.channels:"<<i<<"minvalue:" << minv << "maxvalue:" << maxv << std::endl;
  12. }
  13. Mat mean, stddev;
  14. meanStdDev(image, mean, stddev);//求出图像的均值和方差
  15. std::cout << "mean:" << mean << std::endl;
  16. std::cout << "stddev:" << stddev << std::endl;
  17. }

image.png
means , stddev,均值和方差都是3通道数据,要获取单通道数据需 means.at(0,0) 或 (1,0),(2,0)

第十四节课

图像几何形状的绘制

本节课介绍如何绘制椭圆,矩形,直线,圆等

  1. void QuickDemo::drawing_demo(Mat &image)
  2. {
  3. Rect rect;
  4. rect.x = 200;
  5. rect.y = 200;
  6. rect.width = 100;
  7. rect.height = 100;
  8. Mat bg = Mat::zeros(image.size(),image.type());
  9. rectangle(image, rect, Scalar(0, 0, 255), -1, 8, 0);
  10. //参数1为绘图的底图或者画布名称,
  11. //参数2位图片的起始,宽度,高度
  12. //参数3代表填充颜色。参数4大于0是线小于0是填充
  13. //参数5表示邻域填充,参数6默认值为0
  14. circle(bg, Point(350, 400), 15, Scalar(0, 0, 255), 2, LINE_AA, 0);
  15. //参数2位图片中心位置,参数3为半径为15的圆
  16. Mat dst;
  17. //addWeighted(image, 0.7, bg, 0.3, 0, dst);
  18. RotatedRect rtt;
  19. rtt.center = Point(200, 200);
  20. rtt.size = Size(100, 200);
  21. rtt.angle = 0.0;
  22. line(bg,Point(100,100),Point(350,400), Scalar(0, 0, 255), 8, LINE_AA, 0);
  23. //line_AA表示去掉锯齿
  24. ellipse(bg,rtt, Scalar(0, 0, 255), 2, 8);
  25. imshow("矩形的绘制",bg);
  26. }

第十五节课

随机数与随机颜色

本节主要介绍如何能产生一个随机数字和随机颜色,并且用线条的方式显示出来。

  1. void QuickDemo::random_drawing()
  2. {
  3. Mat canvas = Mat::zeros(Size(512,512), CV_8UC3);
  4. int w = canvas.cols;
  5. int h = canvas.rows;
  6. RNG rng(12345);
  7. while (true)
  8. {
  9. int c = waitKey(10);
  10. if (c == 27)
  11. {
  12. break;
  13. }
  14. int x1 = rng.uniform(0,canvas.cols);
  15. int y1 = rng.uniform(0, h);
  16. int x2 = rng.uniform(0, canvas.cols);
  17. int y2 = rng.uniform(0, h);
  18. int b = rng.uniform(0, 255);
  19. int g = rng.uniform(0, 255);
  20. int r = rng.uniform(0, 255);
  21. canvas = Scalar(0,0,0);
  22. line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b,g,r), 8, LINE_AA,0);
  23. //line_AA表示去掉锯齿
  24. imshow("随机绘制演示", canvas);
  25. }
  26. }

第十六节课

多边形填充与绘制

这节课介绍了2种多边形绘制的实现方式。

  1. void QuickDemo::polyline_drawing_demo(Mat &image)
  2. {
  3. Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
  4. Point p1(100, 100);
  5. Point p2(350, 100);
  6. Point p3(450, 280);
  7. Point p4(320, 450);
  8. Point p5(80, 400);
  9. std::vector<Point>pts;//将5个点装入一个容器内。
  10. pts.push_back(p1);//未初始化数组容量,只能用pushback操作
  11. //如果初始化,可以用数组下标操作。
  12. pts.push_back(p2);
  13. pts.push_back(p3);
  14. pts.push_back(p4);
  15. pts.push_back(p5);
  16. //fillPoly(canvas, pts, Scalar(122, 155, 255), 8, 0);//填充多边形
  17. //polylines(canvas, pts, true, Scalar(0, 0, 255), 2, 8, 0);//绘制多边形
  18. /*
  19. 参数1表示画布,参数2表示点集,参数3表示true,参数4颜色
  20. 参数5表示线宽,参数6表示渲染方式,参数7表示相对左上角(0,0)的位置
  21. */
  22. //单个API搞定图片的绘制填充
  23. std::vector<std::vector<Point>>contours;
  24. contours.push_back(pts);
  25. drawContours(canvas,contours,-1, Scalar(0, 0, 255),-1);
  26. //参数2表示容器名称,参数3为正表示多边形的绘制,为负表示多边形的填充
  27. imshow("多边形绘制", canvas);
  28. }

第十六节课小结

第一种方式,通过标记各个点,然后存储到容器中,之后对容器中的点进行操作。填充多边形调用fillPoly,绘制多边形调用polylines。
第二种方式,使用一个API接口绘制。通过一个容器中的存储的点组成的另一个容器。

第十七节课

鼠标操作与响应

  1. //参数1表示鼠标事件。
  2. Point sp(-1, -1);//鼠标的开始的位置
  3. Point ep(-1, -1);//鼠标的结束的位置
  4. Mat temp;
  5. static void on_draw(int event,int x,int y,int flags,void *userdata)
  6. {
  7. Mat image = *((Mat*)userdata);
  8. if(event == EVENT_LBUTTONDOWN)//如果鼠标的左键按下
  9. {
  10. sp.x = x;
  11. sp.y = y;
  12. std::cout << "start point" <<sp<< std::endl;
  13. }
  14. else if (event == EVENT_LBUTTONUP)
  15. {
  16. ep.x = x;
  17. ep.y = y;
  18. int dx = ep.x - sp.x;
  19. int dy = ep.y - sp.y;
  20. if (dx > 0 && dy > 0)
  21. {
  22. Rect box(sp.x, sp.y, dx, dy);
  23. imshow("ROI区域", image(box));
  24. rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
  25. imshow("鼠标绘制", image);
  26. sp.x = -1;
  27. sp.y = -1;//复位,为下一次做准备
  28. }
  29. }
  30. else if (event == EVENT_MOUSEMOVE)
  31. {
  32. if (sp.x > 0 && sp.y > 0)
  33. {
  34. ep.x = x;
  35. ep.y = y;
  36. int dx = ep.x - sp.x;
  37. int dy = ep.y - sp.y;
  38. if (dx > 0 && dy > 0)
  39. {
  40. Rect box(sp.x, sp.y, dx, dy);
  41. temp.copyTo(image);
  42. rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
  43. imshow("鼠标绘制", image);
  44. }
  45. }
  46. }
  47. }
  48. void QuickDemo::mouse_drawing_demo(Mat &image)
  49. {
  50. namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
  51. setMouseCallback("鼠标绘制", on_draw,(void*)(&image));
  52. //设置窗口的回调函数。参数1表示名称,参数2表示调用on_draw
  53. imshow("鼠标绘制", image);
  54. temp = image.clone();
  55. }