C++OpenCV图像处理(四)——图像的基本操作

        紧接着(一)(二)(三)中的程序我们继续利用C++以及opencv的基本方法对图像进行处理,头文件和源文件还是用的(一)中的,在此基础上进行扩充。

1.在图像上画圆和矩形以及两个图像相加

void QuickDemo::drawing_demo(Mat& image) {
	Rect rect;
	rect.x = 200;
	rect.y = 200;
	rect.width = 250;
	rect.height = 300;
	//生成一个模板,我们想在bg上面绘制
	Mat bg = Mat::zeros(image.size(), image.type());
	rectangle(bg, rect, Scalar(0, 0, 255),2, 8, 0);
	//在图像(350,400)的位置画一个半径为15的圆,颜色为蓝
	circle(bg, Point(350,400),15,Scalar(255,0,0),2,0);
	Mat dst;
	addWeighted(image, 0.7, bg, 0.3, 0, dst);
	imshow("绘制演示", dst);
}

imshow改为bg输出的就是模板上的圆和0矩形。有兴趣的可以自己更改。

addWeighted()函数是将两张相同大小,相同类型的图片融合的函数。他可以实现图片的特效,不多说了,直接上图。

API详解:void cvAddWeighted( const CvArr* src1, double alpha,const CvArr* src2, double beta,double gamma, CvArr* dst );
参数1:src1,第一个原数组.
参数2:alpha,第一个数组元素权重

参数3:src2第二个原数组
参数4:beta,第二个数组元素权重
参数5:gamma,图1与图2作和后添加的数值。不要太大,不然图片一片白。总和等于255以上就是纯白色了。

参数6:dst,输出图片

输出结果:

C++OpenCV图像处理(四)——图像的基本操作_第1张图片

图3是由1,2融合而成。

2.无限随机画线

只有当按键盘ESC才会停止。程序如下所示:

void QuickDemo::random_drawing_demo() {
	//随机绘制
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	int w = canvas.cols;
	int h = canvas.rows;
	RNG rng(12345);//OpenCV随机数产生器,12345是随机数种子,默认产生的是系统时间
	while(true){//无限循环一直画
		//键盘的响应操作,只有按键盘的ESC键退出才不会一直画,否则会一直画线
		int c = waitKey(10);
		if (c == 27) {
			break;
		}
		//线段有两个点,设定点的X,Y坐标
		int x1 = rng.uniform(0, w);//产生统一分布的a,b之间的数
		int y1 = rng.uniform(0, h);
		int x2 = rng.uniform(0, w);
		int y2 = rng.uniform(0, h);

		//颜色也随机产生
		int b = rng.uniform(0, 255);
		int g = rng.uniform(0, 255);
		int r = rng.uniform(0, 255);

		line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_4, 0);
		imshow("随机绘制演示:", canvas);
	}
}

C++OpenCV图像处理(四)——图像的基本操作_第2张图片

3.鼠标的基本操作

        鼠标的基本基本操作主要有如下:

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

1、OnMouse()回调函数: def OnMouse(event,x,y,flags,param): 
2、setMouseCallback()函数: cv2.setMouseCallback('image',OnMouse) 

Event:

        EVENT_MOUSEMOVE 0            #滑动
        EVENT_LBUTTONDOWN 1          #左键点击
        EVENT_RBUTTONDOWN 2          #右键点击
        EVENT_MBUTTONDOWN 3          #中键点击
        EVENT_LBUTTONUP 4            #左键放开
        EVENT_RBUTTONUP 5            #右键放开
        EVENT_MBUTTONUP 6            #中键放开
        EVENT_LBUTTONDBLCLK 7        #左键双击
        EVENT_RBUTTONDBLCLK 8        #右键双击
        EVENT_MBUTTONDBLCLK 9        #中键双击

   x,y,代表鼠标位于窗口的(x,y)坐标位置,flags,代表鼠标的拖拽事件,以及键盘鼠标联合事件。

flags:

EVENT_FLAG_LBUTTON 1       #左鍵拖曳  
EVENT_FLAG_RBUTTON 2       #右鍵拖曳  
EVENT_FLAG_MBUTTON 4       #中鍵拖曳  
EVENT_FLAG_CTRLKEY 8       #(8~15)按Ctrl不放事件  
EVENT_FLAG_SHIFTKEY 16     #(16~31)按Shift不放事件  
EVENT_FLAG_ALTKEY 32       #(32~39)按Alt不放事件  

       在使用之前我们需要定义一个OnMouse()回调函数:

def OnMouse(event,x,y,flags,param):
    global x0,y0,x1,y1
    if event==cv2.EVENT_LBUTTONDOWN:#左键单击,这里可以设置为其他的鼠标动作
        x0, y0 = x, y
        cv2.circle(img, (x, y), 20, (255, 245, 190), 2)

然后在主函数中调用,调用方法如下:

img = 255*np.ones((480,480,3),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',OnMouse)

while(1):
    cv2.imshow('image',img)
    if k==ord('q'):#直到按键盘上的'q'键才退出图像
        break
cv2.destroyAllWindows()

这样操作后,每次点一下屏幕,就会绘制一个固定半径的圆,至于怎么绘制不固定半径的圆

按鼠标左键在图像上画矩形的代码函数如下所示:(鼠标点击的方式绘制矩形)

Point sp(-1, -1); //鼠标开始的位置
Point ep(-1, -1);//鼠标结束的位置
static void on_draw(int event, int x, int y, int flag, void* userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {//左键点击
		sp.x = x;
		sp.y = y;
		std::cout << "start point" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {//左键放开
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
			Rect box(sp.x, sp.y, dx, dy);//可以用鼠标画矩形,但是我们希望在图像上画,所以需要添加如下代码
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("鼠标绘制显示:", image);//绘制了要急时更新
		}

	}
}
void QuickDemo::mouse_drawing_demo(Mat &image) {
	//鼠标的基本操作:使用鼠标画图
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
	imshow("鼠标绘制显示:", image);
}

鼠标移动的方式绘制矩形代码:

Point sp(-1, -1); //鼠标开始的位置
Point ep(-1, -1);//鼠标结束的位置
static void on_draw(int event, int x, int y, int flag, void* userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {//左键点击
		sp.x = x;
		sp.y = y;
		std::cout << "start point" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {//左键放开
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
			Rect box(sp.x, sp.y, dx, dy);//可以用鼠标画矩形,但是我们希望在图像上画,所以需要添加如下代码
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("鼠标绘制显示:", image);//绘制了要急时更新
			//一个矩形绘制好了以后要把鼠标的初始位置还是置为-1,为了下一次绘制做准备
			sp.x = -1;
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 10 && sp.y > 0) {//表示鼠标的左键要按下去
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);

			}
		}

	}
}
void QuickDemo::mouse_drawing_demo(Mat &image) {
	//鼠标的基本操作:使用鼠标画图
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
	imshow("鼠标绘制显示:", image);
}

效果如下所示:

                           

          我们可以看到断断续续的效果,这是由于他把所有的矩形都给绘制出来了,变成了这种叠加的效果。如果我们要擦除前面所画的矩形,只需保留最后的即可。可以如下所示:

                                      

     如果我还想提取box中的ROI区域,只需要在上面程序中增加一句就可以完成。

增加的代码如下所示:

 C++OpenCV图像处理(四)——图像的基本操作_第3张图片

                              

你可能感兴趣的:(c++opencv图像处理,计算机视觉-图像处理,opencv,计算机视觉,c++)