如何自动编辑x,ypath

2024-09-24 22:28:04 发布

您现在位置:Python中文网/ 问答频道 /正文

这是一个相当抽象的问题,不一定附加到语言/模块。很抱歉,没有具体说明

我正在使用OpenCV用Python(为我的生物实验室工作)制作一个对象跟踪程序。到目前为止,我正在将显微镜视频转换成帧,然后检测周围游动的生物体

这些视频中有很多类似这样的bug:

microscopic worm in crescent formation

我已经成功地找到了获得x、y路径的方法,可以勾勒出这些路径的轮廓。如果成功,则如下所示(其中x,y路径是绿色周围的边界):

Correct mask of the first worm

但是,我经常会得到x,y路径,看起来更像这样:

Improper mask

如您所见,x、y路径包含了蠕虫的大部分但不是全部边缘。我将这种不正确的路径称为“边缘遮罩”。我需要的是第二张照片。我可以向任何人解释如何识别这个边缘遮罩(“极端”凹度,在自身上循环),但我正在努力找到一种算法,能够在第三张图像中获取x,y路径,并在第二张图像中返回接近的结果。有什么想法吗

在python中,构成上述绿色掩码的x、y路径在我的程序中存储如下:

lst = [x0, y0, x1, y1, x2, y2, ..., xn, yn]

…其中(xnyn)点被视为也环绕并与(x0y0)点连接。我使用这个表单,但是如果需要的话,可以很容易地将它转换为元组列表

我想象的是一种算法,它能够识别路径的其他部分完全“包含”(可以说)的部分,也就是位于遮罩内部的x,y点(如下图中的红色部分)。如果我能找到一种算法,能够识别红色路径上的点并将其删除,那么该路径将正确地包含/屏蔽蠕虫

Red on the inner edge of the mask

我看到的一个问题是:单靠凹面是没有帮助的。蠕虫本身是弯曲的,它的右边缘是完全凹的,所以我不能单独使用凹度来识别上面图像中的红线

我会附加代码,但我的代码不是问题所在,而是找到一个算法来调整我正在使用的代码的输出。我相信我的问题不需要&;无法提供最小可复制示例。我认为这就是为什么他们在提到使用mre时会说“适当的时候……”。谢谢


在我发布这篇文章之后,我一直在思考,我想我对该做什么有一个想法,我想听听人们的想法:

对于路径上的每个x,y点,我可以使用均匀分布的光线进行检查,以查看大约%的光线与路径的另一部分相交。在上面的第四张图片中,红色边缘上的点的“逃逸”光线的百分比远低于外部的点,甚至低于蠕虫右侧凹面上的点。我可以删除逃逸光线百分比较低的点(使用任意阈值),路径就可以了。想法


原始数据示例:

