使用端点和凸出距离绘制圆弧。在 OpenCV 或 PIL 中

2024-03-08

在编写将 dxf 转换为 png 的脚本时,我需要绘制只有三个参数的圆弧,即圆弧的起点、圆弧的终点和凸出距离。

我检查了OpenCV和PIL,它们需要开始和结束角度来绘制这个弧。我可以使用一些几何图形找出这些角度,但想知道是否还有其他我错过的解决方案。


您有定义圆弧的三条信息:圆上的两个点(定义chord该圆的距离)和凸出距离(称为sagitta的圆弧)。

参见下图:

Here s是矢车菊,l是弦长的一半,并且r当然是半径。其他重要的未标记位置是弦与圆相交的点、矢状面与圆相交的点以及半径从其延伸的圆心。

对于 OpenCV 来说ellipse() https://docs.opencv.org/3.0-beta/modules/imgproc/doc/drawing_functions.html#ellipse函数,我们将使用以下原型:

cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]]) → img

其中大部分参数由下图描述:

由于我们绘制的是圆形而不是椭圆形弧,因此长轴/短轴将具有相同的尺寸,并且旋转它没有区别,因此轴将是(radius, radius)angle为了简化应该为零。那么我们需要的唯一参数就是圆心、半径以及绘制的起始角度和结束角度,对应于弦的点。这些角度很容易计算(它们只是圆上的一些角度)。所以最终我们需要找到圆的半径和圆心。

求半径和圆心与求圆方程相同,因此有很多方法可以实现。但由于我们在这里编程,最简单的方法(IMO)是在圆上定义第三个点,即矢形接触圆的位置,然后从这三个点求解圆。

因此,首先我们需要获得弦的中点,获得与该中点的垂直线,并将其延伸到矢状面的长度以到达第三点,但这很容易。我将开始给出pt1 = (x1, y1) and pt2 = (x2, y2)作为我在圆上的两点和sagitta是“凸出深度”(即您拥有的参数):

# extract point coordinates
x1, y1 = pt1
x2, y2 = pt2

# find normal from midpoint, follow by length sagitta
n = np.array([y2 - y1, x1 - x2])
n_dist = np.sqrt(np.sum(n**2))

if np.isclose(n_dist, 0):
    # catch error here, d(pt1, pt2) ~ 0
    print('Error: The distance between pt1 and pt2 is too small.')

n = n/n_dist
x3, y3 = (np.array(pt1) + np.array(pt2))/2 + sagitta * n

现在我们得到了圆上的第三个点。请注意,矢矢只有一定的长度,因此它可以向任一方向移动——如果矢矢为负,则它会从弦向一个方向移动,如果为正,则它会向另一个方向移动。不确定这是否是给你这个距离的方式。

那么我们可以简单地使用行列式求解半径和中心 https://math.stackexchange.com/a/1460096/246399.

# calculate the circle from three points
# see https://math.stackexchange.com/a/1460096/246399
A = np.array([
    [x1**2 + y1**2, x1, y1, 1],
    [x2**2 + y2**2, x2, y2, 1],
    [x3**2 + y3**2, x3, y3, 1]])
M11 = np.linalg.det(A[:, (1, 2, 3)])
M12 = np.linalg.det(A[:, (0, 2, 3)])
M13 = np.linalg.det(A[:, (0, 1, 3)])
M14 = np.linalg.det(A[:, (0, 1, 2)])

if np.isclose(M11, 0):
    # catch error here, the points are collinear (sagitta ~ 0)
    print('Error: The third point is collinear.')

cx = 0.5 * M12/M11
cy = -0.5 * M13/M11
radius = np.sqrt(cx**2 + cy**2 + M14/M11)

最后,由于我们需要起始角度和结束角度来用 OpenCV 绘制椭圆,所以我们可以使用atan2()获取从中心到初始点的角度:

# calculate angles of pt1 and pt2 from center of circle
pt1_angle = 180*np.arctan2(y1 - cy, x1 - cx)/np.pi
pt2_angle = 180*np.arctan2(y2 - cy, x2 - cx)/np.pi

所以我将这一切打包成一个函数:

