Burst images at way points

Hello All,

The Parrot Anafi looks like an exciting drone. I did some initial tests with Olympe and the flight simulator. The simulator was working for some basic motion. To do what I want though, I need to track motion of surface features with sequential images. I need to known the time between sequential images, the drone position, and the camera orientation …

so, I have two questions,

  1. Is it possible to program burst images at a way point and if so could you give a program example ?

  2. Do the image headers have info such as a) GPS position, b) drone attitude, c) camera attitude, and d) the time the image was collected (fractional second not just second).

many thanks
John

Hello John,

Yes, it’s possible! The following example demonstrate how to take a photo burst of 14 image in 1 second. Check the bust_value enum definition for other possible bust configuration) : 14 over 1/2/4 seconds, 10 over 1/2/4 seconds, and 4 over 1/2/4 seconds.

from olympe.messages.camera import (
    set_camera_mode,
    set_photo_mode,
    take_photo,
    photo_progress,
)
import olympe
import os
import re
import requests
import shutil
import tempfile
import xml.etree.ElementTree as ET


# Drone IP
ANAFI_IP = "192.168.42.1"

# Drone web server URL
ANAFI_URL = "http://{}/".format(ANAFI_IP)

# Drone media web API URL
ANAFI_MEDIA_API_URL = ANAFI_URL + "api/v1/media/medias/"

XMP_TAGS_OF_INTEREST = (
    "CameraRollDegree",
    "CameraPitchDegree",
    "CameraYawDegree",
    "CaptureTsUs",
    # NOTE: GPS metadata is only present if the drone has a GPS fix
    # (i.e. they won't be present indoor)
    "GPSLatitude",
    "GPSLongitude",
    "GPSAltitude",
)


def take_photo_burst(drone):
    # take a photo burst and get the associated media_id
    photo_saved = drone(photo_progress(result="photo_saved", _policy="wait"))
    drone(take_photo(cam_id=0)).wait()
    photo_saved.wait()
    media_id = photo_saved.received_events().last().args["media_id"]

    # download the photos associated with this media id
    media_info_response = requests.get(ANAFI_MEDIA_API_URL + media_id)
    media_info_response.raise_for_status()
    download_dir = tempfile.mkdtemp()
    for resource in media_info_response.json()["resources"]:
        image_response = requests.get(ANAFI_URL + resource["url"], stream=True)
        download_path = os.path.join(download_dir, resource["resource_id"])
        image_response.raise_for_status()
        with open(download_path, "wb") as image_file:
            shutil.copyfileobj(image_response.raw, image_file)

        # parse the xmp metadata
        with open(download_path, "rb") as image_file:
            image_data = image_file.read()
            image_xmp_start = image_data.find(b"<x:xmpmeta")
            image_xmp_end = image_data.find(b"</x:xmpmeta")
            image_xmp = ET.fromstring(image_data[image_xmp_start : image_xmp_end + 12])
            for image_meta in image_xmp[0][0]:
                xmp_tag = re.sub(r"{[^}]*}", "", image_meta.tag)
                xmp_value = image_meta.text
                # only print the XMP tags we are interested in
                if xmp_tag in XMP_TAGS_OF_INTEREST:
                    print(resource["resource_id"], xmp_tag, xmp_value)


def setup_photo_burst_mode(drone):
    drone(set_camera_mode(cam_id=0, value="photo")).wait()
    # For the file_format: jpeg is the only available option
    # dng is not supported in burst mode
    drone(
        set_photo_mode(
            cam_id=0,
            mode="burst",
            format="rectilinear",
            file_format="jpeg",
            burst="burst_14_over_1s",
            bracketing="preset_1ev",
            capture_interval=0.0,
        )
    ).wait()


def main(drone):
    drone.connection()
    setup_photo_burst_mode(drone)
    take_photo_burst(drone)