lst = [17, 297, 17, 303, 15, 305, 15, 309, 16, 310, 17, 310, 20, 313, 21, 313, 32, 324, 32, 326, 33, 326, 35, 328, 38,
       328, 39, 327, 39, 323, 38, 322, 37, 322, 36, 321, 36, 320, 35, 319, 35, 313, 36, 312, 42, 312, 43, 313, 44, 313,
       45, 314, 46, 314, 47, 315, 50, 315, 51, 316, 52, 316, 53, 317, 54, 317, 55, 318, 56, 318, 57, 319, 58, 319, 59,
       320, 60, 320, 62, 322, 63, 322, 67, 326, 70, 326, 74, 330, 75, 330, 78, 333, 79, 333, 83, 337, 83, 338, 84, 339,
       84, 340, 85, 340, 92, 347, 93, 347, 95, 349, 96, 349, 99, 352, 100, 352, 106, 358, 106, 359, 110, 363, 110, 364,
       112, 366, 113, 366, 116, 369, 117, 369, 119, 371, 119, 378, 118, 379, 112, 379, 110, 377, 109, 377, 105, 373,
       104, 373, 93, 362, 92, 362, 88, 358, 88, 357, 87, 357, 81, 351, 80, 351, 77, 348, 76, 348, 67, 339, 66, 339, 61,
       334, 60, 334, 58, 332, 57, 332, 56, 331, 55, 331, 54, 330, 48, 330, 48, 333, 49, 333, 50, 334, 51, 334, 52, 335,
       53, 335, 61, 343, 62, 343, 69, 350, 70, 350, 73, 353, 74, 353, 75, 354, 75, 355, 76, 355, 82, 361, 83, 361, 85,
       363, 85, 364, 86, 365, 87, 365, 99, 377, 100, 377, 104, 381, 105, 381, 107, 383, 108, 383, 109, 384, 111, 384,
       113, 386, 114, 386, 116, 388, 117, 388, 118, 389, 120, 389, 121, 390, 121, 392, 122, 393, 123, 393, 124, 394,
       125, 394, 126, 395, 127, 395, 128, 396, 128, 397, 129, 398, 130, 398, 133, 401, 142, 401, 143, 400, 143, 399,
       144, 398, 144, 394, 143, 393, 143, 389, 140, 386, 140, 385, 138, 383, 137, 383, 132, 378, 132, 377, 131, 376,
       130, 376, 128, 374, 128, 373, 127, 372, 127, 371, 119, 363, 118, 363, 114, 359, 114, 358, 113, 358, 110, 355,
       110, 353, 106, 349, 105, 349, 103, 347, 102, 347, 99, 344, 98, 344, 90, 336, 89, 336, 88, 335, 88, 334, 87, 333,
       87, 332, 85, 330, 84, 330, 81, 327, 80, 327, 79, 326, 78, 326, 76, 324, 75, 324, 73, 322, 72, 322, 68, 318, 67,
       318, 65, 316, 64, 316, 63, 315, 62, 315, 61, 314, 60, 314, 59, 313, 58, 313, 57, 312, 56, 312, 55, 311, 52, 311,
       51, 310, 50, 310, 49, 309, 48, 309, 47, 308, 46, 308, 45, 307, 44, 307, 43, 306, 42, 306, 41, 305, 40, 305, 39,
       304, 32, 304, 32, 308, 31, 309, 25, 309, 24, 308, 24, 302, 25, 301, 28, 301, 28, 299, 27, 299, 26, 298, 22, 298,
       21, 297]

Tags: 代码图像路径程序算法视频边缘光线
1条回答
网友
1楼 · 发布于 2024-09-24 22:28:04

我继续写下了我的想法,到目前为止似乎效果不错。借用了this page中关于查找两条线段是否相交的内容

def ccw(A, B, C):
    return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])


# Return true if line segments AB and CD intersect
def intersect(A, B, C, D):
    return ccw(A, C, D) != ccw(B, C, D) and ccw(A, B, C) != ccw(A, B, D)


def rayEscape(point, degree, path, radius, indx=-1):
    """Returns True if a ray going from 'point' at an angle of 'degree' (defined like in polar coordinates)
    never intercepts with path. False otherwise."""
    ray_end_point = (point[0] + radius * cos(degree), point[1] + radius * sin(degree))
    for i in range(0, len(path), 2):
        j = (i + 2) % len(path)
        seg_point_0 = path[i:i+2]
        seg_point_1 = path[j:j+2]
        if indx != i and indx != j and intersect(point, ray_end_point, seg_point_0, seg_point_1):
            return False
    return True


def deleteInsidePoints(path, num_rays, cutoff=0.0):
    """For each point, calculates the proportion of rays that go from the point and never hit any
    part of the path again. If the proportion is strictly greater than the cutoff, the point is kept in the return list.
    Otherwise, it's ignored."""
    final = []
    max_len = ((min(path[::2]) - max(path[::2])) ** 2 + (min(path[1::2]) - max(path[1::2])) ** 2) ** 0.5
    for i in range(0, len(path), 2):
        point = path[i:i+2]
        num_escape = 0
        for j in range(num_rays):
            num_escape += int(rayEscape(point, 2 * pi * j / num_rays, path, max_len, i))
        if num_escape / num_rays > cutoff:
            final.extend(point)
    return final

lst2 = deleteInsidePoints(lst, 25, 0.3)

以下是两个实际应用程序:

bad 1good 1

bad 2good 2

在第二个例子中,你可以看到它在左边删除的时候有点过于热心,留下了一条直线,但总体来说还是不错的

旁注:我在这里的代码是从我第一次发布它时稍微编辑的。我忘了让程序检查光线是否与路径段相交,包括光线来自的点。现在,rayEscape函数中的“indx”变量允许跳过包含感兴趣点的段

相关问题 更多 >