opencv-7-鼠标绘制自定义图形

opencvc++qt

开始之前

昨天写了具体的基本的图形绘制, 然后我们使用相应的函数接口进行调用, 便能够在图像上绘制出来相应的图形, 我们以图像绘制为例, 最终都会调用了 Line 函数, 最后都是基于一个 自定义迭代器 LineIterator的形成的路径, 通过设定起始点和目标点, 相当于计算出来的斜率值, 每次累加的之后判断下一个点的位置, 通过 重载累加器的 ++ 操作, 完成直线点指针的移动, 在相应的位置填入相应的颜色就可以得到 所要绘制的线, 这里是函数的调用图, 可放大查看细节部分


Line 函数调用图

这里不再深入探讨, 相应的可以去研究具体的实现, 很漂亮的源码, 写的很好

我们这个章节 看一个比较高级点的操作, 操作起来比较复杂, 先不去深究其中的原理, 我们先跑起来, 然后再研究

正文

主要是处理鼠标的操作就好, 然后使用绘制图像就好, 可以参考博文《OpenCV:鼠标操作(绘制直线、矩形、圆)简单示例》

和博文OpenCV鼠标画图例程,鼠标绘制矩形,

鼠标绘制图像

我们先梳理一下逻辑, 我们使用两张图片作为轮换, 原始图和临时图, 每次绘制在临时图上, 然后完成之后存入原始图上

  • 初始原始图像, 绘图标志 flg false
  • 鼠标按下, 确定起始点 start_p 标志开始绘图
  • 鼠标移动, 移动目标点 end_p, 绘制到临时图像上
  • 鼠标抬起, 确定最后的点, 然后将图替换原始图, 同时 绘图标志结束flg = false
  • 循环绘制图像, 绘图中的时候 显示临时图像, 绘图之后 显示原始图像,

逻辑理清除之后,我们就想要处理一下细节部分了, 我们在之前的博文中介绍了显示图像的方式, imshow即可显示, 然后我们

发现问题在于程序的鼠标是件监听了, 这里其实比较深入了, 但是呢, 我们不深入去研究, 只去看实现的过程吧,

cv::setMouseCallback(windows_name, on_MouseHandle, 0);, 我们第一个 windows_name 是我们打开的窗口名称, 用于显示图像, 也能通过名称进行句柄操作, 第二个参数就是我们的鼠标处理函数了, on_MouseHandle(int event, int x, int y, int flags, void *param), 这里的函数名称可以自定义, 但是参数类型与个数必须一致, 然后我们就可以通过预定义的事件宏进行确定当前鼠标操作的动作了, 这里 比如cv::EVENT_MOUSEMOVE 宏就是 鼠标移动事件, cv::EVENT_LBUTTONDOWN,和cv::EVENT_LBUTTONUP 分别对应鼠标按下和鼠标抬起的操作, 命名写的很清楚

编码实现

我们在逻辑理清除 之后, 写起来就很简单了, 可以的大傲下面的代码, 注释也比较清除, 能够一看就懂

