返回使用openCV从不规则形状区域跟踪的物体的着陆位置

问题描述 投票:0回答:1

我正在使用 OpenCV 使用相机从自上而下的位置确定物体的着陆位置。我已经获得了对象跟踪的代码,因此这不是问题。我遇到的问题是返回物体着陆的位置。

因为这是一个与工作相关的问题,所以我将捕获的图像的背景设为白色。

目标是一个不是很厚的大(直径)环。我想要做的是弄清楚物体是落在该环的内部、中心还是外部。 总着陆区域是一个大环,每 5 度有 3 个区域(A、B、C),总共有 216 个可能的着陆位置(图像 1)。摄像机唯一看到的就是戒指。部分/区域及其大小在代码中决定。通过跟踪对象轮廓的中心点,我知道对象着陆位置的 [x,y] 坐标(在帧中)。对于我的示例,对象落在 35 度部分,C 区。我遇到的问题是,我不知道计算和存储每个区域/部分组合的所有可能坐标的最佳方法,以便当物体着陆程序将输出“物体着陆在第 __ 区,区域 __”。

因为 216 个位置中的每一个都由一定数量的像素组成,每个像素都有自己的 [x,y] 坐标。我的想法是,我想要迭代所有 216 个位置并存储组成每个位置的可能坐标,以便当我获得对象的最终位置时,我可以将其与我存储的坐标进行比较并返回它着陆的位置为此,我正在考虑一个字典的字典,它存储所有 72 个部分、每个部分内的三个区域以及每个区域内所有可能的坐标对。我想使用字典的原因是我可以轻松地在最后返回键(部分和区域名称)。

为了测试我是否可以准确地存储所有像素,我使用沿弧线的所有点的方程编写了代码以在该部分中着色。它效果不佳,因为当我为这些像素着色时,我最终既重复了许多像素,又丢失了一些像素(图像2)。我尝试修改代码以使用 Bresenham 算法来尝试修复此问题,但这也不起作用(image 3)。

一些可能值得考虑的注释:

  • 这个程序不是面向消费者的项目,它将用于内部测试,因此不需要过度性能或高效,但如果是的话仍然更好。重要的是返回着陆位置的准确性。

  • 目标和相机将始终固定。

  • 一旦物体着陆,所有跟踪将停止,然后确定着陆位置。

我的问题如下:

  1. 我所描述的能够返回物体着陆位置的正确方法是(即将定义区域的像素坐标存储在字典字典中以便稍后进行比较)吗?

  2. 有更好的方法吗?有没有一种方法可以轻松定义 216 个形状不规则的感兴趣区域(它们实际上只是环形部分)。有没有我可以导入的库可以让这变得更容易?

  3. 我怎样才能准确地、不重复地绘制这些部分,或者逐像素地绘制这些部分,以便我可以确保我不会遗漏任何点。

这里是绘制像素的代码示例(使用非 Bresenham 方法):

step_size = 0.1
angle_start = 32.5
angle_end = angle_start + 398.2 + step_size
r_in_end = radius_inner + ring_thickness/2

r_out_in = r_out - ring_thickness
print(f'Inner radius (float): {r_out_in} | Inner radius (int): {int(r_out_in)}')
r_out_end = r_out
print(f'Outer radius (float): {r_out_end} | Inner radius (int): {int(r_out_end)}')
angle_value = np.arange(angle_start, angle_end, 0.2)
# print(angle_value)
# print(f'angle_value: {angle_value}')
# print(f'angle_value size: {len(angle_value)}')
section_length = r_out_end - r_out_in + 2

# Calculate the sizes of the outer for loop (height)
# calculate the size of the inner for loop (width)
# Initialize an empty array of the size needed (height X width) to fill
width = int((r_out_end + 1.5 - r_out_in - .5))
height = len(angle_value)
pixel_locations = np.zeros((width * height, 2), dtype=np.int32)

# Intitialize variables for storing points in the array and checking repeats in the array
index = 0
px_match = 0
prev_pt = (0, 0)

# Nest the loops to color pixels at every point along the arc
# for every step in the direction of the inner section radius to the outer section radius.
for r in range(int(r_out_in+.5), int(r_out_end+1.5)):

    for angle in angle_value:

        # Convert angle to radians and rename as theta for understandibility
        # Calculate the x and y positions of the pixel along the arc length
        theta = math.radians(angle)
        x = int(center_loc[0] + math.sin(theta) * r)
        y = int(center_loc[1] + math.cos(theta) * r)

        # Store the x and y coords in the empty array
        # Increment the index
        pixel_locations[index] = [x, y]
        index += 1

        # Error checking. We don't want a location to repeat
        if (x, y) == prev_pt:
            # print(f'The current position is:{x, y} | The previous position was: {prev_pt}')
            px_match += 1

        # Draw the new point on the image to give visual check that the function is working
        # cv2.circle(overlay, (x, y), radius=1, color=(255, 0, 0), thickness=-1)
        overlay[y, x] = (255, 0, 0)
        
        # store the current location as the new previous for the next loop.
        prev_pt = (x, y)

# Print out number of repeats.
print(f'The number of overlapping pixels is: {px_match}')
Target_transparent = cv2.addWeighted(overlay, alpha, TargetImg_Resized, 1 - alpha, 0)
python opencv object-detection
1个回答
0
投票

我建议使用极坐标来确定以像素坐标给出的物体已知着陆位置的区域和截面。下面是使用这种方法的代码示例:

import cmath, math, random

webCamImgWidth=640
webCamImgHeight=640
xC = webCamImgWidth/2
yC= webCamImgHeight//2
r = xC
zoneAlpha = 5 # degrees
r0, r1, r2, r3 = ( 0.6*r,  0.7*r,  0.8*r,  0.9*r)   # adjust to desired values if needed
print(f"{xC=} , {yC=} , {r0=} , {r1=}, {r2=} , {r3=} ")
Zones = ["innerZone","A", "targetB", "C", "outerZone"]

landingPositions = [ ( random.randint(1,640), random.randint(1,640) ) for _ in range(10) ]
#print(f"{landingPositions=}") 

for position in landingPositions:
    polarPosition = (position[0]-xC, position[1]-yC)
    x = complex(*polarPosition)
    r, phi = cmath.polar(x)
    if r < r0 : zoneIndex = 0
    elif r < r1 :   zoneIndex = 1
    elif r < r2 :   zoneIndex = 2
    elif r < r3 :   zoneIndex = 3
    else:       zoneIndex = 4
    section=int ( (phi/math.pi)*180 ) // 5
    if section < 0 : section = 36 - section
    print( f"The in image at ( {position[0]:3d}, {position[1]:3d} ) detected object landed in {section=:2d}  zone={Zones[zoneIndex]}")

印刷

The in image at ( 323, 230 ) detected object landed in section=54  zone=innerZone
The in image at ( 410, 435 ) detected object landed in section=10  zone=innerZone
The in image at ( 120, 232 ) detected object landed in section=68  zone=A
The in image at ( 331, 183 ) detected object landed in section=53  zone=innerZone
The in image at ( 199, 357 ) detected object landed in section=32  zone=innerZone
The in image at ( 178, 111 ) detected object landed in section=61  zone=targetB
The in image at (  35, 171 ) detected object landed in section=67  zone=outerZone
The in image at ( 325, 513 ) detected object landed in section=17  zone=A
The in image at ( 168, 511 ) detected object landed in section=25  zone=targetB
The in image at ( 281, 138 ) detected object landed in section=57  zone=innerZone
© www.soinside.com 2019 - 2024. All rights reserved.