def convert_arc(pt1, pt2, sagitta):

    # extract point coordinates
    x1, y1 = pt1
    x2, y2 = pt2

    # find normal from midpoint, follow by length sagitta
    n = np.array([y2 - y1, x1 - x2])
    n_dist = np.sqrt(np.sum(n**2))

    if np.isclose(n_dist, 0):
        # catch error here, d(pt1, pt2) ~ 0
        print('Error: The distance between pt1 and pt2 is too small.')

    n = n/n_dist
    x3, y3 = (np.array(pt1) + np.array(pt2))/2 + sagitta * n

    # calculate the circle from three points
    # see https://math.stackexchange.com/a/1460096/246399
    A = np.array([
        [x1**2 + y1**2, x1, y1, 1],
        [x2**2 + y2**2, x2, y2, 1],
        [x3**2 + y3**2, x3, y3, 1]])
    M11 = np.linalg.det(A[:, (1, 2, 3)])
    M12 = np.linalg.det(A[:, (0, 2, 3)])
    M13 = np.linalg.det(A[:, (0, 1, 3)])
    M14 = np.linalg.det(A[:, (0, 1, 2)])

    if np.isclose(M11, 0):
        # catch error here, the points are collinear (sagitta ~ 0)
        print('Error: The third point is collinear.')

    cx = 0.5 * M12/M11
    cy = -0.5 * M13/M11
    radius = np.sqrt(cx**2 + cy**2 + M14/M11)

    # calculate angles of pt1 and pt2 from center of circle
    pt1_angle = 180*np.arctan2(y1 - cy, x1 - cx)/np.pi
    pt2_angle = 180*np.arctan2(y2 - cy, x2 - cx)/np.pi

    return (cx, cy), radius, pt1_angle, pt2_angle

使用这些值,您可以使用 OpenCV 绘制弧线ellipse()功能。然而,这些都是浮点值。ellipse()确实可以让您使用以下命令绘制浮点值shift争论,但如果你不熟悉它,那就有点奇怪了,所以我们可以借用解决方案这个答案 https://stackoverflow.com/a/44892317/5087436定义一个函数

def draw_ellipse(
        img, center, axes, angle,
        startAngle, endAngle, color,
        thickness=1, lineType=cv2.LINE_AA, shift=10):
    # uses the shift to accurately get sub-pixel resolution for arc
    # taken from https://stackoverflow.com/a/44892317/5087436
    center = (
        int(round(center[0] * 2**shift)),
        int(round(center[1] * 2**shift))
    )
    axes = (
        int(round(axes[0] * 2**shift)),
        int(round(axes[1] * 2**shift))
    )
    return cv2.ellipse(
        img, center, axes, angle,
        startAngle, endAngle, color,
        thickness, lineType, shift)

然后要使用这些功能就很简单:

img = np.zeros((500, 500), dtype=np.uint8)
pt1 = (50, 50)
pt2 = (350, 250)
sagitta = 50

center, radius, start_angle, end_angle = convert_arc(pt1, pt2, sagitta)
axes = (radius, radius)
draw_ellipse(img, center, axes, 0, start_angle, end_angle, 255)
cv2.imshow('', img)
cv2.waitKey()

再次注意,负矢矢给出了另一个方向的弧:

center, radius, start_angle, end_angle = convert_arc(pt1, pt2, sagitta)
axes = (radius, radius)
draw_ellipse(img, center, axes, 0, start_angle, end_angle, 255)
center, radius, start_angle, end_angle = convert_arc(pt1, pt2, -sagitta)
axes = (radius, radius)
draw_ellipse(img, center, axes, 0, start_angle, end_angle, 127)
cv2.imshow('', img)
cv2.waitKey()

最后,为了扩展,我在convert_arc()功能。第一的:

if np.isclose(n_dist, 0):
    # catch error here, d(pt1, pt2) ~ 0
    print('Error: The distance between pt1 and pt2 is too small.')

这里的错误是因为我们需要得到一个单位向量,所以我们需要除以长度,而长度不能为零。当然,这只有在以下情况下才会发生pt1 and pt2是相同的点,因此您只需在函数顶部检查它们是否是唯一的,而不是在此处检查。

Second:

if np.isclose(M11, 0):
    # catch error here, the points are collinear (sagitta ~ 0)
    print('Error: The third point is collinear.')

