Après l’introduction de mesures destinées à assurer sa domination en matière d’intelligence artificielle, l'administration Trump se tourne vers les robots. Le secrétaire au Commerce Howard Lutnick procède à des rencontres avec les PDG de l'industrie robotique et s'est même déjà engagé à fond dans l'accélération du développement de ce secteur.L’administration Trump envisage de publier un décret sur la robotique l'année prochaine. Le secrétaire au Commerce Howard Lutnick déclare à ce propos que : « Nous nous engageons en faveur de la robotique et de la fabrication de pointe, car elles sont essentielles pour ramener la production critique aux États-Unis. » Le Département des Transports s'apprête également à annoncer la création d'un groupe de travail sur la robotique, probablement avant la fin de l'année.
Secretary Lutnick addressed my exclusive reporting today about the Trump administration focusing on robotics.
— Yasmin Khorram (@YasminKhorram) December 3, 2025
Full story: https://t.co/XriGUcUikN pic.twitter.com/kvbypxDRma
Le PDG de l’entreprise américaine Nvidia reconnait que les concurrents chinois en matière d'intelligence artificeille sont devenus « redoutables »
Les États-Unis ont pris des mesures rigoureuses pour ralentir l'industrie technologique chinoise. Ces mesures comprennent des restrictions à l'exportation, des sanctions contre les entreprises chinoises, la limitation de la coopération, etc. Pourtant, la Chine ne cesse d’aller de l’avant en matière d’intelligence artificielle. Elle surpasse même les États-Unis dans certains domaines. Le PDG de Nvidia, Jensen Huang, déclare à ce propos que les rivaux chinois ont évolué et sont devenus « assez redoutables ». Dans le même temps, il estime que les droits de douane controversés imposés par Donald Trump pour réindustrialiser les États-Unis constituent une « vision incroyable ».
Dans une entretien accordé à Bloomberg, Jensen Huang souligne que les rivaux chinois comblent le vide laissé par les entreprises américaines contraintes d'abandonner ce marché en raison des restrictions commerciales imposées par les États-Unis. Les analystes avertissent depuis des années que les restrictions américaines pourraient avoir un effet inverse à celui recherché, en favorisant l'innovation et en consolidant le pouvoir des géants chinois.
Le géant chinois Huawei qui figurait sur la liste noire du gouvernement américain est devenu « tout à fait redoutable », indique-t-il. Jensen Huang a affirmé : « comme tout le monde, ils doublent, voire quadruplent leurs capacités chaque année. Et le volume augmente considérablement ».
Jensen Huang a souligné que l'écart entre les performances des produits américains et leurs alternatives chinoises se réduit. La dernière puce d'IA de Huawei offre des « performances similaires » à celles de la puce H200 de Nvidia, un composant qui était à la pointe de la technologie jusqu'à son remplacement ces derniers mois. En vertu des restrictions, Nvidia ne peut pas expédier sa puce H20 en Chine. Ce composant clé est une version dégradée du H200.
Jensen Huang explique à propos de cette puce : « il n'est pas possible de dégrader davantage les capacités du produit. Nvidia envisage des alternatives potentielles au H20, mais n'a pas de puce prévue pour l'instant. Lorsqu'elle le fera, l'entreprise devra demander l'autorisation de Washington. Il ne faut pas sous-estimer l'importance du marché chinois. C'est là que se trouve la plus grande population de chercheurs en intelligence artificielle au monde ».
Selon plusieurs rapports, l'industrie chinoise se tourne de plus en plus vers les alternatives offertes par Huawei. Ainsi, les restrictions américaines pourraient non seulement favoriser la Chine dans la course mondiale à l'IA, mais aussi transformer Huawei en une puissance mondiale en matière de puce d'intelligence artificielle.
De nombreux indicateurs laissent penser que la Chine a une longueur d’avance considérable sur les Etats-Unis en matière de robotique
Les Etats-Unis et la Chine sont engagés dans une course à l'armement de robots à 4 pattes pour des applications militaires. En 2024, l'armée chinoise a récemment dévoilé un nouveau type de compagnon de combat pour ses soldats : un robot-chien avec une mitrailleuse attachée à son dos.
Dans une vidéo diffusée par l'agence de presse gouvernementale CCTV, on voit des membres des militaires chinois opérer sur un champ de tir aux côtés d'un robot à quatre pattes sur lequel est monté ce qui semble être une variante du fusil d'assaut QBZ-95 de 5,8 x 42 mm, dans le cadre des récents exercices militaires conjoints Golden Dragon 24 menés par la Chine et le Cambodge dans le golfe de Thaïlande.
Dans un scénario, les soldats chinois se tiennent de part et d'autre d'une porte tandis que le chien robot pénètre dans le bâtiment devant eux ; dans un autre, le robot tire une rafale de balles alors qu'il avance sur une cible.
« Il peut servir de nouveau membre dans nos opérations de combat urbain, remplaçant nos membres pour mener la reconnaissance, identifier l'ennemi et frapper la cible pendant notre entraînement », rapporte la CCTV des propos d’un soldat chinois montrant le robot en train d'opérer.
Du point de vue du développeur informatique, il s’agit de kits matériel - à la présentation visuelle similaire à celle d’un chien sur pattes – programmable via des API fournies par les constructeurs. C’est au travers de ces dernières, ainsi que d’une série de modules d’extensions, que le développeur peut aller à l’essentiel de l’application à mettre en œuvre.
Ces robots s’appuient à la base sur des applications à de la détection et suivi d’objets. Dans ce cas, il y a au préalable collecte des images provenant de caméras avant puis détection d’objet sur une classe spécifiée. Cette détection utilise Tensorflow via le tensorflow_object_detector. Il accepte n'importe quel modèle Tensorflow et permet au développeur de spécifier un sous-ensemble de classes de détection incluses dans le modèle. Il effectue cet ensemble d'opérations pour un nombre prédéfini d'itérations, en bloquant pendant une durée prédéfinie entre chaque itération. L'application détermine ensuite l'emplacement de la détection la plus fiable de la classe spécifiée et se dirige vers l'objet.
L’application est organisée en trois ensembles de processus Python communiquant avec le robot Spot. Le diagramme des processus est illustré ci-dessous. Le processus principal communique avec le robot Spot via GRPC et reçoit constamment des images. Ces images sont poussées dans la RAW_IMAGES_QUEUE et lues par les processus Tensorflow. Ces processus détectent des objets dans les images et poussent l'emplacement dans PROCESSED_BOXES_QUEUE. Le thread principal détermine alors l'emplacement de l'objet et envoie des commandes au robot pour qu'il se dirige vers l'objet.
[CODE=Python]# Copyright (c) 2023 Boston Dynamics, Inc. All rights reserved.
#
# Downloading, reproducing, distributing or otherwise using the SDK Software
# is subject to the terms and conditions of the Boston Dynamics Software
# Development Kit License (20191101-BDSDK-SL).
"""Tutorial to show how to use the Boston Dynamics API to detect and follow an object"""
import argparse
import io
import json
import math
import os
import signal
import sys
import time
from multiprocessing import Barrier, Process, Queue, Value
from queue import Empty, Full
from threading import BrokenBarrierError, Thread
import cv2
import numpy as np
from PIL import Image
from scipy import ndimage
from tensorflow_object_detection import DetectorAPI
import bosdyn.client
import bosdyn.client.util
from bosdyn import geometry
from bosdyn.api import geometry_pb2 as geo
from bosdyn.api import image_pb2, trajectory_pb2
from bosdyn.api.image_pb2 import ImageSource
from bosdyn.api.spot import robot_command_pb2 as spot_command_pb2
from bosdyn.client.async_tasks import AsyncPeriodicQuery, AsyncTasks
from bosdyn.client.frame_helpers import (GROUND_PLANE_FRAME_NAME, VISION_FRAME_NAME, get_a_tform_b,
get_vision_tform_body)
from bosdyn.client.image import ImageClient
from bosdyn.client.lease import LeaseClient, LeaseKeepAlive
from bosdyn.client.math_helpers import Quat, SE3Pose
from bosdyn.client.robot_command import (CommandFailedError, CommandTimedOutError,
RobotCommandBuilder, RobotCommandClient, blocking_stand)
from bosdyn.client.robot_state import RobotStateClient
LOGGER = bosdyn.client.util.get_logger()
SHUTDOWN_FLAG = Value('i', 0)
# Don't let the queues get too backed up
QUEUE_MAXSIZE = 10
# This is a multiprocessing.Queue for communication between the main process and the
# Tensorflow processes.
# Entries in this queue are in the format:
# {
# 'source': Name of the camera,
# 'world_tform_cam': transform from VO to camera,
# 'world_tform_gpe': transform from VO to ground plane,
# 'raw_image_time': Time when the image was collected,
# 'cv_image': The decoded image,
# 'visual_dims': (cols, rows),
# 'depth_image': depth image proto,
# 'system_cap_time': Time when the image was received by the main process,
# 'image_queued_time': Time when the image was done preprocessing and queued
# }
RAW_IMAGES_QUEUE = Queue(QUEUE_MAXSIZE)
# This is a multiprocessing.Queue for communication between the Tensorflow processes and
# the bbox print process. This is meant for running in a containerized environment with no access
# to an X display
# Entries in this queue have the following fields in addition to those in :
# {
# 'processed_image_start_time': Time when the image was received by the TF process,
# 'processed_image_end_time': Time when the image was processing for bounding boxes
# 'boxes': list of detected bounding boxes for the processed image
# 'classes': classes of objects,
# 'scores': confidence scores,
# }
PROCESSED_BOXES_QUEUE = Queue(QUEUE_MAXSIZE)
# Barrier for waiting on Tensorflow processes to start, initialized in main()
TENSORFLOW_PROCESS_BARRIER = None
COCO_CLASS_DICT = {
1: 'person',
2: 'bicycle',
3: 'car',
4: 'motorcycle',
5: 'airplane',
6: 'bus',
7: 'train',
8: 'truck',
9: 'boat',
10: 'trafficlight',
11: 'firehydrant',
13: 'stopsign',
14: 'parkingmeter',
15: 'bench',
16: 'bird',
17: 'cat',
18: 'dog',
19: 'horse',
20: 'sheep',
21: 'cow',
22: 'elephant',
23: 'bear',
24: 'zebra',
25: 'giraffe',
27: 'backpack',
28: 'umbrella',
31: 'handbag',
32: 'tie',
33: 'suitcase',
34: 'frisbee',
35: 'skis',
36: 'snowboard',
37: 'sportsball',
38: 'kite',
39: 'baseballbat',
40: 'baseballglove',
41: 'skateboard',
42: 'surfboard',
43: 'tennisracket',
44: 'bottle',
46: 'wineglass',
47: 'cup',
48: 'fork',
49: 'knife',
50: 'spoon',
51: 'bowl',
52: 'banana',
53: 'apple',
54: 'sandwich',
55: 'orange',
56: 'broccoli',
57: 'carrot',
58: 'hotdog',
59: 'pizza',
60: 'donut',
61: 'cake',
62: 'chair',
63: 'couch',
64: 'pottedplant',
65: 'bed',
67: 'diningtable',
70: 'toilet',
72: 'tv',
73: 'laptop',
74: 'mouse',
75: 'remote',
76: 'keyboard',
77: 'cellphone',
78: 'microwave',
79: 'oven',
80: 'toaster',
81: 'sink',
82: 'refrigerator',
84: 'book',
85: 'clock',
86: 'vase',
87: 'scissors',
88: 'teddybear',
89: 'hairdrier',
90: 'toothbrush'
}
# Mapping from visual to depth data
VISUAL_SOURCE_TO_DEPTH_MAP_SOURCE = {
'frontleft_fisheye_image': 'frontleft_depth_in_visual_frame',
'frontright_fisheye_image': 'frontright_depth_in_visual_frame'
}
ROTATION_ANGLES = {
'back_fisheye_image': 0,
'frontleft_fisheye_image': -78,
'frontright_fisheye_image': -102,
'left_fisheye_image': 0,
'right_fisheye_image': 180
}
def _update_thread(async_task):
while True:
async_task.update()
time.sleep(0.01)
class AsyncImage(AsyncPeriodicQuery):
"""Grab image."""
def __init__(self, image_client, image_sources):
# Period is set to be about 15 FPS
super(AsyncImage, self).__init__('images', image_client, LOGGER, period_sec=0.067)
self.image_sources = image_sources
def _start_query(self):
return self._client.get_image_from_sources_async(self.image_sources)
class AsyncRobotState(AsyncPeriodicQuery):
"""Grab robot state."""
def __init__(self, robot_state_client):
# period is set to be about the same rate as detections on the CORE AI
super(AsyncRobotState, self).__init__('robot_state', robot_state_client, LOGGER,
period_sec=0.02)
def _start_query(self):
return self._client.get_robot_state_async()
def get_source_list(image_client):
"""Gets a list of image sources and filters based on config dictionary
Args:
image_client: Instantiated image client
"""
# We are using only the visual images with their corresponding depth sensors
sources = image_client.list_image_sources()
source_list = []
for source in sources:
if source.image_type == ImageSource.IMAGE_TYPE_VISUAL:
# only append if sensor has corresponding depth sensor
if source.name in VISUAL_SOURCE_TO_DEPTH_MAP_SOURCE:
source_list.append(source.name)
source_list.append(VISUAL_SOURCE_TO_DEPTH_MAP_SOURCE[source.name])
return source_list
def capture_images(image_task, sleep_between_capture):
""" Captures images and places them on the queue
Args:
image_task (AsyncImage): Async task that provides the images response to use
sleep_between_capture (float): Time to sleep between each image capture
"""
while not SHUTDOWN_FLAG.value:
get_im_resp = image_task.proto
start_time = time.time()
if not get_im_resp:
continue
depth_responses = {
img.source.name: img
for img in get_im_resp
if img.source.image_type == ImageSource.IMAGE_TYPE_DEPTH
}
entry = {}
for im_resp in get_im_resp:
if im_resp.source.image_type == ImageSource.IMAGE_TYPE_VISUAL:
source = im_resp.source.name
depth_source = VISUAL_SOURCE_TO_DEPTH_MAP_SOURCE[source]
depth_image = depth_responses[depth_source]
acquisition_time = im_resp.shot.acquisition_time
image_time = acquisition_time.seconds + acquisition_time.nanos * 1e-9
try:
image = Image.open(io.BytesIO(im_resp.shot.image.data))
source = im_resp.source.name
image = ndimage.rotate(image, ROTATION_ANGLES[source])
if im_resp.shot.image.pixel_format == image_pb2.Image.PIXEL_FORMAT_GREYSCALE_U8:
image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) # Converted to RGB for TF
tform_snapshot = im_resp.shot.transforms_snapshot
frame_name = im_resp.shot.frame_name_image_sensor
world_tform_cam = get_a_tform_b(tform_snapshot, VISION_FRAME_NAME, frame_name)
world_tform_gpe = get_a_tform_b(tform_snapshot, VISION_FRAME_NAME,
GROUND_PLANE_FRAME_NAME)
entry[source] = {
'source': source,
'world_tform_cam': world_tform_cam,
'world_tform_gpe': world_tform_gpe,
'raw_image_time': image_time,
'cv_image': image,
'visual_dims': (im_resp.shot.image.cols, im_resp.shot.image.rows),
'depth_image': depth_image,
'system_cap_time': start_time,
'image_queued_time': time.time()
}
except Exception as exc: # pylint: disable=broad-except
print(f'Exception occurred during image capture {exc}')
try:
RAW_IMAGES_QUEUE.put_nowait(entry)
except Full as exc:
print(f'RAW_IMAGES_QUEUE is full: {exc}')
time.sleep(sleep_between_capture)
def start_tensorflow_processes(num_processes, model_path, detection_class, detection_threshold,
max_processing_delay):
"""Starts Tensorflow processes in parallel.
It does not keep track of the processes once they are started because they run indefinitely
and are never joined back to the main process.
Args:
num_processes (int): Number of Tensorflow processes to start in parallel.
model_path (str): Filepath to the Tensorflow model to use.
detection_class (int): Detection class to detect
detection_threshold (float): Detection threshold to apply to all Tensorflow detections.
max_processing_delay (float): Allowed delay before processing an incoming image.
"""
processes = []
for _ in range(num_processes):
process = Process(
target=process_images, args=(
model_path,
detection_class,
detection_threshold,
max_processing_delay,
), daemon=True)
process.start()
processes.append(process)
return processes
def process_images(model_path, detection_class, detection_threshold, max_processing_delay):
"""Starts Tensorflow and detects objects in the incoming images.
Args:
model_path (str): Filepath to the Tensorflow model to use.
detection_class (int): Detection class to detect
detection_threshold (float): Detection threshold to apply to all Tensorflow detections.
max_processing_delay (float): Allowed delay before processing an incoming image.
"""
odapi = DetectorAPI(path_to_ckpt=model_path)
num_processed_skips = 0
if TENSORFLOW_PROCESS_BARRIER is None:
return
try:
TENSORFLOW_PROCESS_BARRIER.wait()
except BrokenBarrierError as exc:
print(f'Error waiting for Tensorflow processes to initialize: {exc}')
return False
while not SHUTDOWN_FLAG.value:
try:
entry = RAW_IMAGES_QUEUE.get_nowait()
except Empty:
time.sleep(0.1)
continue
for _, capture in entry.items():
start_time = time.time()
processing_delay = time.time() - capture['raw_image_time']
if processing_delay > max_processing_delay:
num_processed_skips += 1
print(f'skipped image because it took {processing_delay}')
continue # Skip image due to delay
image = capture['cv_image']
boxes, scores, classes, _ = odapi.process_frame(image)
confident_boxes = []
confident_object_classes = []
confident_scores = []
if len(boxes) == 0:
print('no detections founds')
continue
for box, score, box_class in sorted(zip(boxes, scores, classes), key=lambda x: x[1],
reverse=True):
if score > detection_threshold and box_class == detection_class:
confident_boxes.append(box)
confident_object_classes.append(COCO_CLASS_DICT[box_class])
confident_scores.append(score)
image = cv2.rectangle(image, (box[1], box[0]), (box[3], box[2]), (255, 0, 0), 2)
capture['processed_image_start_time'] = start_time
capture['processed_image_end_time'] = time.time()
capture['boxes'] = confident_boxes
capture['classes'] = confident_object_classes
capture['scores'] = confident_scores
capture['cv_image'] = image
try:
PROCESSED_BOXES_QUEUE.put_nowait(entry)
except Full as exc:
print(f'PROCESSED_BOXES_QUEUE is full: {exc}')
print('tf process ending')
return True
def get_go_to(world_tform_object, robot_state, mobility_params, dist_margin=0.5):
"""Gets trajectory command to a goal location
Args:
world_tform_object (SE3Pose): Transform from vision frame to target object
robot_state (RobotState): Current robot state
mobility_params (MobilityParams): Mobility parameters
dist_margin (float): Distance margin to target
"""
vo_tform_robot = get_vision_tform_body(robot_state.kinematic_state.transforms_snapshot)
print(f'robot pos: {vo_tform_robot}')
delta_ewrt_vo = np.array(
[world_tform_object.x - vo_tform_robot.x, world_tform_object.y - vo_tform_robot.y, 0])
norm = np.linalg.norm(delta_ewrt_vo)
if norm == 0:
return None
delta_ewrt_vo_norm = delta_ewrt_vo / norm
heading = _get_heading(delta_ewrt_vo_norm)
vo_tform_goal = np.array([
world_tform_object.x - delta_ewrt_vo_norm[0] * dist_margin,
world_tform_object.y - delta_ewrt_vo_norm[1] * dist_margin
])
se2_pose = geo.SE2Pose(position=geo.Vec2(x=vo_tform_goal[0], y=vo_tform_goal[1]), angle=heading)
tag_cmd = RobotCommandBuilder.synchro_se2_trajectory_command(se2_pose,
frame_name=VISION_FRAME_NAME,
params=mobility_params)
return tag_cmd
def _get_heading(xhat):
zhat = [0.0, 0.0, 1.0]
yhat = np.cross(zhat, xhat)
mat = np.array([xhat, yhat, zhat]).transpose()
return Quat.from_matrix(mat).to_yaw()
def set_default_body_control():
"""Set default body control params to current body position"""
footprint_R_body = geometry.EulerZXY()
position = geo.Vec3(x=0.0, y=0.0, z=0.0)
rotation = footprint_R_body.to_quaternion()
pose = geo.SE3Pose(position=position, rotation=rotation)
point = trajectory_pb2.SE3TrajectoryPoint(pose=pose)
traj = trajectory_pb2.SE3Trajectory(points=[point])
return spot_command_pb2.BodyControlParams(base_offset_rt_footprint=traj)
def get_mobility_params():
"""Gets mobility parameters for following"""
vel_desired = .75
speed_limit = geo.SE2VelocityLimit(
max_vel=geo.SE2Velocity(linear=geo.Vec2(x=vel_desired, y=vel_desired), angular=.25))
body_control = set_default_body_control()
mobility_params = spot_command_pb2.MobilityParams(vel_limit=speed_limit, obstacle_params=None,
body_control=body_control,
locomotion_hint=spot_command_pb2.HINT_TROT)
return mobility_params
def depth_to_xyz(depth, pixel_x, pixel_y, focal_length, principal_point):
"""Calculate the transform to point in image using camera intrinsics and depth"""
x = depth * (pixel_x - principal_point.x) / focal_length.x
y = depth * (pixel_y - principal_point.y) / focal_length.y
z = depth
return x, y, z
def remove_ground_from_depth_image(raw_depth_image, focal_length, principal_point, world_tform_cam,
world_tform_gpe, ground_tolerance=0.04):
""" Simple ground plane removal algorithm. Uses ground height
and does simple z distance filtering.
Args:
raw_depth_image (np.array): Depth image
focal_length (Vec2): Focal length of camera that produced the depth image
principal_point (Vec2): Principal point of camera that produced the depth image
world_tform_cam (SE3Pose): Transform from VO to camera frame
world_tform_gpe (SE3Pose): Transform from VO to GPE frame
ground_tolerance (float): Distance in meters to add to the ground plane
"""
new_depth_image = raw_depth_image
# same functions as depth_to_xyz, but converted to np functions
indices = np.indices(raw_depth_image.shape)
xs = raw_depth_image * (indices[1] - principal_point.x) / focal_length.x
ys = raw_depth_image * (indices[0] - principal_point.y) / focal_length.y
zs = raw_depth_image
# create xyz point cloud
camera_tform_points = np.stack([xs, ys, zs], axis=2)
# points in VO frame
world_tform_points = world_tform_cam.transform_cloud(camera_tform_points)
# array of booleans where True means the point was below the ground plane plus tolerance
world_tform_points_mask = (world_tform_gpe.z - world_tform_points[:, :, 2]) < ground_tolerance
# remove data below ground plane
new_depth_image[world_tform_points_mask] = 0
return new_depth_image
def get_distance_to_closest_object_depth(x_min, x_max, y_min, y_max, depth_scale, raw_depth_image,
histogram_bin_size=0.50, minimum_number_of_points=10,
max_distance=8.0):
"""Make a histogram of distances to points in the cloud and take the closest distance with
enough points.
Args:
x_min (int): minimum x coordinate (column) of object to find
x_max (int): maximum x coordinate (column) of object to find
y_min (int): minimum y coordinate (row) of object to find
y_max (int): maximum y coordinate (row) of object to find
depth_scale (float): depth scale of the image to convert from sensor value to meters
raw_depth_image (np.array): matrix of depth pixels
histogram_bin_size (float): size of each bin of distances
minimum_number_of_points (int): minimum number of points before returning depth
max_distance (float): maximum distance to object in meters
"""
num_bins = math.ceil(max_distance / histogram_bin_size)
# get a sub-rectangle of the bounding box out of the whole image, then flatten
obj_depths = (raw_depth_image[y_min:y_max, x_min
obj_depths = obj_depths / depth_scale
obj_depths = obj_depths[obj_depths != 0]
hist, hist_edges = np.histogram(obj_depths, bins=num_bins, range=(0, max_distance))
edges_zipped = zip(hist_edges[:-1], hist_edges[1:])
# Iterate over the histogram and return the first distance with enough points.
for entry, edges in zip(hist, edges_zipped):
if entry > minimum_number_of_points:
filtered_depths = obj_depths[(obj_depths > edges[0]) & (obj_depths < edges[1])]
if len(filtered_depths) == 0:
continue
return np.mean(filtered_depths)
return max_distance
def rotate_about_origin_degrees(origin, point, angle):
"""
Rotate a point counterclockwise by a given angle around a given origin.
Args:
origin (tuple): Origin to rotate the point around
point (tuple): Point to rotate
angle (float): Angle in degrees
"""
return rotate_about_origin(origin, point, math.radians(angle))
def rotate_about_origin(origin, point, angle):
"""
Rotate a point counterclockwise by a given angle around a given origin.
Args:
origin (tuple): Origin to rotate the point around
point (tuple): Point to rotate
angle (float): Angle in radians
"""
orig_x, orig_y = origin
pnt_x, pnt_y = point
ret_x = orig_x + math.cos(angle) * (pnt_x - orig_x) - math.sin(angle) * (pnt_y - orig_y)
ret_y = orig_y + math.sin(angle) * (pnt_x - orig_x) + math.cos(angle) * (pnt_y - orig_y)
return int(ret_x), int(ret_y)
def get_object_position(world_tform_cam, world_tform_gpe, visual_dims, depth_image, bounding_box,
rotation_angle):
"""
Extract the bounding box, then find the mode in that region.
Args:
world_tform_cam (SE3Pose): SE3 transform from world to camera frame
visual_dims (Tuple): (cols, rows) tuple from the visual image
depth_image (ImageResponse): From a depth camera corresponding to the visual_image
bounding_box (list): Bounding box from tensorflow
rotation_angle (float): Angle (in degrees) to rotate depth image to match cam image rotation
"""
# Make sure there are two images.
if visual_dims is None or depth_image is None:
# Fail.
return
# Rotate bounding box back to original frame
points = [(bounding_box[1], bounding_box[0]), (bounding_box[3], bounding_box[0]),
(bounding_box[3], bounding_box[2]), (bounding_box[1], bounding_box[2])]
origin = (visual_dims[0] / 2, visual_dims[1] / 2)
points_rot = [rotate_about_origin_degrees(origin, point, rotation_angle) for point in points]
# Get the bounding box corners.
y_min = max(0, min([point[1] for point in points_rot]))
x_min = max(0, min([point[0] for point in points_rot]))
y_max = min(visual_dims[1], max([point[1] for point in points_rot]))
x_max = min(visual_dims[0], max([point[0] for point in points_rot]))
# Check that the bounding box is valid.
if (x_min < 0 or y_min < 0 or x_max > visual_dims[0] or y_max > visual_dims[1]):
print(f'Bounding box is invalid: ({x_min}, {y_min}) | ({x_max}, {y_max})')
print(f'Bounds: ({visual_dims[0]}, {visual_dims[1]})')
return
# Unpack the images.
try:
if depth_image.shot.image.pixel_format == image_pb2.Image.PIXEL_FORMAT_DEPTH_U16:
dtype = np.uint16
else:
dtype = np.uint8
img = np.fromstring(depth_image.shot.image.data, dtype=dtype)
if depth_image.shot.image.format == image_pb2.Image.FORMAT_RAW:
img = img.reshape(depth_image.shot.image.rows, depth_image.shot.image.cols)
else:
img = cv2.imdecode(img, -1)
depth_image_pixels = img
depth_image_pixels = remove_ground_from_depth_image(
depth_image_pixels, depth_image.source.pinhole.intrinsics.focal_length,
depth_image.source.pinhole.intrinsics.principal_point, world_tform_cam, world_tform_gpe)
# Get the depth data from the region in the bounding box.
max_distance = 8.0
depth = get_distance_to_closest_object_depth(x_min, x_max, y_min, y_max,
depth_image.source.depth_scale,...[/1]
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

Partagez-vous les avis des observateurs selon lesquels les Etats-Unis ont déjà perdu la guerre face à la Chine en matière de robotique ? Dans quels autres domaines technologiques ces avis sont-ils susceptibles d'être vérifiés à date ?