您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“如何用Python實現點云的地面檢測”,內容詳細,步驟清晰,細節處理妥當,希望這篇“如何用Python實現點云的地面檢測”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
在開始之前,了解計算機視覺中的傳統坐標系是很重要的。其次是Open3D和Microsoft Kinect傳感器。在計算機視覺中,圖像用獨立的2D坐標系表示,其中x軸從左向右指向,y軸是上下指向。對于相機,3D坐標系原點位于相機的焦點處,x軸指向右,y軸指向下,z軸指向前。
計算機視覺坐標系
我們首先導入所需的Python庫:
import numpy as np import open3d as o3d
為了更好地理解,讓我們從 PLY 文件中導入點云,使用 Open3D 創建默認的 3D 坐標系并顯示它們:
# Read point cloud: pcd = o3d.io.read_point_cloud("data/depth_2_pcd.ply") # Create a 3D coordinate system: origin = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5) # geometries to draw: geometries = [pcd, origin] # Visualize: o3d.visualization.draw_geometries(geometries)
以坐標系原點顯示的點云
藍色箭頭是 Z 軸,紅色箭頭是 X 軸,綠色箭頭是 Y 軸。可以看到點云在與Open3D坐標系相同的坐標系中表示。現在,讓我們獲取具有每個軸的最小值和最大值的點:
# Get max and min points of each axis x, y and z: x_max = max(pcd.points, key=lambda x: x[0]) y_max = max(pcd.points, key=lambda x: x[1]) z_max = max(pcd.points, key=lambda x: x[2]) x_min = min(pcd.points, key=lambda x: x[0]) y_min = min(pcd.points, key=lambda x: x[1]) z_min = min(pcd.points, key=lambda x: x[2])
我們可以打印它們,但為了更好的可視化,我們在每個點位置創建一個球體。默認情況下,Open3D在原點位置創建3D幾何圖形:
要將球體移動到給定位置,需要進行平移變換。在下面的示例中,球體以向量 [1,1,1] 平移:
讓我們回到我們的示例,為每個球體分配一個顏色。對于每個位置,我們創建一個球體并將其平移到該位置。然后,我們分配正確的顏色,最后我們將它添加到顯示。
# Colors: RED = [1., 0., 0.] GREEN = [0., 1., 0.] BLUE = [0., 0., 1.] YELLOW = [1., 1., 0.] MAGENTA = [1., 0., 1.] CYAN = [0., 1., 1.] positions = [x_max, y_max, z_max, x_min, y_min, z_min] colors = [RED, GREEN, BLUE, MAGENTA, YELLOW, CYAN] for i in range(len(positions)): # Create a sphere mesh: sphere = o3d.geometry.TriangleMesh.create_sphere(radius=0.05) # move to the point position: sphere.translate(np.asarray(positions[i])) # add color: sphere.paint_uniform_color(np.asarray(colors[i])) # compute normals for vertices or faces: sphere.compute_vertex_normals() # add to geometry list to display later: geometries.append(sphere) # Display: o3d.visualization.draw_geometries(geometries)
實際上,y軸代表了點的高度:在現實世界中,最高的球是黃色的球,最低的球是綠色的球。但是,由于y軸向下,黃色球體的值最小,綠色球體的值最大。
另一個有趣的球體是原點上的青色球體。正如我們在上一篇教程中提到的,深度值為0的像素是噪聲點,因此位于原點的點是從這些噪聲像素計算出來的點(當z=0時,則x=0和y=0)。
現在我們已經展示了一些重要的點,如何進行地面檢測呢?在前面的例子中,綠色球體位于地面上。確切地說,它的中心對應于沿y軸的最高點是一個地面點。假設為了地面檢測,我們將所有具有y_max的點的顏色都更改為綠
如果顯示點云,您會注意到并非所有的地面點都是綠色的。事實上,只有一個與前面綠色球體的中心相對應的點是綠色的。這是由于深度相機的精度和噪聲造成的。
為了克服這個限制,我們需要添加一個閾值,以便將y坐標為[y_max-threshold, y_max]的點都視為地面點。為此,在得到y_max后,我們檢查每個點的y坐標是否在該區間內,然后將其顏色設置為綠色。最后更新點云的顏色屬性并顯示結果。
# Define a threshold: THRESHOLD = 0.075 # Get the max value along the y-axis: y_max = max(pcd.points, key=lambda x: x[1])[1] # Get the original points color to be updated: pcd_colors = np.asarray(pcd.colors) # Number of points: n_points = pcd_colors.shape[0] # update color: for i in range(n_points): # if the current point is aground point: if pcd.points[i][1] >= y_max - THRESHOLD: pcd_colors[i] = GREEN# color it green pcd.colors = o3d.utility.Vector3dVector(pcd_colors) # Display: o3d.visualization.draw_geometries([pcd, origin])
在本例中,我們只將代表地面的點涂成綠色。在現實世界的應用中,地面被提取來定義可行走的區域,如機器人或視覺障礙系統,或在其上放置物體,如室內設計系統。它也可以被刪除,所以剩下的點可以被分割或分類,就像在場景理解和目標檢測系統一樣。
我們知道點云定義為一組3D點。集合是一種無序結構,因此集合所表示的點云稱為無組織點云。與RGB矩陣類似,有組織的點云是一個2D矩陣,有3個通道表示點的x、y和z坐標。矩陣結構提供了相鄰點之間的關系,從而降低了一些算法的時間復雜度,如最近鄰算法。
舉個例子,我們正在寫一篇研究論文,我們想用圖的形式展示我們的檢測算法的結果。我們既可以截取點云的截圖,也可以將結果顯示在深度圖像上,如下圖所示。在我看來,第二個選擇是最好的。在這種情況下,需要一個有組織的點云來保存深度像素的位置。
左:3D 可視化的屏幕截圖 右:深度圖像的結果
讓我們從之前的深度圖像創建一個有組織的點云。我們首先導入相機參數。我們還導入深度圖像并將其轉換為3通道灰度圖像,以便我們可以將地面像素設置為綠色:
import imageio.v3 as iio import numpy as np import matplotlib.pyplot as plt # Camera parameters: FX_DEPTH = 5.8262448167737955e+02 FY_DEPTH = 5.8269103270988637e+02 CX_DEPTH = 3.1304475870804731e+02 CY_DEPTH = 2.3844389626620386e+02 # Read depth image: depth_image = iio.imread('../data/depth_2.png') # Compute the grayscale image: depth_grayscale = np.array(256 * depth_image / 0x0fff, dtype=np.uint8) # Convert a grayscale image to a 3-channel image: depth_grayscale = np.stack((depth_grayscale,) * 3, axis=-1)
要計算一個有組織的點云,我們使用與上一篇教程相同的方法(Python:基于 RGB-D 圖像的點云計算)。我們沒有將深度圖像扁平化,而是將jj和ii重塑為與深度圖像相同的形狀,如下所示:
# get depth image resolution: height, width = depth_image.shape # compute indices and reshape it to have the same shape as the depth image: jj = np.tile(range(width), height).reshape((height, width)) ii = np.repeat(range(height), width).reshape((height, width)) # Compute constants: xx = (jj - CX_DEPTH) / FX_DEPTH yy = (ii - CY_DEPTH) / FY_DEPTH # compute organised point cloud: organized_pcd = np.dstack((xx * depth_image, yy * depth_image, depth_image))
如果你打印出創建的點云的形狀,你可以看到它是一個有3個通道的矩陣(480,640,3)。如果你覺得這個代碼很難理解,請回到之前的教程(Python:基于 RGB-D 圖像的點云計算)。
類似地,我們像上面那樣檢測地面,但不是更新點的顏色并顯示點云,而是更新灰度圖像的像素并顯示它:
# Ground_detection: THRESHOLD = 0.075 * 1000# Define a threshold y_max = max(organized_pcd.reshape((height * width, 3)), key=lambda x: x[1])[ 1]# Get the max value along the y-axis # Set the ground pixels to green: for i in range(height): for j in range(width): if organized_pcd[i][j][1] >= y_max - THRESHOLD: depth_grayscale[i][j] = [0, 255, 0]# Update the depth image # Display depth_grayscale: plt.imshow(depth_grayscale) plt.show()
讀到這里,這篇“如何用Python實現點云的地面檢測”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。