在OpenCV中绘制几何形状
void Demo::drawing_demo(Mat &image) {Mat bg = Mat::zeros(image.size(), image.type()), dst;//矩形Rect rect;//可以用Rect定义矩形rect.x = 200;//矩形左上角的坐标rect.y = 200;//矩形左上角的坐标//注:坐标系是以左上角为原点,右下角为正方向rect.width = 80;rect.height = 80;rectangle(bg, rect, Scalar(0, 255, 0), -1, 8, 0);//圆circle(bg, Point(120, 120), 60, Scalar(255, 0, 0), 1, 8, 0);//背景,圆心,半径,颜色,线宽//线line(bg, Point(0, 0), Point(200, 200), Scalar(0, 0, 255), 2, 8, 0);//背景,起始点,结束点,颜色,线宽//椭圆//和矩形一样,可以先定义RotatedRect rrt;rrt.size = Size(100, 200);//长轴短轴rrt.center = Point(120, 120);//中心坐标rrt.angle = 45;//旋转角度ellipse(bg, rrt, Scalar(255, 255, 0), 1, 8);//addWeighted(bg, 0.6, image, 0.4, 0, dst);imshow("绘制演示",dst);
}
需要注意的是,在绘制矩形椭圆这些参数较多的几何图形时,我们可以先创建一个图形,防止括号内参数过多,影响可读性,但是直接绘制也是可以的,如矩形的绘制也可以采用这种方式:
rectangle(bg, Rect(200, 200, 60, 60), Scalar(0,255,255), -1, 8, 0);
当然所有图形都可以采用先定义后绘制的方式。
最后一个参数是缩放参数shift,缩放后的图形d和原图D的关系为:d = D/2shift。
随机数产生器RNG
在OpenCV中,可以用RNG来构造随机数
RNG rng;
int a;
a = rng.gaussian(10);//返回一个均值为0,标准差为10的随机数
a = rng.next();//返回下一个64位随机整数
a = rng.uniform(1,10);//返回范围内均匀分布的整数随机数
通过RNG产生随机数,可以实现许多功能,比如可以实现随机形状的绘制:
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);RNG rng;while (true) {int c = waitKey(10);if (c == 27)break;int x1 = rng.uniform(0, canvas.cols), x2 = rng.uniform(0, canvas.cols);int y1 = rng.uniform(0, canvas.rows), y2 = rng.uniform(0, canvas.rows);Scalar sca = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));line(canvas, Point(x1, y1), Point(x2, y2), sca, 2, 8, 0);imshow("随机绘制", canvas);}
会以10ms为时间间隔不断绘制随机长度随机颜色的线段line;
绘制多边形
多边形的绘制和其他几何图形大同小异,需要注意的有两点
1.需要定义多边形的端点集合
2.线宽必须大于0,不能为-1,因此多边形的填充需要用到专门的填充函数fillPoly();
点集的定义:
Point p1(100, 100);
Point p2(200, 150);
Point p3(300, 200);
Point p4(400, 250);
Point p5(50, 50);
vector<Point> pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
空心和填充多边形的绘制:
polylines(canvas, pts, true, Scalar(255, 0, 0), 1, 8, 0);fillPoly(canvas, pts, Scalar(255, 0, 0), 8, 0);
同时绘制多个多边形
vector<vector<Point>> con;//端点集的集合
con.push_back(pts);
drawContours(canvas, con, -1, Scalar(0, 0, 255), 1, 8);
//背景,端点集的集合,绘制第几个多边形(填-1则绘制全部),颜色,线宽
相应鼠标事件
OpenCV中的鼠标相应事件有如下:
EVENT_MOUSEMOVE = 0, //!< indicates that the mouse pointer has moved over the window.EVENT_LBUTTONDOWN = 1, //!< indicates that the left mouse button is pressed.EVENT_RBUTTONDOWN = 2, //!< indicates that the right mouse button is pressed.EVENT_MBUTTONDOWN = 3, //!< indicates that the middle mouse button is pressed.EVENT_LBUTTONUP = 4, //!< indicates that left mouse button is released.EVENT_RBUTTONUP = 5, //!< indicates that right mouse button is released.EVENT_MBUTTONUP = 6, //!< indicates that middle mouse button is released.EVENT_LBUTTONDBLCLK = 7, //!< indicates that left mouse button is double clicked.EVENT_RBUTTONDBLCLK = 8, //!< indicates that right mouse button is double clicked.EVENT_MBUTTONDBLCLK = 9, //!< indicates that middle mouse button is double clicked.EVENT_MOUSEWHEEL = 10,//!< positive and negative values mean forward and backward scrolling, respectively.EVENT_MOUSEHWHEEL = 11 //!< positive and negative values mean right and left scrolling, respectively.
鼠标的相响应操作是一个回调函数的过程
在回调函数中定义鼠标事件以及对应的响应操作:
static void on_draw(int event, int x, int y, int flags, void *userdata)
//回调函数
{Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {sp.x = x;sp.y = y;cout << sp << endl;}else if (event == EVENT_LBUTTONUP) {ep.x = x;ep.y = y;cout << ep << endl;int dx = ep.x - sp.x;int dy = ep.y - sp.y;if(dx>0&&dy>0)rectangle(image, Rect(sp.x, sp.y, dx, dy), Scalar(0, 255, 255), -1, 8, 0);imshow("鼠标响应", image);}}
然后在函数中传递参数,调用回调函数:
void Demo::mouse_drawing_demo(Mat &image) {namedWindow("鼠标响应", WINDOW_AUTOSIZE);setMouseCallback("鼠标响应",on_draw,(void*)(&image));//事件响应窗口,调用鼠标事件
}
需要注意的是,回调函数需要一个void*类型的参数,而如果想要将Mat对象传递进去,就需要一个数据类型的转换,在传递进去以后,再将这个参数转换回Mat类型,具体操作如下:
void* a = (void*)(&image);(void*)(&image);
Mat image = *((Mat*)userdata);
这样就完成了一个运用鼠标响应事件完成的矩形绘制效果。
在这个基础上,可以用一个小技巧,独立显示矩形选中部分:
imshow("ROI区域", image(Rect(sp.x, sp.y, dx, dy)));