仅当三个点共线时才会发生这种情况,而只有当 sagitta 为 0 时才会发生这种情况。因此,您可以在函数的顶部检查这一点(也许会说,好吧,如果它是 0,则只需从pt1 to pt2或任何你想做的事)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用端点和凸出距离绘制圆弧。在 OpenCV 或 PIL 中 的相关文章

  • 使用 openCV 和 python 检测物体

    我正在尝试使用 OpenCV 和 Python 检测下图中的白点 我尝试使用函数 cv2 HoughCircles 但没有成功 我需要使用不同的方法吗 这是我的代码 import cv2 cv import numpy as np impo
  • Python - 查找图像中对象的中心

    我有一个具有白色背景和非白色对象的图像文件 我想使用 python Pillow 找到对象的中心 我在 C 中发现了类似的问题 但没有可接受的答案 如何找到物体的中心 https stackoverflow com questions 12
  • opencv createsamples没有错误,但是没有找到样本

    我在用着this http coding robin de 2013 07 22 train your own opencv haar classifier html教程 我正在根据我的正面图像创建大量样本 我正在使用 Windows 这是
  • 查找彼此接近的对象边界

    我正在研究一个计算机视觉问题 其中问题的第一步是找到物体彼此靠近的位置 例如 在下图中 我感兴趣的是找到灰色标记的区域 Input Output 我目前的方法是首先反转图像 然后通过侵蚀进行形态梯度跟随 然后删除一些不感兴趣的轮廓 脚本如下
  • 如何读取 10 位原始图像?其中包含 RGB-IR 数据

    我想知道如何从我的 10 位原始 它有 rgb ir 图像数据 数据中提取 RGB 图像 如何使用 Python 或 MATLAB 进行阅读 拍摄时的相机分辨率为 1280x720 室内照片图片下载 https drive google c
  • OpenCV:视频结束后如何重新启动?

    我正在播放视频文件 但播放完毕后如何再次播放 Javier 如果您想一遍又一遍地重新启动视频 也称为循环播放 可以通过在帧数达到时使用 if 语句来实现cap get cv2 cv CV CAP PROP FRAME COUNT 然后重置帧
  • 使用 opencv warpPerspective() 生成道路的自上而下视图

    我正在尝试实施逆透视映射计算与道路上另一辆车的距离 我知道在应用该函数之前我需要生成一个包含源点和目标点的变换矩阵warpPerspective 但我不知道如何计算目的地点 我在这个论坛和其他网站中搜索 但无法将第一张图片转换为第二张图片
  • PIL 不保存透明度

    from PIL import Image img Image open 1 png img save 2 png 第一张图像具有透明背景 但是当我保存它时 透明度消失了 背景为白色 我究竟做错了什么 可能图像已被索引 PIL 中的模式 P
  • 使用 StretchDIBits 使用 Delphi 6 处理条形码图像 - 输出中缺少条形线

    我的应用程序是在 Delphi 6 中开发的 由于后台处理和大量数据 它消耗大约 60MB 120MB 物理内存 这是一个资源密集型应用程序 该应用程序的功能之一是在进行某些处理后创建条形码图像 如果用户继续生成条形码 那么至少十分之一的条
  • 创建圆形图像 PIL Tkinter

    Currently I have a zoom feature in my application that works very well however I d like the actual zoom box to be a circ
  • 在加载“cv2”二进制扩展期间检测到递归

    我有一个小程序 在 pyinstaller 编译后返回 opencv 错误 但无需编译即可工作 我在 Windows 10 上使用 Python 3 8 10 Program 导入 pyautogui将 numpy 导入为 np导入CV2
  • Python中最相似的人脸识别

    如何使用Python和OpenCV来查找面部相似 我已成功使用 OpenCV 和 Python 使用 Haar Cascades 从多张照片中提取人脸 我现在有一个图像目录 所有这些都是不同人的面孔 我想做的是拍摄一张样本图像 然后看看它最
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • Tesseract 是否会忽略扫描文档中的任何非文本区域?

    我正在使用 Tesseract 但我不知道它是否忽略任何非文本区域并仅针对文本 我是否必须删除任何非文本区域作为预处理步骤以获得更好的输出 Tesseract 有一个非常好的算法来检测文本 但它最终会给出误报匹配 理想情况下 您应该在将图像
  • 我可以使用 openCV 比较两张不同图像上的两张脸吗?

    我对 openCV 很陌生 我看到它可以计算出脸部并返回一个矩形来指示脸部 我想知道 openCV 是否可以访问两张包含一张脸的图像 并且我希望 openCV 返回这两个人是否相同的可能性 Thanks OpenCV 不提供完整的人脸识别引
  • 如何修复此 YCrCb -> RBG 转换公式?

    我使用的公式来自这个问题 https stackoverflow com questions 8838481 kcvpixelformattype 420ypcbcr8biplanarfullrange frame to uiimage c
  • 从 imread 返回的 ndims

    我正在从文件夹中选取图像 尺寸为128 128 为此 我使用以下代码行 FileName PathName uigetfile jpg Select the Cover Image file fullfile PathName FileNa
  • 在discord.py中访问成员的横幅

    我正在制作图像配置文件命令 我想为此访问会员的横幅 我们有什么办法可以在discord py 中做到这一点吗 如果不清楚我所说的横幅是什么意思 那么蓝色背景的图像就是横幅 我想访问它 在discord py v2 0中你可以使用 You m
  • 在Matlab中选择图像上的像素时,索引指的是什么?

    当在Matlab中查看图像的单个像素时 该索引指的是什么 X Y 指的是像素的坐标 RGB 指的是颜色 但是关于索引是什么有什么想法吗 为了澄清一下 当我在 Matlab 中查看图形并使用数据光标选择一个点时 显示的三行是 X Y 指数 R
  • 如何使用 PySpark 预处理图像?

    我有一个项目 需要为 1 设置大数据架构 AWS S3 SageMaker 的概念验证使用 PySpark 预处理图像 2 执行 PCA and 3 训练一些机器或深度学习模型 我的问题是了解如何使用 PySpark 操作图像数据 但无法在

随机推荐