Image APIs#
Bitte lesen Sie zuerst die allgemeine API-Dokumentation, wenn Sie mit AirSim APIs nicht vertraut sind.
Einzelbild abrufen#
Hier ist ein Beispielcode, um ein einzelnes Bild von der Kamera mit dem Namen "0" abzurufen. Der zurückgegebene Wert sind die Bytes eines Bildes im PNG-Format. Um unkomprimierte Bilder und andere Formate sowie verfügbare Kameras zu erhalten, lesen Sie die folgenden Abschnitte.
Python#
import airsim #pip install airsim
# for car use CarClient()
client = airsim.MultirotorClient()
png_image = client.simGetImage("0", airsim.ImageType.Scene)
# do something with image
C++#
#include "vehicles/multirotor/api/MultirotorRpcLibClient.hpp"
int getOneImage()
{
using namespace msr::airlib;
// for car use CarRpcLibClient
MultirotorRpcLibClient client;
std::vector<uint8_t> png_image = client.simGetImage("0", VehicleCameraBase::ImageType::Scene);
// do something with images
}
Bilder mit mehr Flexibilität abrufen#
Die API simGetImages ist etwas komplexer zu verwenden als die API simGetImage. Sie können beispielsweise die Ansicht der linken Kamera, der rechten Kamera und das Tiefenbild der linken Kamera in einem einzigen API-Aufruf abrufen. Die API simGetImages ermöglicht es Ihnen auch, unkomprimierte Bilder sowie einkanalige Gleitkomma-Bilder (anstelle von 3-kanaligen (RGB), jeweils 8 Bit) zu erhalten.
Python#
import airsim #pip install airsim
# for car use CarClient()
client = airsim.MultirotorClient()
responses = client.simGetImages([
# png format
airsim.ImageRequest(0, airsim.ImageType.Scene),
# uncompressed RGB array bytes
airsim.ImageRequest(1, airsim.ImageType.Scene, False, False),
# floating point uncompressed image
airsim.ImageRequest(1, airsim.ImageType.DepthPlanar, True)])
# do something with response which contains image data, pose, timestamp etc
AirSim-Bilder mit NumPy verwenden#
Wenn Sie NumPy für die Bildbearbeitung verwenden möchten, sollten Sie ein unkomprimiertes RGB-Bild abrufen und es dann wie folgt in NumPy konvertieren:
responses = client.simGetImages([airsim.ImageRequest("0", airsim.ImageType.Scene, False, False)])
response = responses[0]
# get numpy array
img1d = np.fromstring(response.image_data_uint8, dtype=np.uint8)
# reshape array to 4 channel image array H X W X 4
img_rgb = img1d.reshape(response.height, response.width, 3)
# original image is fliped vertically
img_rgb = np.flipud(img_rgb)
# write to png
airsim.write_png(os.path.normpath(filename + '.png'), img_rgb)
Schnelle Tipps#
-
Die API
simGetImagegibt einenbinären String-Literalzurück, was bedeutet, dass Sie ihn einfach in eine Binärdatei schreiben können, um eine .png-Datei zu erstellen. Wenn Sie ihn jedoch anders verarbeiten möchten, können Sie die Hilfsfunktionairsim.string_to_uint8_arrayverwenden. Diese konvertiert den binären String-Literal in ein NumPy uint8 Array. -
Die API
simGetImageskann Anfragen für mehrere Bildtypen von beliebigen Kameras in einem einzigen Aufruf entgegennehmen. Sie können angeben, ob das Bild als PNG komprimiert, als unkomprimiertes RGB oder als Gleitkomma-Array vorliegt. Für PNG-komprimierte Bilder erhalten Sie einenbinären String-Literal. Für Gleitkomma-Arrays erhalten Sie eine Python-Liste von float64. Sie können dieses Gleitkomma-Array mit konvertieren
Sie können Gleitkomma-Arrays auch mit der Funktionairsim.list_to_2d_float_array(response.image_data_float, response.width, response.height)airsim.write_pfm()in .pfm-Dateien (Portable Float Map-Format) speichern. -
Wenn Sie Positions- und Orientierungsinformationen synchron mit einem Aufruf einer der Bild-APIs abfragen möchten, können Sie
client.simPause(True)undclient.simPause(False)verwenden, um die Simulation anzuhalten, während Sie die Bild-API aufrufen und den gewünschten physikalischen Zustand abfragen. Dies stellt sicher, dass der physikalische Zustand unmittelbar nach dem Aufruf der Bild-API unverändert bleibt.
C++#
int getStereoAndDepthImages()
{
using namespace msr::airlib;
typedef VehicleCameraBase::ImageRequest ImageRequest;
typedef VehicleCameraBase::ImageResponse ImageResponse;
typedef VehicleCameraBase::ImageType ImageType;
// for car use
// CarRpcLibClient client;
MultirotorRpcLibClient client;
// get right, left and depth images. First two as png, second as float16.
std::vector<ImageRequest> request = {
//png format
ImageRequest("0", ImageType::Scene),
//uncompressed RGB array bytes
ImageRequest("1", ImageType::Scene, false, false),
//floating point uncompressed image
ImageRequest("1", ImageType::DepthPlanar, true)
};
const std::vector<ImageResponse>& response = client.simGetImages(request);
// do something with response which contains image data, pose, timestamp etc
}
Sofort einsatzbereite vollständige Beispiele#
Python#
Ein vollständigeres, sofort einsatzbereites Beispiel finden Sie im Beispielcode im AirSimClient-Projekt für Multirotoren oder im HelloCar-Beispiel. Dieser Code demonstriert auch einfache Aktivitäten wie das Speichern von Bildern in Dateien oder die Verwendung von numpy zur Bildbearbeitung.
C++#
Ein vollständigeres, sofort einsatzbereites Beispiel finden Sie im Beispielcode im HelloDrone-Projekt für Multirotoren oder im HelloCar-Projekt.
Weitere Beispielcodes finden Sie unter anderen Beispielcodes, die eine angegebene Anzahl von Stereo-Bildern zusammen mit Ground-Truth-Tiefe und Disparität generieren und diese im pfm-Format speichern.
Verfügbare Kameras#
Dies sind die Standardkameras, die in jedem Fahrzeug bereits verfügbar sind. Zusätzlich können Sie Fahrzeuge um weitere Kameras erweitern und externe Kameras, die nicht an ein Fahrzeug gebunden sind, über die Einstellungen hinzufügen.
Auto#
Die Kameras im Auto können in API-Aufrufen unter folgenden Namen angesprochen werden: front_center, front_right, front_left, fpv und back_center. Die FPV-Kamera befindet sich an der Position des Fahrerkopfes im Auto.
Multirotor#
Die Kameras in der Drohne können in API-Aufrufen unter folgenden Namen angesprochen werden: front_center, front_right, front_left, bottom_center und back_center.
Computer Vision Modus#
Die Kameranamen sind die gleichen wie bei Multirotoren.
Abwärtskompatibilität für Kameranamen#
Vor AirSim v1.2 wurden Kameras anstelle von Namen über ID-Nummern angesprochen. Zur Abwärtskompatibilität können Sie die folgenden ID-Nummern für die oben genannten Kameranamen in der gleichen Reihenfolge wie oben verwenden: "0", "1", "2", "3", "4". Zusätzlich ist der Kameraname "" verfügbar, um auf die Standardkamera zuzugreifen, die im Allgemeinen die Kamera "0" ist.
"Computer Vision"-Modus#
Sie können AirSim im sogenannten "Computer Vision"-Modus verwenden. In diesem Modus ist die Physik-Engine deaktiviert und es gibt kein Fahrzeug, nur Kameras (Wenn Sie das Fahrzeug ohne seine Kinematik haben möchten, können Sie den Multirotor-Modus mit der Physik-Engine ExternalPhysicsEngine verwenden). Sie können sich mit der Tastatur bewegen (drücken Sie F1, um Hilfe zu den Tasten zu erhalten). Sie können die Aufnahmetaste drücken, um kontinuierlich Bilder zu generieren. Oder Sie können APIs aufrufen, um Kameras zu bewegen und Bilder aufzunehmen.
Um diesen Modus zu aktivieren, bearbeiten Sie die settings.json, die Sie in Ihrem Dokumente\AirSim-Ordner finden (oder ~/Dokumente/AirSim unter Linux) und stellen Sie sicher, dass die folgenden Werte auf der Stammebene vorhanden sind:
{
"SettingsVersion": 1.2,
"SimMode": "ComputerVision"
}
Hier ist das Python-Codebeispiel zum Bewegen der Kamera und Aufnehmen von Bildern.
Dieser Modus wurde vom UnrealCV-Projekt inspiriert.
Pose im Computer Vision Modus setzen#
Um sich mit APIs durch die Umgebung zu bewegen, können Sie die API simSetVehiclePose verwenden. Diese API nimmt Position und Orientierung entgegen und setzt diese auf das unsichtbare Fahrzeug, an dem sich die Front-Center-Kamera befindet. Alle anderen Kameras bewegen sich mit, wobei die relative Position beibehalten wird. Wenn Sie die Position (oder Orientierung) nicht ändern möchten, setzen Sie einfach die Komponenten der Position (oder Orientierung) auf Gleitkomma-NaN-Werte. simGetVehiclePose ermöglicht das Abrufen der aktuellen Pose. Sie können auch simGetGroundTruthKinematics verwenden, um die kinematischen Größen für die Bewegung zu erhalten. Viele andere nicht-fahrzeugspezifische APIs sind ebenfalls verfügbar, wie z. B. Segmentierungs-APIs, Kollisions-APIs und Kamera-APIs.
Kamera-APIs#
simGetCameraInfo gibt die Pose (im Weltkoordinatensystem, NED-Koordinaten, SI-Einheiten) und das FOV (in Grad) für die angegebene Kamera zurück. Bitte sehen Sie sich das Beispiel zur Verwendung an.
simSetCameraPose setzt die Pose für die angegebene Kamera, wobei eine Eingabepose als Kombination aus relativer Position und einem Quaternion im NED-Rahmen verwendet wird. Die praktische Funktion airsim.to_quaternion() ermöglicht die Konvertierung von Neigung, Rollen und Gieren in ein Quaternion. Um beispielsweise Kamera-0 auf 15 Grad Neigung zu setzen, während die gleiche Position beibehalten wird, können Sie verwenden:
camera_pose = airsim.Pose(airsim.Vector3r(0, 0, 0), airsim.to_quaternion(0.261799, 0, 0)) #PRY in radians
client.simSetCameraPose(0, camera_pose);
simSetCameraFovermöglicht die Änderung des Sichtfelds der Kamera zur Laufzeit.simSetDistortionParams,simGetDistortionParamsermöglichen das Setzen und Abrufen der Verzerrungsparameter K1, K2, K3, P1, P2.
Alle Kamera-APIs nehmen neben den API-spezifischen Parametern drei allgemeine Parameter entgegen: camera_name (str), vehicle_name (str) und external (bool, um die externe Kamera anzuzeigen). Der Kamera- und Fahrzeugname wird verwendet, um die spezifische Kamera abzurufen. Wenn external auf true gesetzt ist, wird der Fahrzeugname ignoriert. Sehen Sie sich auch external_camera.py für Beispiele zur Verwendung dieser APIs an.
Gimbal#
Sie können die Stabilisierung für Neigung, Rollen oder Gieren für jede Kamera über die Einstellungen einstellen.
Bitte sehen Sie sich das Beispiel zur Verwendung an.
Auflösung und Kameraparameter ändern#
Um Auflösung, FOV usw. zu ändern, können Sie settings.json verwenden. Zum Beispiel setzt die folgende Ergänzung in settings.json Parameter für die Szenenerfassung und verwendet den oben beschriebenen "Computer Vision"-Modus. Wenn Sie eine Einstellung weglassen, werden die folgenden Standardwerte verwendet. Weitere Informationen finden Sie in der Einstellungen-Dokumentation. Wenn Sie eine Stereokamera verwenden, ist der Abstand zwischen links und rechts derzeit auf 25 cm festgelegt.
{
"SettingsVersion": 1.2,
"CameraDefaults": {
"CaptureSettings": [
{
"ImageType": 0,
"Width": 256,
"Height": 144,
"FOV_Degrees": 90,
"AutoExposureSpeed": 100,
"MotionBlurAmount": 0
}
]
},
"SimMode": "ComputerVision"
}
Was bedeuten Pixelwerte in verschiedenen Bildtypen?#
Verfügbare ImageType-Werte#
Scene = 0,
DepthPlanar = 1,
DepthPerspective = 2,
DepthVis = 3,
DisparityNormalized = 4,
Segmentation = 5,
SurfaceNormals = 6,
Infrared = 7,
OpticalFlow = 8,
OpticalFlowVis = 9
DepthPlanar und DepthPerspective#
Normalerweise möchten Sie das Tiefenbild als Gleitkommawert abrufen (d. h. pixels_as_float = true setzen) und ImageType = DepthPlanar oder ImageType = DepthPerspective in ImageRequest angeben. Für ImageType = DepthPlanar erhalten Sie die Tiefe in der Kameraebene, d. h. alle Punkte, die parallel zur Kamera sind, haben die gleiche Tiefe. Für ImageType = DepthPerspective erhalten Sie die Tiefe von der Kamera über einen Projektionsstrahl, der auf dieses Pixel trifft. Je nach Anwendungsfall kann die Planartiefe oder die Perspektivtiefe das Ground-Truth-Bild sein, das Sie benötigen. Sie können beispielsweise die perspektivische Tiefe an ROS-Pakete wie depth_image_proc weitergeben, um eine Punktwolke zu generieren. Oder die Planartiefe ist möglicherweise besser mit geschätzten Tiefenbildern kompatibel, die von Stereoalgorithmen wie SGM generiert werden.
DepthVis#
Wenn Sie ImageType = DepthVis in ImageRequest angeben, erhalten Sie ein Bild, das die Tiefenvisualisierung unterstützt. In diesem Fall wird jeder Pixelwert je nach Tiefe in der Kameraebene in Metern von Schwarz zu Weiß interpoliert. Reine weiße Pixel bedeuten eine Tiefe von 100 m oder mehr, während reine schwarze Pixel eine Tiefe von 0 m bedeuten.
DisparityNormalized#
Normalerweise möchten Sie das Disparitätsbild als Gleitkommawert abrufen (d. h. pixels_as_float = true setzen und ImageType = DisparityNormalized in ImageRequest angeben), in diesem Fall ist jedes Pixel (Xl - Xr)/Xmax, was dadurch auf Werte zwischen 0 und 1 normalisiert wird.
Segmentierung#
Wenn Sie ImageType = Segmentation in ImageRequest angeben, erhalten Sie ein Bild, das die Ground-Truth-Segmentierung der Szene liefert. Beim Start weist AirSim jedem im Umfeld verfügbaren Mesh einen Wert von 0 bis 255 zu. Dieser Wert wird dann einer bestimmten Farbe in der Palette zugeordnet. Die RGB-Werte für jede Objekt-ID finden Sie in dieser Datei.
Sie können einem bestimmten Mesh mithilfe von APIs einen bestimmten Wert (begrenzt auf den Bereich 0-255) zuweisen. Zum Beispiel setzt der folgende Python-Code die Objekt-ID für das Mesh namens "Ground" auf 20 in der Blocks-Umgebung und ändert dadurch seine Farbe in der Segmentierungsansicht.
success = client.simSetSegmentationObjectID("Ground", 20);
Der Rückgabewert ist ein boolescher Typ, der Ihnen mitteilt, ob das Mesh gefunden wurde.
Beachten Sie, dass typische Unreal-Umgebungen, wie z. B. Blocks, normalerweise viele andere Meshes enthalten, die dasselbe Objekt ausmachen, z. B. "Ground_2", "Ground_3" und so weiter. Da es mühsam ist, für all diese Meshes eine Objekt-ID festzulegen, unterstützt AirSim auch reguläre Ausdrücke. Der folgende Code weist beispielsweise allen Meshes, deren Namen mit "ground" beginnen (Groß-/Kleinschreibung wird ignoriert), mit nur einer Zeile die ID 21 zu.
success = client.simSetSegmentationObjectID("ground[\w]*", 21, True);
Der Rückgabewert ist true, wenn mindestens ein Mesh durch regulären Ausdruck gefunden wurde.
Es wird empfohlen, mit dieser API ein unkomprimiertes Bild anzufordern, um präzise RGB-Werte für das Segmentierungsbild zu erhalten.
responses = client.simGetImages([ImageRequest(0, AirSimImageType.Segmentation, False, False)])
img1d = np.fromstring(response.image_data_uint8, dtype=np.uint8) #get numpy array
img_rgb = img1d.reshape(response.height, response.width, 3) #reshape array to 3 channel image array H X W X 3
img_rgb = np.flipud(img_rgb) #original image is fliped vertically
#find unique colors
print(np.unique(img_rgb[:,:,0], return_counts=True)) #red
print(np.unique(img_rgb[:,:,1], return_counts=True)) #green
print(np.unique(img_rgb[:,:,2], return_counts=True)) #blue
Ein vollständiges, sofort einsatzbereites Beispiel finden Sie unter segmentation.py.
Objekt-ID zurücksetzen#
Die ID eines Objekts kann auf -1 gesetzt werden, damit es im Segmentierungsbild nicht angezeigt wird.
Wie finde ich Mesh-Namen?#
Um die gewünschte Ground-Truth-Segmentierung zu erhalten, müssen Sie die Namen der Meshes in Ihrer Unreal-Umgebung kennen. Dazu müssen Sie die Unreal-Umgebung im Unreal Editor öffnen und dann die Namen der gewünschten Meshes im World Outliner inspizieren. Zum Beispiel sehen wir hier die Mesh-Namen für den Boden in der Blocks-Umgebung im rechten Bereich des Editors.