if __name__ == "__main__":
    with olympe.Drone(ANAFI_IP, loglevel=0) as drone:
        main(drone)

To go to a specific GPS coordinate before taking the burst images, you have to use the moveTo command. You should refer to the Moving around - Waiting for a ‘hovering’ flying state user guide section and use the moveTo command instead of the moveBy command.

The example above download the burst images with the drone web API and extract relevant XMP metadata : “CameraRollDegree”, “CameraPitchDegree”, “CameraYawDegree”, “CaptureTsUs”, “GPSLatitude”, “GPSLongitude” and “GPSAltitude”.

Note: GPS metadata is only present if the drone has a GPS fix (i.e. they won’t be present while the drone is indoor).

Regards
Nicolas

Hello I’m working with JP95

I ran the code you posted and it seems like the drone is only saving 1 image instead of 14. I have changed the folder from tempfile.mkdtemp() to ‘images/’ to see that images and I’m getting only 1 which is
100000100010.JPG. Is there suppose to be more images else where and is my output normal? E pomp seems to be an error. Thanks for your help.

output:

(olympe-python3) patrick@patrick-ideapad:~/Desktop/ExamplePrograms$ python GetBurstImages_v0TEST.py
I arsdkctrl: discovery ‘net’: start
I arsdkctrl: discovery ‘net’: add device name=‘ANAFI-G038730’ id=‘PI040416AA8G038730’
I arsdkctrl_net: Sending json:
I arsdkctrl_net: { “arstream2_client_stream_port”: “55004”, “arstream2_client_control_port”: “55005”, “arstream2_supported_metadata_version”: “1”, “controller_name”: “arsdk-ng”, “controller_type”: “desktop”, “d2c_port”: 9988, “device_id”: “”, “qos_mode”: 0 }
I arsdkctrl_net: Received json:
I arsdkctrl_net: { “arstream_fragment_size”: 65000, “arstream_fragment_maximum_number”: 4, “arstream_max_ack_interval”: -1, “c2d_update_port”: 51, “c2d_user_port”: 21, “arstream2_server_stream_port”: 5004, “arstream2_server_control_port”: 5005, “arstream2_max_packet_size”: 1500, “arstream2_max_latency”: 0, “arstream2_max_network_latency”: 200, “arstream2_max_bitrate”: 1500000, “arstream2_parameter_sets”: “TBD”, “status”: 0, “c2d_port”: 2233, “qos_mode”: 0 }
100000100010.JPG CameraRollDegree 0.000000
100000100010.JPG CameraPitchDegree 0.000000
100000100010.JPG CameraYawDegree -3.676739
100000100010.JPG GPSLatitude 0,0N
100000100010.JPG GPSLongitude 0,0E
100000100010.JPG GPSAltitude 0/1
E pomp: fd=26, cb=0x7fc29a4ee970 still in loop
E pomp: fd=25, cb=0x7fc29a4ee970 still in loop
E pomp: fd=23, cb=0x7fc29ad51f50 still in loop
E pomp: fd=22, cb=0x7fc29a4ee970 still in loop
E pomp: fd=21, cb=0x7fc29a4ee970 still in loop
E pomp: fd=20, cb=0x7fc29a4e45b0 still in loop
E pomp: fd=19, cb=0x7fc29a4ee970 still in loop
E pomp: fd=18, cb=0x7fc29a4ee970 still in loop
I arsdkctrl: discovery ‘net’: remove device name=‘ANAFI-G038730’ id=‘PI040416AA8G038730’
I arsdkctrl: internally disconnect device name=‘ANAFI-G038730’ type=ANAFI4K id=‘PI040416AA8G038730’
I arsdkctrl: discovery ‘net’: stop

Okay so I somehow got this working and its taking 14 pictures now. I didn’t do anything except taking the drone out to fly with the app maybe some firmware got updated when I connected the drone to the app.

Also if anyone is trying this don’t have usb connected to your computer accessing the sd card when running the code.