使用 python 在 open cv 中使用鼠标事件绘制填充多边形

2024-03-04

我试图在通过单击鼠标事件获得的坐标之间绘制一个多边形。

第一次单击应定义多边形的起点。每次额外的单击都应根据前一次单击绘制一条线段。当整个单击点绘制多边形时,多边形内部应被填充。

有人可以建议如何在我单击图像的点之间绘制多边形吗?我正在考虑cv2.polylines功能,但我不知道如何将其与SetMouseCallback功能。


为了使用户界面更加直观(因为用户很难精确地单击与起点相同的位置),让我们使用以下操作:

  • 鼠标左键单击在单击位置的多边形上添加一个点
  • 单击鼠标右键完成数据输入,并使程序显示最终填充的多边形

我们需要几个变量来跟踪我们的进度:

  • 定义多边形的点的列表。每个点都是一个元组(x, y)
  • 一个布尔标志,表示数据输入何时完成
  • 作为奖励,鼠标光标的最后一个已知位置,因此我们可以为当前输入的段(光标后面的一行)设置动画。

当发生适当的鼠标事件时,我们将使用鼠标回调定期更新这些变量:

  • EVENT_MOUSEMOVE-- 鼠标移动了,更新当前位置
  • EVENT_LBUTTONDOWN-- 用户按下鼠标左键,将当前位置添加到点列表中
  • EVENT_RBUTTONDOWN-- 用户按下鼠标右键,将数据输入标记为完成

最后,我们将有一个实现显示循环的函数。

该函数将首先创建一个命名窗口,绘制一个空白画布,并设置鼠标回调。然后它会通过以下方式反复不断更新屏幕:

  • 创建一个新的画布图像(在其上绘制)
  • 输入点后,使用以下命令绘制连接的线段cv2.polyline
  • 使用不同的颜色绘制从最后输入的点指向当前位置的当前线段cv2.line.
  • 显示新图像。
  • 等待一段时间,同时发送窗口消息。

数据输入过程完成后,该函数将绘制最终的填充多边形和干净的画布图像,显示它,并在用户按下某个键时返回最终图像。


代码示例

import numpy as np
import cv2

# ============================================================================

CANVAS_SIZE = (600,800)

FINAL_LINE_COLOR = (255, 255, 255)
WORKING_LINE_COLOR = (127, 127, 127)

# ============================================================================

class PolygonDrawer(object):
    def __init__(self, window_name):
        self.window_name = window_name # Name for our window

        self.done = False # Flag signalling we're done
        self.current = (0, 0) # Current position, so we can draw the line-in-progress
        self.points = [] # List of points defining our polygon


    def on_mouse(self, event, x, y, buttons, user_param):
        # Mouse callback that gets called for every mouse event (i.e. moving, clicking, etc.)

        if self.done: # Nothing more to do
            return

        if event == cv2.EVENT_MOUSEMOVE:
            # We want to be able to draw the line-in-progress, so update current mouse position
            self.current = (x, y)
        elif event == cv2.EVENT_LBUTTONDOWN:
            # Left click means adding a point at current position to the list of points
            print("Adding point #%d with position(%d,%d)" % (len(self.points), x, y))
            self.points.append((x, y))
        elif event == cv2.EVENT_RBUTTONDOWN:
            # Right click means we're done
            print("Completing polygon with %d points." % len(self.points))
            self.done = True


    def run(self):
        # Let's create our working window and set a mouse callback to handle events
        cv2.namedWindow(self.window_name, flags=cv2.CV_WINDOW_AUTOSIZE)
        cv2.imshow(self.window_name, np.zeros(CANVAS_SIZE, np.uint8))
        cv2.waitKey(1)
        cv2.cv.SetMouseCallback(self.window_name, self.on_mouse)

        while(not self.done):
            # This is our drawing loop, we just continuously draw new images
            # and show them in the named window
            canvas = np.zeros(CANVAS_SIZE, np.uint8)
            if (len(self.points) > 0):
                # Draw all the current polygon segments
                cv2.polylines(canvas, np.array([self.points]), False, FINAL_LINE_COLOR, 1)
                # And  also show what the current segment would look like
                cv2.line(canvas, self.points[-1], self.current, WORKING_LINE_COLOR)
            # Update the window
            cv2.imshow(self.window_name, canvas)
            # And wait 50ms before next iteration (this will pump window messages meanwhile)
            if cv2.waitKey(50) == 27: # ESC hit
                self.done = True

        # User finised entering the polygon points, so let's make the final drawing
        canvas = np.zeros(CANVAS_SIZE, np.uint8)
        # of a filled polygon
        if (len(self.points) > 0):
            cv2.fillPoly(canvas, np.array([self.points]), FINAL_LINE_COLOR)
        # And show it
        cv2.imshow(self.window_name, canvas)
        # Waiting for the user to press any key
        cv2.waitKey()

        cv2.destroyWindow(self.window_name)
        return canvas

# ============================================================================

if __name__ == "__main__":
    pd = PolygonDrawer("Polygon")
    image = pd.run()
    cv2.imwrite("polygon.png", image)
    print("Polygon = %s" % pd.points)

截图

绘图过程中,我们输入了 5 个点,当前线段显示为一条指向鼠标当前位置的深色线:

绘图完成,程序显示整个多边形已填充:


最终图像

控制台输出