#include "mainwindow.h"
#include <QApplication>
// 引入 opencv 函数头文件
#include <opencv2/opencv.hpp> // 记录鼠标位置点, 以及 正在绘图标志位 flg
cv::Point start_p(-1, -1), end_p(-1, -1);
bool flg_drawing = false; // 使用原始图像与临时图像 存储
cv::Mat src_img, temp_img; //鼠标回调函数 // 记录窗口的x y 位置
void on_MouseHandle(int event, int x, int y, int flags, void *param)
{
switch (event)
{
case cv::EVENT_LBUTTONDOWN:
{
start_p = cv::Point(x, y); // 确定起始点
temp_img = src_img.clone(); // 复制原始图, 进行绘图操作
flg_drawing = true;
}break;
case cv::EVENT_MOUSEMOVE:
{
if (flg_drawing)
end_p = cv::Point(x, y); // 如果在绘制, 则更新移动后的目标点
}break;
case cv::EVENT_LBUTTONUP:
{
end_p = cv::Point(x, y); // 确定最终点
src_img = temp_img.clone(); // 将图像更新成为原始图 存储下来
flg_drawing = false;
}break;
}
} // 返回两点之间的距离 直线距离 平方和的开方值
float distance(const cv::Point &p1, const cv::Point &p2)
{
return cv::sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
} int main(int argc, char *argv[])
{
//QApplication a(argc, argv);
//MainWindow w;
//w.show();
// 设置 要显示的图像路径
std::string img_lena = "./TestImages/lena.png";
src_img = cv::imread(img_lena); std::string windows_name = "show";
cv::namedWindow(windows_name,cv::WINDOW_AUTOSIZE); // 设置窗口 鼠标操作 监听 函数为 on_MouseHandle
cv::setMouseCallback(windows_name, on_MouseHandle, 0); while (true)
{
// 根据当前点 绘制
if (flg_drawing)
{
temp_img = src_img.clone(); cv::line(temp_img, start_p, end_p, cv::Scalar(0, 255, 0));
cv::rectangle(temp_img, cv::Rect(start_p, end_p), cv::Scalar(255, 0, 0));
cv::circle(temp_img, start_p, distance(start_p,end_p), cv::Scalar(0, 0, 255));
cv::imshow(windows_name, temp_img);
}
else
{
cv::imshow(windows_name, src_img);
}
// 设置 按 esc 退出循环
if (cv::waitKey(30) == 27)
break;
}
return 0;
// return a.exec();
}

运行结果

然后就到了我们结果的时候了, 运行之后, 鼠标左键点击开始, 拖动实时绘制, 抬起结束绘制, 然后 我们绘制了 直线, 矩形, 和圆, 同时进行了绘制,


鼠标绘制图像

ps: 这里录制 gif 使用的是 ScreenToGif 特别好用

我们实现的比较简单, 可以去看我提到的两篇博文, 以及这一篇鼠标作为画笔 翻译的文档,

他们实现的比较复杂, 不仅实现了绘制, 还能够选择绘制什么, 也提供了 随机颜色的方法, cv::RNG

可以参考OpenCV中随机颜色, 随机颜色的解释, 听简单的, 初始化随机, 自动生成随机颜色就行了,

