In this tutorial we are going to learn how to use pralin/compose to process images stored in a kDB dataset. We will see how to iterate over the images, reduce them in size, and insert them in a new dataset.

We will use a kDB store for the purpose of that tutorial, lets start it with:

kdb store --path tuto_kdb_store --extension kDBSensing

We will use the dataset of images acquired in the water near the Gränsö castle. It can be downloaded and uncompressed with the following command:

curl -o images_sea.kdb_dataset.xz "https://gitlab.liu.se/lks/tutorials_data/-/raw/main/images_sea.kdb_dataset.xz?ref_type=heads&inline=false"
xz -d images_sea.kdb_dataset.xz

The dataset can be imported into the database using the following command:

kdb datasets import --path tuto_kdb_store --filename images_sea.kdb_dataset

Show images from a dataset

The first example that we will look at is how to show the images from a dataset. The full composition is shown bellow

compose:
  parameters:
    kdb_host: !required null
    kdb_port: 1242
    source_dataset_uri: !required null
  process:
    # This create a connection to the kDB database, according to the parameter `kdb_host`
    # and `kdb_port`
    - kdb/create_connection_handle:
        id: connection
        parameters:
          host: !param kdb_host
          port: !param kdb_port
    # This start a query for an image dataset, using the connection and the dataset
    # specified in parameters
    - kdb/sensing/query_image_dataset:
        id: qid
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # This loop over the images in the dataset
    - for_each:
        id: iterate_image
        iterator: qid[0]
        process:
          # This shows the images using OpenCV
          - opencv/highgui/imshow:
              id: imwrite
              inputs: [ "iterate_image[0]"]
              parameters:
                wait_delay: 1000

It requires the two parameters, the kdb_host and the source_dataset_uri. When using ROS, the kdb/create_connection_handle can be replaced with ros_kdb/create_connection_handle to automatically connect to the database (see ROS Computation Server tutorial). When using the Gränsö dataset, and the tuto_kdb_store database, the composition can be started with:

pralin compose --parameters "{ kdb_host: 'tuto_kdb_store', source_dataset_uri: 'http://askco.re/examples#images_granso' }" --

Export images from a dataset

The second example will use OpenCV to write the images to files.

compose:
  variables:
    # This variable will be used to increment the number used to index the file
    counter: &counter [0, 'add[0]']
  parameters:
    kdb_host: !required null
    kdb_port: 1242
    source_dataset_uri: !required null
  process:
    # This create a connection to the kDB database, according to the parameter `kdb_host`
    # and `kdb_port`
    - kdb/create_connection_handle:
        id: connection
        parameters:
          host: !param kdb_host
          port: !param kdb_port
    # This start a query for an image dataset, using the connection and the dataset
    # specified in parameters
    - kdb/sensing/query_image_dataset:
        id: qid
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # This loop over the images in the dataset
    - for_each:
        id: iterate_image
        iterator: qid[0]
        process:
          # This create the filename
          - pralin/values/string/format:
              id: filename
              inputs: [ [*counter] ]
              parameters:
                format: "{:04}.jpg"
          - opencv/imgcodecs/imwrite:
              id: imwrite
              inputs: [ "filename[0]", "iterate_image[0]"]
          - pralin/arithmetic/addition:
              id: add
              inputs: [ *counter, 1]

Show scale down images from a dataset

This example iterate through the images in the dataset, reduce their size and display the results.

compose:
  parameters:
    kdb_host: !required null
    kdb_port: 1242
    source_dataset_uri: !required null
    destination_dataset_uri: !required null
  process:
    # This create a connection to the kDB database, according to the parameter `kdb_host`
    # and `kdb_port`
    - kdb/create_connection_handle:
        id: connection
        parameters:
          host: !param kdb_host
          port: !param kdb_port
    # Query the source dataset
    - kdb/datasets/get:
        id: source_dataset
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # Create the dataset, as a subdataset from the source dataset
    - kdb/datasets/create:
        inputs: ["connection[0]", "source_dataset[0]"]
        parameters:
          uri: !param destination_dataset_uri
    # This start a query for an image dataset, using the connection and the dataset
    # specified in parameters
    - kdb/sensing/query_image_dataset:
        id: qid
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # This loop over the images in the dataset
    - for_each:
        id: iterate_image
        iterator: qid[0]
        process:
          # This resize the image
          - opencv/imgproc/resize:
              id: resize
              inputs: [ "iterate_image[0]"]
              parameterkos:
                scale: 0.25
          # This insert the image in the dataset
          - kdb/sensing/insert_image_in_dataset:
              inputs: [ "connection[0]", "resize[0]"]
              parameters:
                query: !param destination_dataset_uri

Scale down images and save it into a dataset

This example iterate through the images in the dataset, reduce their size and store the results in a new dataset.

compose:
  parameters:
    kdb_host: !required null
    kdb_port: 1242
    source_dataset_uri: !required null
    destination_dataset_uri: !required null
  process:
    # This create a connection to the kDB database, according to the parameter `kdb_host`
    # and `kdb_port`
    - kdb/create_connection_handle:
        id: connection
        parameters:
          host: !param kdb_host
          port: !param kdb_port
    # Query the source dataset
    - kdb/datasets/get:
        id: source_dataset
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # Create the dataset, as a subdataset from the source dataset, since we use a source
    # dataset, we don't  need to specify a type or a geometry as parameter, they will be
    # copied from "source_dataset[0]",  which is `source_dataset_uri`.
    # We specify as parameter `destination_dataset_uri`.
    - kdb/datasets/create:
        inputs: ["connection[0]", "source_dataset[0]"]
        parameters:
          uri: !param destination_dataset_uri
    # This start a query for an image dataset, using the connection and the dataset
    # specified in parameters
    - kdb/sensing/query_image_dataset:
        id: qid
        inputs: ["connection[0]"]
        parameters:
          query: !param source_dataset_uri
    # This loop over the images in the dataset
    - for_each:
        id: iterate_image
        iterator: qid[0]
        process:
          # This shows the images using OpenCV
          - opencv/imgproc/resize:
              id: resize
              inputs: [ "iterate_image[0]"]
              parameters:
                scale: 0.25
          # This save the scale down images in the database, with the
          # `destination_dataset_uri` uri.
          - kdb/sensing/insert_image_in_dataset:
              inputs: [ "connection[0]", "resize[0]"]
              parameters:
                query: !param destination_dataset_uri

When running this composition, you need to specify a value for destination_dataset_uri as parameter. You can check that everything went fine by using the visualisation composition from the beginning of this tutorial.