Example Program (Bash)

A complete Bash script for detecting fish on images using the Fishial Recognition API.

Dependencies: bc, curl, jq, seq

Usage:

recognize_fish -k <API_KEY_ID> -s <API_SECRET_KEY> <picture-file>

Options:

Flag Description
-h, --help Print help and exit
-k, --key-id Client key ID
-s, --key-secret Client key secret

Sample output:

Fishial Recognition has found 1 fish on the picture.

Fish 1 [137,326 758,495] is:
  - Roach / Rutilus rutilus [certainty 97.00%]
  - Rudd / Scardinius erythrophthalmus [certainty 10.0%]

This means: one fish detected with a bounding box from (137, 326) to (758, 495), matched to two species with the given certainty percentages (they do not necessarily sum to 100%).

Full script source

#!/usr/bin/env bash

set -euo pipefail

DEPENDENCIES=( bc curl jq seq )

print_help()
{
  cat <<HELP

    ---- Fishial Recognition TM command line tool. ----

REQUIREMENTS

    Following tools must be installed in order to run this program:

        ${DEPENDENCIES[*]}

USAGE

    recognize_fish <options> <picture-file>

    Note: this tool is not production grade.  It lacks proper error checks, etc.

OPTIONS

    -h, --help
        Prints this message and exits.

    -k, --key-id
        Client key ID.

    -s, --key-secret
        Client key secret.

OUTPUT

    A program could produce an output similar to this:

        Fishial Recognition has found 1 fish on the picture.

        Fish 1 [137,326 758,495] is:
          - Roach / Rutilus rutilus [certainty 97.00%]
          - Rudd / Scardinius erythrophthalmus [certainty 10.0%]

    Which means that:

        - there is only one fish on that picture
        - a bounding box for a detected fish is defined by two opposite corners
          at points (137, 326) and (758, 495)
        - two species have been matched, roach and rudd, with certainty 97%
          and 10%, respectively (mind that they do not necessarily sum up to
          100%)

EXAMPLES

    recognize_fish --help
    recognize_fish -h

        Prints this message.

    recognize_fish --key-id=abc123 --key-secret=abcd1234 fishpic.jpg
    recognize_fish -k abc123 -s abcd1234 fishpic.jpg

        Requests recognition of fishes pictured on fishipic.jpg.
        Client key "abc123" with secret "abcd1234" will be used.

HELP
}

#### HELPERS ####

err()
{
    echo "$1"
    echo "In order to learn more, run: recognize_fish --help"
    exit 1
}

extract_from_json()
{
  jq --raw-output "$1" <<<"$2"
}

#### ENTRY POINT ####

#### PARSE ARGUMENTS ####

while test $# -gt 0
do
  case "$1" in
    -h|--help)
      print_help
      exit 0
      ;;
    --key-id=*)
      KEY_ID="${1#*=}"
      shift
      ;;
    -k)
      KEY_ID="$2"
      shift
      shift
      ;;
    --key-secret=*)
      KEY_SECRET="${1#*=}"
      shift
      ;;
    -s)
      KEY_SECRET="$2"
      shift
      shift
      ;;
    *)
      PICTURE="$1"
      shift
      ;;
  esac
done

#### CHECK ARGUMENTS ####

if ! [[ -f $PICTURE ]]; then
  err "No picture file has been specified."
fi

#### CHECK DEPENDENCIES ####

for dep in ${DEPENDENCIES[*]}; do
  if ! which -s "$dep"; then
    err "Unsatisfied dependency: $dep"
  fi
done

#### OBTAIN TOKEN ####

echo "Obtaining authorization token..."
echo

D=$(cat <<JSON
  {
    "client_id": "$KEY_ID",
    "client_secret": "$KEY_SECRET"
  }
JSON
)

R=$(
curl --request POST \
  --silent \
  --url "https://api-recognition.fishial.ai/v2/auth" \
  --header 'Content-Type: application/json' \
  --data "$D"
)

AUTH_TOKEN=$(extract_from_json '.access_token' "$R")

if [[ "$AUTH_TOKEN" == 'null' ]]; then
  echo "Authentication has failed!"
  echo "Make sure that API credentials are valid."
  exit 1
fi

AUTH="Authorization: Bearer $AUTH_TOKEN"

echo "Access token: $AUTH_TOKEN"
echo

#### RUN RECOGNITION ####

echo "Requesting fish recognition..."

R=$(
curl --request POST \
  --silent \
  --url "https://api-recognition.fishial.ai/v2/recognize" \
  --header "$AUTH" \
  --header "Content-Type: application/octet-stream" \
  --data-binary "@${PICTURE}"
)

OK=$(extract_from_json '.ok' "$R")
ERROR=$(extract_from_json '.error' "$R")

if [[ "$OK" != 'true' ]]; then
  echo
  echo "Fishial Recognition has failed to recognize the picture!"
  echo "$ERROR"
  exit 1
fi

#### PRINT RESULTS ####

FISH_COUNT=$(extract_from_json '.objects | length' "$R")

echo
echo "Fishial Recognition has found $FISH_COUNT fish on the picture."

if [[ "$FISH_COUNT" -eq 0 ]]; then
  exit 0
fi

for i in $(seq $FISH_COUNT); do
  FISH_DATA=$(extract_from_json ".objects[$(expr $i - 1)]" "$R")

  POINT1=$(extract_from_json '.bbox[0:2] | join(",")' "$FISH_DATA")
  POINT2=$(extract_from_json '.bbox[2:4] | join(",")' "$FISH_DATA")

  echo
  echo "Fish $i [$POINT1 $POINT2] is:"

  for j in $(seq $(extract_from_json '.species | length' "$FISH_DATA")); do
    SPECIES_MATCH=$(extract_from_json ".species[$(expr $j - 1)]" "$FISH_DATA")
    SPECIES_ID=$(extract_from_json ".id" "$SPECIES_MATCH")
    CERTAINTY1=$(extract_from_json ".certainty" "$SPECIES_MATCH")
    CERTAINTY=$(bc <<<"100 * $CERTAINTY1")

    SPECIES_DEFN=$(extract_from_json ".definitions[\"$SPECIES_ID\"]" "$R")
    SPECIES_NAME_SCI=$(extract_from_json ".scientificName" "$SPECIES_DEFN")
    SPECIES_NAME_ENG=$(extract_from_json ".commonName" "$SPECIES_DEFN")

    echo "  - $SPECIES_NAME_ENG / $SPECIES_NAME_SCI [certainty $CERTAINTY%]"
  done
done