Adding point #0 with position(257,144)
Adding point #1 with position(657,263)
Adding point #2 with position(519,478)
Adding point #3 with position(283,383)
Adding point #4 with position(399,126)
Adding point #5 with position(142,286)
Adding point #6 with position(165,38)
Completing polygon with 7 points.
Polygon = [(257, 144), (657, 263), (519, 478), (283, 383), (399, 126), (142, 286), (165, 38)]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 python 在 open cv 中使用鼠标事件绘制填充多边形 的相关文章

  • 导入错误:无法导入名称“FFProbe”

    我无法获取ffprobe包 https github com simonh10 ffprobe在 Python 3 6 中工作 我使用 pip 安装它 但是当我输入import ffprobe it says Traceback most
  • 在函数内的 for 循环上使用 tqdm 来检查进度

    我正在使用 for 循环迭代目录树内的一大组文件 这样做时 我想通过控制台中的进度条来监视进度 因此 我决定使用 tqdm 来实现此目的 目前 我的代码如下所示 for dirPath subdirList fileList in tqdm
  • 如何替换Python字符串中的正确字母

    任务是 您的任务是纠正数字化文本中的错误 您只需处理以下错误 S 被误解为 5 O 被误解为 0 I 被误解为 1 我的代码 def correct string for i in string if 5 in string string
  • 如何同时运行多个功能[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有以下代码 my func1 my func2 my func3 my func4 my func5 是否可以同时计算函数的数据 而
  • 使用管理员权限打开cmd(Windows 10)

    我有自己的 python 脚本来管理我的计算机上的 IP 地址 它主要在命令行 Windows 10 中执行netsh命令 您必须具有管理员权限 这是我自己的计算机 我是管理员 运行脚本时我已经使用管理员类型的用户 Adrian 登录 我无
  • 如何在 Pandas Python 中按 id 对行进行排名

    我有一个像这样的数据框 id points1 points2 1 44 53 1 76 34 1 63 66 2 23 34 2 44 56 我想要这样的输出 id points1 points2 points1 rank points2
  • Python 内置对象的 __enter__() 和 __exit__() 在哪里定义?

    我读到每次使用 with 时都会调用该对象的 enter 和 exit 方法 我知道对于用户定义的对象 您可以自己定义这些方法 但我不明白这对于 打开 等内置对象 函数甚至测试用例是如何工作的 这段代码按预期工作 我假设它使用 exit 关
  • 如何找到多个 pandas 数据框中一对列与任意顺序对的交集?

    我有多个 pandas 数据框 为了简单起见 假设我有三个 gt gt df1 col1 col2 id1 A B id2 C D id3 B A id4 E F gt gt df2 col1 col2 id1 B A id2 D C id
  • 为什么需要设置WORKON_HOME环境变量?

    我已经有一段时间没有使用 python 虚拟环境了 但我也安装了虚拟环境包装器 我的问题是 在文档页面中它说要这样做 export WORKON HOME Envs mkdir p WORKON HOME source usr local
  • 在 Python 中从 Excel 复制 YEARFRAC() 函数

    因此 我使用 python 来自动执行一些必须在 Excel 中执行的重复任务 我需要做的计算之一需要使用yearfrac 这在Python中被复制了吗 I found this https lists oasis open org arc
  • 了解 Python 2.7 中的缩进错误

    在编写 python 代码时 我往往会遇到很多缩进错误 有时 当我删除并重写该行时 错误就会消失 有人可以为菜鸟提供 python 中 IndentationErrors 的高级解释吗 以下是我在玩 CheckIO 时收到的最近 inden
  • multiprocessing.Queue 中的 ctx 参数

    我正在尝试使用 multiprocessing Queue 模块中的队列 实施 https docs python org 3 4 library multiprocessing html exchang objects Between p
  • 使用 python 脚本更改 shell 中的工作目录

    我想实现一个用户态命令 它将采用其参数之一 路径 并将目录更改为该目录 程序完成后 我希望 shell 位于该目录中 所以我想实施cd命令 但需要外部程序 可以在 python 脚本中完成还是我必须编写 bash 包装器 Example t
  • Flymake的临时文件可以在系统临时目录下创建吗?

    我目前正在使用以下代码在 emacs 中连接 Flymake 和 Pyflakes defun flymake create temp in system tempdir filename prefix make temp file or
  • 如何通过selenium中弹出的身份验证?

    我正在尝试使用带有 Selenium 的 Python 脚本加载需要身份验证的网页 options webdriver ChromeOptions prefs download default directory r download de
  • 如何创建增量加载网页

    我正在编写一个处理大量数据的页面 它会永远持续到我的结果页面加载 几乎无限 因为返回的数据太大了 因此 我需要实现一个增量加载页面 例如 url 中的页面 http docs python org http docs python org
  • 类返回语句不打印任何输出

    我正在学习课程 但遇到了问题return语句 它是语句吗 我希望如此 程序什么也没有打印出来 它只是结束而不做任何事情 class className def createName self name self name name def
  • AWS 将 MQTT 消息存储到 DynamoDB

    我构建了一个定期发送 MQTT 消息的 python 脚本 这是发送到后端的 JSON 字符串 Id 1234 Ut 1488395951 Temp 22 86 Rh 48 24 在后端 我想将 MQTT 消息存储到 DynamoDB 表中
  • PyQt5按钮lambda变量变成布尔值[重复]

    这个问题在这里已经有答案了 当我运行下面的代码时 它显示如下 为什么 x 不是 x 而是变成布尔值 这种情况仅发生在传递到用 lambda 调用的函数中的第一个参数上 错误的 y home me model some file from P
  • py2exe ImportError:没有名为 的模块

    我已经实现了一个名为 myUtils 的包 它由文件夹 myUtils 文件 组成 init py 和许多名称为 myUtils 的 py 文件 该包包含在 myOtherProject py 中 当我从 Eclipse 运行它们时可以找到

随机推荐