OpenCV - C++实战(02) — 图片点击与绘图

目录

第2章  图片点击与绘图

2.1 图像点击

2.1.1 在图上点击

2.2 在图像上绘图

2.2.1 在图像上绘制基本图像

2.2.2 在图像上写入文本

2.2.3 在图像上插入logo

2.3 完整代码


 Github代码地址:https://github.com/Qinong/OpenCV.git

第2章  图片点击与绘图

2.1 图像点击

2.1.1 在图上点击

        highgui 模块中有使程序对鼠标或键盘事件做出响应、在图像上绘制形状或写人文本的函数。
可以让鼠标在置于图像窗口上时运行特定的指令。要实现这个功能,需定义一个合适的回调函数。回调函数不会被显式地调用,但是会在响应特定事件(这里是指有关鼠标与图像窗口交互的事件)的时候被程序调用。为了能被程序识别,回调函数需要具有特定的签名,并且必须注册。对于鼠标事件处理两数,回调函数必须具有这种签名:

void onMouse( int event, int x, int y, int flags, void* param)

                event:表示触发回调的数的鼠标事件的类型。

                x,y:两个参数是事件发生时鼠标的位置,用像素坐标表示。

                flags:表示事件发生时按下了鼠标的哪个键。

                param:指向任意对象的指针,作为附加的参数发送给函数。

        你可用下面的方法 在程序中注册回调函数:

void cv::setMouseCallback(const String &winname,cv::MouseCallback onMouse,void *userdata=(void*)0)
  • winname:窗口名称
  • onMouse:鼠标事件的回调函数
  • userdata:传递给回调函数的可选参数
  • 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:鼠标所在图像的坐标
  • flags:代表拖拽事件

                EVENT_FLAG_LBUTTON  1 按住左键拖拽

                EVENT_FLAG_RBUTTON 2  按住右键拖拽

                EVENT_FLAG_MBUTTON 4  按住中键拖拽

                EVENT_FLAG_CTRLKEY 8  按住ctrl键拖拽

                EVENT_FLAG_SHIFTKEY  16 按住shift键拖拽

                EVENT_FLAG_ALTKEY 32  按住alt键拖拽

  • param: 自己定义的onMouse事件的ID

 (1)显示鼠标点击点的像素值

void onMouse( int event, int x, int y, int flags, void* param)	{
	cv::Mat *im= reinterpret_cast<cv::Mat*>(param);
    switch (event) {    // 调度事件
		case cv::EVENT_LBUTTONDOWN: // 鼠标左键按下的事件
			// 显示鼠标点按下的像素值(x,y)
			std::cout << "at (" << x << "," << y << ") value is: " 
				      << static_cast<int>(im->at<uchar>(cv::Point(x,y))) << std::endl;
			break;
	}
}

2.2 在图像上绘图

2.2.1 在图像上绘制基本图像

        OpenCV 提供了几个用于在图像上绘制形状的函数,基本的形状绘制函数有circle、ellipse、line 和 rectangle。

void cv::circle (InputOutputArray img,     // 图像
                 Point center,         // 圆心点
                 int radius,           // 半径
                 const Scalar &color,    // 颜色
                 int thickness=1,       // 线条粗细
                 int lineType=LINE_8,     // 线条类型
                 int shift=0)            // 中心坐标和半径值中的小数位数

(1)在图上画圆

cv::Mat image2 = image1.clone();
cv::circle(image2,              // 目标图像
		   cv::Point(1500,2000), // 中心点坐标
		   500,                 // 半径
		   0,                  // 颜色
		   50);                 // 厚度
cv::namedWindow("Image2",0);
cv::imshow("Image2", image2); 
cv::waitKey(0); 

2.2.2 在图像上写入文本

        在OpenCV 的方法和函数中,你也可以在图像上写人文本,方法如下所示: 

void cv::putText(cv::Mat& img, // 待绘制的图像
	             const string& text, // 待绘制的文字
	             cv::Point origin, // 文本框的左下角
	             int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
		         double fontScale, // 尺寸因子,值越大文字越大
		         cv::Scalar color, // 线条的颜色(RGB)
		         int thickness = 1, // 线条宽度
		         int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
		         bool bottomLeftOrigin = false // 指定的点为插入文字的位置(true=文字的左上角位置,false=文字的左下角位置)
                );

 (1)在图像上写入文本

cv::Mat image3 = image1.clone();
cv::putText(image3,                   // destination image
		    "This is a Audi.",        // text
		    cv::Point(1000,2500),       // text position
		    cv::FONT_HERSHEY_PLAIN,  // font type
			20.0,                     // font scale
			255,                     // text color (here white)
			20);                      // text thickness
cv::namedWindow("Image3",0);
cv::imshow("Image3", image3); 
cv::waitKey(0); 

        假设我们要把一 个小图像复制到一个大图像上。例如要把下面的logo插人到测试图像中。
为了实现这个功能,可以定义一个兴趣区域 (Region Of Interest, ROI),在此处进行复制操作,这个ROI的位置将决定标志的插人位置。

         第一步是定义 ROI。定义后,就可以把 ROI当作一个普通的cv::Mat 实例进行操作。接着,可以用下面的方法插人标志:

// cv::Rect矩形类参数设置
cv::Rect(int x, int y,         // 左上角坐标
         int width, int height);    // 矩形的宽和高 

        cv:Range类型用于指元连续的整数序列,包合两个元素start和end,通过cv:Range (int start, int end)进行初始化。生成结果包括起始值,但不含终值。

(1)方法1:图片插入logo

// 方法1:图片插入logo
cv::Mat image4 = image1.clone(); 
cv::Mat logo=  cv::imread("Audi_logo.jpeg"); 
// 在图像的右下角定义一个ROI
cv::Mat imageROI(image4, 
		         cv::Rect(image4.cols-logo.cols, // ROI坐标
                          image4.rows-logo.rows,
		                  logo.cols,logo.rows));// ROI大小
// 插入logo
logo.copyTo(imageROI);
cv::namedWindow("Image4",0); 
cv::imshow("Image4", image4); 
cv::waitKey(0);

(2)方法2:图片插入logo

// 方法2:图片插入logo
cv::Mat image5 = image1.clone(); 
cv::Mat logo1=  cv::imread("Audi_logo.jpeg",cv::IMREAD_GRAYSCALE); 
// ROI用cv::Range描述
imageROI= image5(cv::Range(image5.rows-logo.rows,image5.rows), 
                 cv::Range(image5.cols-logo.cols,image5.cols));

// 用logo作为掩码(必须是灰度图像)
cv::Mat mask(logo1);
// 插入logo,只负责掩码不为0的位置
logo.copyTo(imageROI,mask);
cv::namedWindow("Image5",0);
cv::imshow("Image5", image5); 
cv::waitKey(0);

        运行上述代码后,你将得到下面的图像。

 

2.3 完整代码

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>


void onMouse( int event, int x, int y, int flags, void* param)	{
	cv::Mat *im= reinterpret_cast<cv::Mat*>(param);
    switch (event) {    // 调度事件
		case cv::EVENT_LBUTTONDOWN: // 鼠标左键按下的事件
			// 显示鼠标点按下的像素值(x,y)
			std::cout << "at (" << x << "," << y << ") value is: " 
				      << static_cast<int>(im->at<uchar>(cv::Point(x,y))) << std::endl;
			break;
	}
}

int main() {
	// code1
    // 显示鼠标点击点的像素值
    cv::Mat image1 = cv::imread("Audi_RS7.jpg");
    if (image1.empty()) { 
		std::cout << "Error reading image..." << std::endl;
		return 0;
	}
    cv::namedWindow("Image1",0); 
	cv::imshow("Image1", image1); // show the image
	cv::waitKey(0); // 0 to indefinitely wait for a key pressed
	cv::setMouseCallback("Image1", onMouse, reinterpret_cast<void*>(&image1));
    
    // code2
    // 在图上画圆
    cv::Mat image2 = image1.clone();
 	cv::circle(image2,              // 目标图像
		       cv::Point(1500,2000), // 中心点坐标
			   500,                 // 半径
			   0,                  // 颜色
			   50);                 // 厚度
    cv::namedWindow("Image2",0);
	cv::imshow("Image2", image2); 
	cv::waitKey(0); 
	 
    // code3
    // 在图上写入文本
    cv::Mat image3 = image1.clone();
	cv::putText(image3,                   // destination image
		        "This is a Audi.",        // text
				cv::Point(1000,2500),       // text position
				cv::FONT_HERSHEY_PLAIN,  // font type
				20.0,                     // font scale
				255,                     // text color (here white)
				20);                      // text thickness
    cv::namedWindow("Image3",0);
	cv::imshow("Image3", image3); 
	cv::waitKey(0);   

    // code4
    // 方法1:图片插入logo
	cv::Mat image4 = image1.clone(); 
	cv::Mat logo=  cv::imread("Audi_logo.jpeg"); 
	// 在图像的右下角定义一个ROI
	cv::Mat imageROI(image4, 
		          cv::Rect(image4.cols-logo.cols, // ROI坐标
                           image4.rows-logo.rows,
		                   logo.cols,logo.rows));// ROI大小
	// 插入logo
	logo.copyTo(imageROI);
	cv::namedWindow("Image4",0); 
	cv::imshow("Image4", image4); 
	cv::waitKey(0);


    // code5
    // 方法2:图片插入logo
	cv::Mat image5 = image1.clone(); 
    cv::Mat logo1=  cv::imread("Audi_logo.jpeg",cv::IMREAD_GRAYSCALE); 
	// ROI用cv::Range描述
    imageROI= image5(cv::Range(image5.rows-logo.rows,image5.rows), 
                    cv::Range(image5.cols-logo.cols,image5.cols));

    // 用logo作为掩码(必须是灰度图像)
    cv::Mat mask(logo1);
	// 插入logo,只负责掩码不为0的位置
	logo.copyTo(imageROI,mask);
    cv::namedWindow("Image5",0);
	cv::imshow("Image5", image5); 
	cv::waitKey(0);
    
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值