// 随机颜色绘制
cv::line(temp_img, start_p, end_p, cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
cv::rectangle(temp_img, cv::Rect(start_p, end_p), cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
cv::circle(temp_img, start_p, distance(start_p,end_p), cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));

自定义颜色绘制

其他


opencv-7-鼠标绘制自定义图形的更多相关文章

  1. [Xcode 实际操作]九、实用进阶-(19)重写父类的绘图方法,使用图形上下文绘制自定义图形

    目录:[Swift]Xcode实际操作 本文将演示如何使用图形上下文,绘制自定义图形. 使用快捷键[Command]+[N]创建一个新的类文件. (在项目文件夹[DemoApp]上点击鼠标右键[New ...

  2. 使用Ogre::ManualObject 绘制自定义图形

    在ogre中如果需要进行自定义图形绘制可以使用ManualObject.例如绘制一个三角形的用法如下: SceneNode* pGridNode = m_pBaseNode->createChi ...

  3. 软件项目技术点(7)——在canvas上绘制自定义图形

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 图形种类 目前我们软件可以绘制出来的形状有如下这几种,作为开发者我们一直想支持用户可以拖拽的类似word里面图形库,但目前还没有找到比 ...

  4. C# 绘制PDF图形——基本图形、自定义图形、色彩透明度

    引言 在PDF中我们可以通过C#程序代码来添加非常丰富的元素来呈现我们想要表达的内容,如绘制表格.文字,添加图形.图像等等.在本篇文章中,我将介绍如何在PDF中绘制图形,并设置图形属性的操作. 文章中 ...

  5. 在OpenCV中利用鼠标绘制矩形和截取图像的矩形区域

    这是两个相关的程序,前者是后者的基础.实际上前一个程序也是在前面博文的基础上做的修改,请参考<在OpenCV中利用鼠标绘制直线> .下面贴出代码. 程序之一,在OpenCV中利用鼠标绘制矩 ...

  6. 自定义View—绘制基本图形

    一.Canvas能够绘制哪些图形 二.

  7. opencv2 使用鼠标绘制矩形并截取和保存矩形区域图像

    前言 好长时间没写博文了,今天偷偷懒写篇关于opencv2中鼠标响应操作的文章. 鼠标操作属于用户接口设计,以前一直使用Qt来做,但是如果只需要简单的鼠标,键盘操作,直接调用opencv库的函数也未尝 ...

  8. 关于MFC与OpenGL结合绘图区域用鼠标来控制图形的移动的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11773171.html 之前开发的导入多个模型,旋转,分别移动什么什么的,都是在纯OpenGL ...

  9. 绘制基本图形和线型(StrokeStyle)的设置详解

    绘制基本图形和线型(StrokeStyle)的设置详解 目前,在博客园上,相对写得比较好的两个关于Direct2D的教程系列,分别是万一的Direct2D系列和zdd的Direct2D系列.有兴趣的网 ...

随机推荐

  1. 1519: 【USACO】超级书架

    1519: [USACO]超级书架 时间限制: 1 Sec 内存限制: 64 MB 提交: 1735 解决: 891 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 Farmer Jo ...

  2. Spring之Bean的管理方式(Content,Beans)

    Spring的bean管理(注释) 注解 代码里特殊的标记,使用注解也可以直接完成相关功能 注解写法:@注解名称(属性名=属性值) 使用在类,方法,属性上面 Spring注解开发准备 导入jar包 ( ...

  3. day 1 硬件组成概念及介绍笔记

    一.服务器的种类: 硬件服务器: 1.机架式服务器 2.刀片式服务器 3.塔式服务器 虚拟服务器: 阿里云 aws 腾讯云 二.详细硬件组成: 1.电源  ----心脏(供电) 冗余特性    ups ...

  4. PTA数据结构与算法题目集(中文) 7-38寻找大富翁 (25 分)

    PTA数据结构与算法题目集(中文)  7-38寻找大富翁 (25 分) 7-38 寻找大富翁 (25 分)   胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人.假 ...

  5. Halo博客的搭建

    今日主题:搭建一个私人博客 好多朋友和我说,能不能弄一个简单的私人博客啊,我说行吧,今天给你们一份福利啦! 搭建一个私人博客,就可以在自己的电脑上写博客了 Halo Halo 是一款现代化的个人独立博 ...

  6. P1198 [JSOI2008]最大数(线段树基础)

    P1198 [JSOI2008]最大数 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制: ...

  7. 数据库学习 day1 认识数据库

    从SQL的角度而言,数据库是一个以某种有组织的方式储存的数据集合. 我们可以把它比作一个“文件柜”,这个“文件柜”是一个存放数据的物理位置,不管数据是什么,也不管数据是如何组织的. 下面介绍几个术语 ...

  8. uni-app在线引入阿里字体图标库

    第一步 在app.vue中引入阿里字体图标库 第二步 在任意页面使用就可以了 <view class="item" v-for="(value,index) in ...

  9. 关于Cookie的相关知识点以及使用方法

    首先介绍cookie的一些方法 response.addCookie(Cookie cookie)是将一个cookie对象传入客户端. Cookie cookie=new Cookie(String ...

  10. go 内置函数

    一.什么是内置函数? 二.内置函数有哪些? 名称 说明 close 用于管道通信 len.cap len 用于返回某个类型的长度或数量(字符串.数组.切片.map 和管道):cap 是容量的意思,用于 ...