Wenn Sie nicht wissen, wie Sie eine Unreal-Umgebung im Unreal Editor öffnen, versuchen Sie, dem Leitfaden für das Erstellen aus dem Quellcode zu folgen.
Sobald Sie sich für die Meshes entschieden haben, die Sie interessieren, notieren Sie sich deren Namen und verwenden Sie die obige API, um deren Objekt-IDs festzulegen. Es gibt einige Einstellungen, um das Verhalten der Objekt-ID-Generierung zu ändern.
Farben für Objekt-IDs ändern#
Derzeit ist die Farbe für jede Objekt-ID wie in dieser Palette festgelegt. Wir werden in Kürze die Möglichkeit hinzufügen, Farben für Objekt-IDs auf gewünschte Werte zu ändern. In der Zwischenzeit können Sie das Segmentierungsbild in Ihrem bevorzugten Bildbearbeitungsprogramm öffnen und die gewünschten RGB-Werte erhalten.
Objekt-IDs beim Start#
Beim Start weist AirSim jedem im Umfeld gefundenen Objekt vom Typ UStaticMeshComponent oder ALandscapeProxy eine Objekt-ID zu. Anschließend wird entweder der Mesh-Name oder der Besitzername (abhängig von den Einstellungen) verwendet, kleingeschrieben, alle Zeichen unter ASCII 97 entfernt (um Zahlen und einige Satzzeichen zu entfernen), der ganzzahlige Wert aller Zeichen summiert und modulo 255 gerechnet, um die Objekt-ID zu generieren. Mit anderen Worten, alle Objekte mit denselben alphabetischen Zeichen erhalten dieselbe Objekt-ID. Diese Heuristik ist einfach und effektiv für viele Unreal-Umgebungen, aber möglicherweise nicht das, was Sie möchten. In diesem Fall verwenden Sie bitte die obigen APIs, um die Objekt-IDs auf Ihre gewünschten Werte zu ändern. Es gibt einige Einstellungen, um dieses Verhalten zu ändern.
Objekt-ID für Mesh abrufen#
Die API simGetSegmentationObjectID ermöglicht es Ihnen, die Objekt-ID für einen gegebenen Mesh-Namen abzurufen.
Infrarot#
Derzeit ist dies nur eine Zuordnung von Objekt-ID zu Graustufen 0-255. Somit wird jeder Mesh mit der Objekt-ID 42 mit der Farbe (42, 42, 42) angezeigt. Weitere Details zum Festlegen von Objekt-IDs finden Sie im Segmentierungsabschnitt. Typischerweise kann ein Rauschfilter auf diesen Bildtyp angewendet werden, um einen etwas realistischeren Effekt zu erzielen. Wir arbeiten noch daran, weitere Infrarotartefakte hinzuzufügen, und Beiträge sind willkommen.
OpticalFlow und OpticalFlowVis#
Diese Bildtypen geben Informationen über die vom Blickwinkel der Kamera wahrgenommene Bewegung zurück. OpticalFlow gibt ein 2-Kanal-Bild zurück, bei dem die Kanäle vx bzw. vy entsprechen. OpticalFlowVis ähnelt OpticalFlow, konvertiert die Flussdaten jedoch in RGB für eine "visuellere" Ausgabe.
Beispielcode#
Ein vollständiges Beispiel für das Setzen von Fahrzeugpositionen an zufälligen Orten und Orientierungen und das anschließende Aufnehmen von Bildern finden Sie unter GenerateImageGenerator.hpp. Dieses Beispiel generiert eine bestimmte Anzahl von Stereo-Bildern und ein Ground-Truth-Disparitätsbild und speichert es im pfm-Format.