RoboWaiter/robowaiter/proto/camera.py

530 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# enconding = utf8
import json
import string
import sys
import time
import grpc
from sklearn.cluster import DBSCAN
sys.path.append('./')
sys.path.append('../')
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
import GrabSim_pb2_grpc
import GrabSim_pb2
channel = grpc.insecure_channel('localhost:30001', options=[
('grpc.max_send_message_length', 1024 * 1024 * 1024),
('grpc.max_receive_message_length', 1024 * 1024 * 1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
objects_dic = {}
obstacle_objs_id = [114, 115, 122, 96, 102, 83, 121, 105, 108, 89, 100, 90,
111, 103, 95, 92, 76, 113, 101, 29, 112, 87, 109, 98,
106, 120, 97, 86, 104, 78, 85, 81, 82, 84, 91, 93, 94,
99, 107, 116, 117, 118, 119, 255, 251]
not_key_objs_id = {255,254,253,107,81}
'''
初始化,卸载已经加载的关卡,清除所有机器人
'''
def Init():
sim_client.Init(GrabSim_pb2.NUL())
'''
获取当前可加载的地图信息(地图名字、地图尺寸)
'''
def AcquireAvailableMaps():
AvailableMaps = sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL())
print(AvailableMaps)
'''
1、根据mapID加载指定地图
2、如果scene_num>1,则根据地图尺寸偏移后加载多个相同地图
3、这样就可以在一个关卡中训练多个地图
'''
def SetWorld(map_id=0, scene_num=1):
print('------------------SetWorld----------------------')
world = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
'''
返回场景的状态信息
1、返回机器人的位置和旋转
2、返回各个关节的名字和旋转
3、返回场景中标记的物品信息(名字、类型、位置、旋转)
4、返回场景中行人的信息(名字、位置、旋转、速度)
5、返回机器人手指和双臂的碰撞信息
'''
def Observe(scene_id=0):
print('------------------show_env_info----------------------')
scene = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
print(
f"location:{[scene.location]}, rotation:{scene.rotation}\n",
f"joints number:{len(scene.joints)}, fingers number:{len(scene.fingers)}\n",
f"objects number: {len(scene.objects)}, walkers number: {len(scene.walkers)}\n"
f"timestep:{scene.timestep}, timestamp:{scene.timestamp}\n"
f"collision:{scene.collision}, info:{scene.info}")
return scene
'''
重置场景
1、重置桌子的宽度和高度
2、清除生成的行人和物品
3、重置关节角度、位置旋转
4、清除碰撞信息
5、重置场景中标记的物品
'''
def Reset(scene_id=0):
print('------------------Reset----------------------')
scene = sim_client.Reset(GrabSim_pb2.ResetParams(scene=scene_id))
print(scene)
# 如果场景支持调整桌子
# sim_client.Reset(GrabSim_pb2.ResetParams(scene = scene_id, adjust = True, height = 100.0, width = 100.0))"
'''
根据传入的部位名字,获取相机数据
'''
def get_camera(part, scene_id=0):
print('------------------get_camera----------------------')
action = GrabSim_pb2.CameraList(cameras=part, scene=scene_id)
return sim_client.Capture(action)
'''
显示相机画面
'''
def show_image(img_data, scene):
print('------------------show_image----------------------')
im = img_data.images[0]
# 相机内参矩阵
in_matrix = np.array(
[[im.parameters.fx, 0, im.parameters.cx], [0, im.parameters.fy, im.parameters.cy], [0, 0, 1]])
# 相机外参矩阵
out_matrix = np.array(im.parameters.matrix).reshape((4, 4))
# # 旋转矩阵
# rotation_matrix = out_matrix[0:3, 0:3]
#
# # 平移矩阵
# translation_matrix = out_matrix[0:3, -1].reshape(3, 1)
# 像素坐标
# pixel_point = np.array([403, 212, 1]).reshape(3, 1)
pixel_x = 404
pixel_y = 212
depth = 369
# 将像素坐标转换为归一化设备坐标
normalized_x = (pixel_x - im.parameters.cx) / im.parameters.fx
normalized_y = (pixel_y - im.parameters.cy) / im.parameters.fy
# 将归一化设备坐标和深度值转换为相机坐标
camera_x = normalized_x * depth
camera_y = normalized_y * depth
camera_z = depth
# 构建相机坐标向量
camera_coordinates = np.array([camera_x, camera_y, camera_z, 1])
# print("物体相对相机坐标的齐次坐标: ", camera_coordinates)
# 将相机坐标转换为机器人底盘坐标
robot_coordinates = np.dot(out_matrix, camera_coordinates)[:3]
# print("物体的相对底盘坐标为:", robot_coordinates)
# 将物体相对机器人底盘坐标转为齐次坐标
robot_homogeneous_coordinates = np.array([robot_coordinates[0], -robot_coordinates[1], robot_coordinates[2], 1])
# print("物体的相对底盘的齐次坐标为:", robot_homogeneous_coordinates)
# 机器人坐标
X = scene.location.X
Y = scene.location.Y
Z = 0.0
# 机器人旋转信息
Roll = 0.0
Pitch = 0.0
Yaw = scene.rotation.Yaw
# 构建平移矩阵
T = np.array([[1, 0, 0, X],
[0, 1, 0, Y],
[0, 0, 1, Z],
[0, 0, 0, 1]])
# 构建旋转矩阵
Rx = np.array([[1, 0, 0, 0],
[0, np.cos(Roll), -np.sin(Roll), 0],
[0, np.sin(Roll), np.cos(Roll), 0],
[0, 0, 0, 1]])
Ry = np.array([[np.cos(Pitch), 0, np.sin(Pitch), 0],
[0, 1, 0, 0],
[-np.sin(Pitch), 0, np.cos(Pitch), 0],
[0, 0, 0, 1]])
Rz = np.array([[np.cos(np.radians(Yaw)), -np.sin(np.radians(Yaw)), 0, 0],
[np.sin(np.radians(Yaw)), np.cos(np.radians(Yaw)), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
R = np.dot(Rz, np.dot(Ry, Rx))
# 构建机器人的变换矩阵
T_robot = np.dot(T, R)
# print(T_robot)
# 将物体的坐标从机器人底盘坐标系转换到世界坐标系
world_coordinates = np.dot(T_robot, robot_homogeneous_coordinates)[:3]
# print("物体的世界坐标:", world_coordinates)
# 世界偏移后的坐标
world_offest_coordinates = [world_coordinates[0] + 700, world_coordinates[1] + 1400, world_coordinates[2]]
# print("物体世界偏移的坐标: ", world_offest_coordinates)
# world_point = world_coordinates + np.array([])
# print("物体的世界坐标为:", )
# # 相对机器人的世界坐标
# world_point = rotation_matrix.T @ (in_matrix.T * 369 @ pixel_point - translation_matrix)
# print(world_point)
# print(in_matrix @ out_matrix @ obj_world)
#
d = np.frombuffer(im.data, dtype=im.dtype).reshape((im.height, im.width, im.channels))
plt.imshow(d, cmap="gray" if "depth" in im.name.lower() else None)
plt.show()
def transform_co(img_data, pixel_x_, pixel_y_,depth_, scene ,id = 0,label = 0):
im = img_data.images[0]
# 相机外参矩阵
out_matrix = np.array(im.parameters.matrix).reshape((4, 4))
d = np.frombuffer(im.data, dtype=im.dtype).reshape((im.height, im.width, im.channels))
depth = depth_
# 将像素坐标转换为归一化设备坐标
normalized_x = (pixel_x_ - im.parameters.cx) / im.parameters.fx
normalized_y = (pixel_y_ - im.parameters.cy) / im.parameters.fy
# 将归一化设备坐标和深度值转换为相机坐标
camera_x = normalized_x * depth
camera_y = normalized_y * depth
camera_z = depth
# 构建相机坐标向量
camera_coordinates = np.array([camera_x, camera_y, camera_z, 1])
# print("物体相对相机坐标的齐次坐标: ", camera_coordinates)
# 将相机坐标转换为机器人底盘坐标
robot_coordinates = np.dot(out_matrix, camera_coordinates)[:3]
# print("物体的相对底盘坐标为:", robot_coordinates)
# 将物体相对机器人底盘坐标转为齐次坐标
robot_homogeneous_coordinates = np.array([robot_coordinates[0], -robot_coordinates[1], robot_coordinates[2], 1])
# print("物体的相对底盘的齐次坐标为:", robot_homogeneous_coordinates)
# 机器人坐标
X = scene.location.X
Y = scene.location.Y
Z = 0.0
# 机器人旋转信息
Roll = 0.0
Pitch = 0.0
Yaw = scene.rotation.Yaw
# 构建平移矩阵
T = np.array([[1, 0, 0, X],
[0, 1, 0, Y],
[0, 0, 1, Z],
[0, 0, 0, 1]])
# 构建旋转矩阵
Rx = np.array([[1, 0, 0, 0],
[0, np.cos(Roll), -np.sin(Roll), 0],
[0, np.sin(Roll), np.cos(Roll), 0],
[0, 0, 0, 1]])
Ry = np.array([[np.cos(Pitch), 0, np.sin(Pitch), 0],
[0, 1, 0, 0],
[-np.sin(Pitch), 0, np.cos(Pitch), 0],
[0, 0, 0, 1]])
Rz = np.array([[np.cos(np.radians(Yaw)), -np.sin(np.radians(Yaw)), 0, 0],
[np.sin(np.radians(Yaw)), np.cos(np.radians(Yaw)), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
R = np.dot(Rz, np.dot(Ry, Rx))
# 构建机器人的变换矩阵
T_robot = np.dot(T, R)
# print(T_robot)
# 将物体的坐标从机器人底盘坐标系转换到世界坐标系
world_coordinates = np.dot(T_robot, robot_homogeneous_coordinates)[:3]
# if world_coordinates[0] < 200 and world_coordinates[1] <= 1050:
# world_coordinates[0] += 400
# world_coordinates[1] += 400
# elif world_coordinates[0] >= 200 and world_coordinates[1] <= 1050:
# world_coordinates[0] -= 550
# world_coordinates[1] += 400
# elif world_coordinates[0] >= 200 and world_coordinates[1] > 1050:
# world_coordinates[0] -= 550
# world_coordinates[1] -= 1450
# elif world_coordinates[0] < 200 and world_coordinates[1] > 1050:
# world_coordinates[0] += 400
# world_coordinates[1] -= 1450
# print("物体的世界坐标:", world_coordinates)
# 世界偏移后的坐标
world_offest_coordinates = [world_coordinates[0] + 700, world_coordinates[1] + 1400, world_coordinates[2]]
# print("物体世界偏移的坐标: ", world_offest_coordinates)
return world_coordinates
# 世界偏移后的坐标
# world_offest_coordinates = [world_coordinates[0] + 700, world_coordinates[1] + 1400, world_coordinates[2]]
# print("物体世界偏移的坐标: ", world_offest_coordinates)
# dict_f = {'id':id,'label':label,'world_coordinates':world_coordinates,'world_offest_coordinates':world_offest_coordinates}
# with open('./semantic.txt', 'a') as file:
# file.write(str(dict_f) + '\n')
def save_obj_info(img_data, objs_name):
items = img_data.info.split(";")
dictionary = {}
for item in items:
key, value = item.split(":")
dictionary[int(key)] = value
im = img_data.images[0]
d = np.frombuffer(im.data, dtype=im.dtype).reshape((im.height, im.width, im.channels))
arr_flat = d.ravel()
for id in arr_flat:
if id not in dictionary:
print(id)
else:
objs_name.add(dictionary[id])
return objs_name
def get_obstacle_point(plt, db, scene, cur_obstacle_world_points, map_ratio):
cur_obstacle_pixel_points = []
object_pixels = {}
obj_detect_count = 0
cur_objs_id = []
colors = [
'red',
'pink',
'purple',
'blue',
'cyan',
'green',
'yellow',
'orange',
'brown',
'gold',
]
img_data_segment = get_camera([GrabSim_pb2.CameraName.Head_Segment])
img_data_depth = get_camera([GrabSim_pb2.CameraName.Head_Depth])
img_data_color = get_camera([GrabSim_pb2.CameraName.Head_Color])
im_segment = img_data_segment.images[0]
im_depth = img_data_depth.images[0]
im_color = img_data_color.images[0]
d_segment = np.frombuffer(im_segment.data, dtype=im_segment.dtype).reshape((im_segment.height, im_segment.width, im_segment.channels))
d_depth = np.frombuffer(im_depth.data, dtype=im_depth.dtype).reshape((im_depth.height, im_depth.width, im_depth.channels))
d_color = np.frombuffer(im_color.data, dtype=im_color.dtype).reshape((im_color.height, im_color.width, im_color.channels))
items = img_data_segment.info.split(";")
objs_id = {}
for item in items:
key, value = item.split(":")
objs_id[int(key)] = value
objs_id[251] = "walker"
# plt.imshow(d_depth, cmap="gray" if "depth" in im_depth.name.lower() else None)
# plt.show()
plt.subplot(2, 2, 1)
plt.imshow(d_segment, cmap="gray" if "depth" in im_segment.name.lower() else None)
plt.axis("off")
plt.title("相机分割")
# plt.show()
d_depth = np.transpose(d_depth, (1, 0, 2))
d_segment = np.transpose(d_segment, (1, 0, 2))
for i in range(0, d_segment.shape[0], map_ratio):
for j in range(0, d_segment.shape[1], map_ratio):
if d_depth[i][j][0] == 600:
continue
# if d_segment[i][j] == 96:
# print(f"apple的像素坐标({i},{j})")
# print(f"apple的深度{d_depth[i][j][0]}")
# print(f"apple的世界坐标: {transform_co(img_data_depth, i, j, d_depth[i][j][0], scene)}")
# if d_segment[i][j] == 113:
# print(f"kettle的像素坐标({i},{j})")
# print(f"kettle的深度{d_depth[i][j][0]}")
# print(f"kettle的世界坐标: {transform_co(img_data_depth, i, j, d_depth[i][j][0], scene)}")
if d_segment[i][j][0] in obstacle_objs_id:
cur_obstacle_pixel_points.append([i, j])
if d_segment[i][j][0] not in not_key_objs_id:
# 首先检查键是否存在
if d_segment[i][j][0] in object_pixels:
# 如果键存在,那么添加元组(i, j)到对应的值中
object_pixels[d_segment[i][j][0]].append([i, j])
else:
# 如果键不存在那么创建一个新的键值对其中键是d_segment[i][j][0],值是一个包含元组(i, j)的列表
object_pixels[d_segment[i][j][0]] = [[i, j]]
# print(cur_obstacle_pixel_points)
for pixel in cur_obstacle_pixel_points:
world_point = transform_co(img_data_depth, pixel[0], pixel[1], d_depth[pixel[0]][pixel[1]][0], scene)
cur_obstacle_world_points.append([world_point[0], world_point[1]])
# print(f"{pixel}{[world_point[0], world_point[1]]}")
plt.subplot(2, 2, 2)
plt.imshow(d_color, cmap="gray" if "depth" in im_depth.name.lower() else None)
plt.axis('off')
plt.title("目标检测")
# plt.tight_layout()
for key, value in object_pixels.items():
if key == 0 or key not in objs_id.keys():
continue
if key in [91, 84, 96, 87, 102, 106, 120, 85,113, 101, 83, 251]:
X = np.array(value)
db.fit(X)
labels = db.labels_
# 将数据按照聚类标签分组,并打印每个分组的数据
for i in range(max(labels) + 1): # 从0到最大聚类标签的值
group_data = X[labels == i] # 获取当前标签的数据
x_max = max(p[0] for p in group_data)
y_max = max(p[1] for p in group_data)
x_min = min(p[0] for p in group_data)
y_min = min(p[1] for p in group_data)
if x_max - x_min < 10 or y_max - y_min < 10:
continue
if key != 251:
obj_detect_count += 1
cur_objs_id.append(objs_id[key])
# 在指定的位置绘制方框
# 创建矩形框
rect = patches.Rectangle((x_min, y_min), (x_max - x_min), (y_max - y_min), linewidth=1, edgecolor=colors[key % 10],
facecolor='none')
plt.text(x_min, y_min, f'{objs_id[key]}', fontdict={'family': 'serif', 'size': 10, 'color': 'green'}, ha='center',
va='center')
plt.gca().add_patch(rect)
else:
if key != 251:
obj_detect_count += 1
cur_objs_id.append(objs_id[key])
x_max = max(p[0] for p in value)
y_max = max(p[1] for p in value)
x_min = min(p[0] for p in value)
y_min = min(p[1] for p in value)
# 在指定的位置绘制方框
# 创建矩形框
rect = patches.Rectangle((x_min, y_min), (x_max - x_min), (y_max - y_min), linewidth=1, edgecolor=colors[key % 10],
facecolor='none')
plt.text(x_min, y_min, f'{objs_id[key]}', fontdict={'family': 'serif', 'size': 10, 'color': 'green'}, ha='center',
va='center')
plt.gca().add_patch(rect)
# point1 = min(value, key=lambda x: (x[0], x[1]))
# point2 = max(value, key=lambda x: (x[0], x[1]))
# width = point2[1] - point1[1]
# height = point2[0] - point1[0]
# rect = patches.Rectangle((0, 255), 15, 30, linewidth=1, edgecolor='g',
# facecolor='none')
plt.subplot(2, 7, 14) # 这里的2,1表示总共2行1列2表示这个位置是第2个子图
plt.text(0, 0.7, f'检测物体数量:{obj_detect_count}', fontsize=10)
# plt.show()
return cur_obstacle_world_points, cur_objs_id
def get_semantic_map(camera, cur_objs, objs_name):
scene = Observe(0)
objs = scene.objects
img_data = get_camera([camera])
# show_image(img_data, scene)
objs_name = save_obj_info(img_data, objs_name)
for obj_name in list(objs_name):
for obj in objs:
if obj.name == obj_name and obj not in cur_objs:
cur_objs.append(obj)
break
return cur_objs, objs_name
if __name__ == '__main__':
map_id = 11 # 地图编号
scene_num = 1 # 场景数量
cur_objs = []
print('------------ 初始化加载场景 ------------')
Init()
AcquireAvailableMaps()
SetWorld(map_id, scene_num)
time.sleep(5.0)
for i in range(scene_num):
print('------------ 场景操作 ------------')
scene = Observe(i)
Reset(i)
print('------------ 相机捕获 ------------')
Reset(i)
time.sleep(1.0)
# print(get_semantic_map(GrabSim_pb2.CameraName.Head_Segment,cur_objs))
# for camera_name in [GrabSim_pb2.CameraName.Head_Depth]:
# img_data = get_camera([camera_name], i)
# show_image(img_data, scene)
# for camera_name in [GrabSim_pb2.CameraName.Waist_Color, GrabSim_pb2.CameraName.Waist_Depth]:
# img_data = get_camera([camera_name], i)
# show_image(img_data, 2)