examples: classification example with command line defined labels and class filtering
authorDjordje Senicic <x0157990@ti.com>
Mon, 9 Jul 2018 20:18:58 +0000 (16:18 -0400)
committerDjordje Senicic <x0157990@ti.com>
Mon, 9 Jul 2018 20:18:58 +0000 (16:18 -0400)
Signed-off-by: Djordje Senicic <x0157990@ti.com>
19 files changed:
examples/classification/Makefile [new file with mode: 0644]
examples/classification/classlist.txt [new file with mode: 0644]
examples/classification/clips/test1.mp4 [new file with mode: 0644]
examples/classification/clips/test2.mp4 [new file with mode: 0644]
examples/classification/clips/test3.mp4 [new file with mode: 0644]
examples/classification/findclasses.cpp [new file with mode: 0644]
examples/classification/imagenet.txt [new file with mode: 0644]
examples/classification/images/baseball.jpg [new file with mode: 0644]
examples/classification/images/coffe.jpg [new file with mode: 0644]
examples/classification/images/coffe_pot.jpg [new file with mode: 0644]
examples/classification/images/img2clip.sh [new file with mode: 0644]
examples/classification/images/tennis_ball.jpg [new file with mode: 0644]
examples/classification/labels.txt [new file with mode: 0644]
examples/classification/main.cpp [new file with mode: 0644]
examples/classification/multiple_executors.cpp [new file with mode: 0644]
examples/classification/readme.md [new file with mode: 0644]
examples/classification/stream_config_dogs.txt [new file with mode: 0644]
examples/classification/stream_config_j11_v2.txt [new file with mode: 0644]
examples/classification/tidl-sw-stack-small.png [new file with mode: 0644]

diff --git a/examples/classification/Makefile b/examples/classification/Makefile
new file mode 100644 (file)
index 0000000..507ee00
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of Texas Instruments Incorporated nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+EXE = tidl_classification
+
+include ../make.common
+
+LIBS     += -lopencv_highgui -lopencv_imgcodecs -lopencv_videoio\
+                       -lopencv_imgproc -lopencv_core
+
+SOURCES = main.cpp multiple_executors.cpp findclasses.cpp
+
+$(EXE): $(TIDL_API_LIB) $(HEADERS) $(SOURCES)
+       $(CXX) $(CXXFLAGS) $(SOURCES) $(TIDL_API_LIB) $(LDFLAGS) $(LIBS) -o $@
+
+clean::
+       $(RM) -f $(EXE)
+
diff --git a/examples/classification/classlist.txt b/examples/classification/classlist.txt
new file mode 100644 (file)
index 0000000..a21f165
--- /dev/null
@@ -0,0 +1,13 @@
+coffee_mug
+coffeepot
+tennis_ball
+baseball
+sunglass
+sunglasses
+water_bottle
+pill_bottle
+beer_glass
+fountain_pen
+laptop
+envelope
+notebook
diff --git a/examples/classification/clips/test1.mp4 b/examples/classification/clips/test1.mp4
new file mode 100644 (file)
index 0000000..95d3ce7
Binary files /dev/null and b/examples/classification/clips/test1.mp4 differ
diff --git a/examples/classification/clips/test2.mp4 b/examples/classification/clips/test2.mp4
new file mode 100644 (file)
index 0000000..cb47958
Binary files /dev/null and b/examples/classification/clips/test2.mp4 differ
diff --git a/examples/classification/clips/test3.mp4 b/examples/classification/clips/test3.mp4
new file mode 100644 (file)
index 0000000..6952fab
Binary files /dev/null and b/examples/classification/clips/test3.mp4 differ
diff --git a/examples/classification/findclasses.cpp b/examples/classification/findclasses.cpp
new file mode 100644 (file)
index 0000000..2793295
--- /dev/null
@@ -0,0 +1,85 @@
+
+#include <signal.h>
+#include <getopt.h>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cassert>
+#include <string>
+
+#define MAX_CLASSES 1000
+#define MAX_SELECTED_ITEMS 100
+
+using namespace std;
+
+std::string labels_classes[MAX_CLASSES];
+int IMAGE_CLASSES_NUM = 0;
+int selected_items_size = 0;
+int selected_items[MAX_SELECTED_ITEMS];
+static int get_classindex(std::string str2find)
+{
+  if(selected_items_size >= MAX_SELECTED_ITEMS)
+  {
+     std::cout << "Max number of selected classes is reached! (" << selected_items_size << ")!" << std::endl;
+     return -1;
+  }
+  for (int i = 0; i < IMAGE_CLASSES_NUM; i ++)
+  {
+    if(labels_classes[i].compare(str2find) == 0)
+    {
+      selected_items[selected_items_size ++] = i;
+      return i;
+    }
+  }
+  std::cout << "Not found: " << str2find << std::endl << std::flush;
+  return -1;
+}
+
+int populate_selected_items (char *filename)
+{
+  ifstream file(filename);
+  if(file.is_open())
+  {
+    string inputLine;
+
+    while (getline(file, inputLine) )                 //while the end of file is NOT reached
+    {
+      int res = get_classindex(inputLine);
+      std::cout << "Searching for " << inputLine  << std::endl;
+      if(res >= 0) {
+        std::cout << "Found: " << res << std::endl;
+      } else {
+        std::cout << "Not Found: " << res << std::endl;
+      }
+    }
+    file.close();
+  }
+#if 0
+  std::cout << "==Total of " << selected_items_size << " items!" << std::endl;
+  for (int i = 0; i < selected_items_size; i ++)
+    std::cout << i << ") " << selected_items[i] << std::endl;
+#endif
+  return selected_items_size;
+}
+
+void populate_labels (char *filename)
+{
+  ifstream file(filename);
+  if(file.is_open())
+  {
+    string inputLine;
+
+    while (getline(file, inputLine) )                 //while the end of file is NOT reached
+    {
+      labels_classes[IMAGE_CLASSES_NUM ++] = string(inputLine);
+    }
+    file.close();
+  }
+#if 1
+  std::cout << "==Total of " << IMAGE_CLASSES_NUM << " items!" << std::endl;
+  for (int i = 0; i < IMAGE_CLASSES_NUM; i ++)
+    std::cout << i << ") " << labels_classes[i] << std::endl;
+#endif
+}
+
+
diff --git a/examples/classification/imagenet.txt b/examples/classification/imagenet.txt
new file mode 100644 (file)
index 0000000..9f6d42a
--- /dev/null
@@ -0,0 +1,1000 @@
+tench
+goldfish
+great_white_shark
+tiger_shark
+hammerhead
+electric_ray
+stingray
+cock
+hen
+ostrich
+brambling
+goldfinch
+house_finch
+junco
+indigo_bunting
+robin
+bulbul
+jay
+magpie
+chickadee
+water_ouzel
+kite
+bald_eagle
+vulture
+great_grey_owl
+European_fire_salamander
+common_newt
+eft
+spotted_salamander
+axolotl
+bullfrog
+tree_frog
+tailed_frog
+loggerhead
+leatherback_turtle
+mud_turtle
+terrapin
+box_turtle
+banded_gecko
+common_iguana
+American_chameleon
+whiptail
+agama
+frilled_lizard
+alligator_lizard
+Gila_monster
+green_lizard
+African_chameleon
+Komodo_dragon
+African_crocodile
+American_alligator
+triceratops
+thunder_snake
+ringneck_snake
+hognose_snake
+green_snake
+king_snake
+garter_snake
+water_snake
+vine_snake
+night_snake
+boa_constrictor
+rock_python
+Indian_cobra
+green_mamba
+sea_snake
+horned_viper
+diamondback
+sidewinder
+trilobite
+harvestman
+scorpion
+black_and_gold_garden_spider
+barn_spider
+garden_spider
+black_widow
+tarantula
+wolf_spider
+tick
+centipede
+black_grouse
+ptarmigan
+ruffed_grouse
+prairie_chicken
+peacock
+quail
+partridge
+African_grey
+macaw
+sulphur-crested_cockatoo
+lorikeet
+coucal
+bee_eater
+hornbill
+hummingbird
+jacamar
+toucan
+drake
+red-breasted_merganser
+goose
+black_swan
+tusker
+echidna
+platypus
+wallaby
+koala
+wombat
+jellyfish
+sea_anemone
+brain_coral
+flatworm
+nematode
+conch
+snail
+slug
+sea_slug
+chiton
+chambered_nautilus
+Dungeness_crab
+rock_crab
+fiddler_crab
+king_crab
+American_lobster
+spiny_lobster
+crayfish
+hermit_crab
+isopod
+white_stork
+black_stork
+spoonbill
+flamingo
+little_blue_heron
+American_egret
+bittern
+crane
+limpkin
+European_gallinule
+American_coot
+bustard
+ruddy_turnstone
+red-backed_sandpiper
+redshank
+dowitcher
+oystercatcher
+pelican
+king_penguin
+albatross
+grey_whale
+killer_whale
+dugong
+sea_lion
+Chihuahua
+Japanese_spaniel
+Maltese_dog
+Pekinese
+Shih-Tzu
+Blenheim_spaniel
+papillon
+toy_terrier
+Rhodesian_ridgeback
+Afghan_hound
+basset
+beagle
+bloodhound
+bluetick
+black-and-tan_coonhound
+Walker_hound
+English_foxhound
+redbone
+borzoi
+Irish_wolfhound
+Italian_greyhound
+whippet
+Ibizan_hound
+Norwegian_elkhound
+otterhound
+Saluki
+Scottish_deerhound
+Weimaraner
+Staffordshire_bullterrier
+American_Staffordshire_terrier
+Bedlington_terrier
+Border_terrier
+Kerry_blue_terrier
+Irish_terrier
+Norfolk_terrier
+Norwich_terrier
+Yorkshire_terrier
+wire-haired_fox_terrier
+Lakeland_terrier
+Sealyham_terrier
+Airedale
+cairn
+Australian_terrier
+Dandie_Dinmont
+Boston_bull
+miniature_schnauzer
+giant_schnauzer
+standard_schnauzer
+Scotch_terrier
+Tibetan_terrier
+silky_terrier
+soft-coated_wheaten_terrier
+West_Highland_white_terrier
+Lhasa
+flat-coated_retriever
+curly-coated_retriever
+golden_retriever
+Labrador_retriever
+Chesapeake_Bay_retriever
+German_short-haired_pointer
+vizsla
+English_setter
+Irish_setter
+Gordon_setter
+Brittany_spaniel
+clumber
+English_springer
+Welsh_springer_spaniel
+cocker_spaniel
+Sussex_spaniel
+Irish_water_spaniel
+kuvasz
+schipperke
+groenendael
+malinois
+briard
+kelpie
+komondor
+Old_English_sheepdog
+Shetland_sheepdog
+collie
+Border_collie
+Bouvier_des_Flandres
+Rottweiler
+German_shepherd
+Doberman
+miniature_pinscher
+Greater_Swiss_Mountain_dog
+Bernese_mountain_dog
+Appenzeller
+EntleBucher
+boxer
+bull_mastiff
+Tibetan_mastiff
+French_bulldog
+Great_Dane
+Saint_Bernard
+Eskimo_dog
+malamute
+Siberian_husky
+dalmatian
+affenpinscher
+basenji
+pug
+Leonberg
+Newfoundland
+Great_Pyrenees
+Samoyed
+Pomeranian
+chow
+keeshond
+Brabancon_griffon
+Pembroke
+Cardigan
+toy_poodle
+miniature_poodle
+standard_poodle
+Mexican_hairless
+timber_wolf
+white_wolf
+red_wolf
+coyote
+dingo
+dhole
+African_hunting_dog
+hyena
+red_fox
+kit_fox
+Arctic_fox
+grey_fox
+tabby
+tiger_cat
+Persian_cat
+Siamese_cat
+Egyptian_cat
+cougar
+lynx
+leopard
+snow_leopard
+jaguar
+lion
+tiger
+cheetah
+brown_bear
+American_black_bear
+ice_bear
+sloth_bear
+mongoose
+meerkat
+tiger_beetle
+ladybug
+ground_beetle
+long-horned_beetle
+leaf_beetle
+dung_beetle
+rhinoceros_beetle
+weevil
+fly
+bee
+ant
+grasshopper
+cricket
+walking_stick
+cockroach
+mantis
+cicada
+leafhopper
+lacewing
+dragonfly
+damselfly
+admiral
+ringlet
+monarch
+cabbage_butterfly
+sulphur_butterfly
+lycaenid
+starfish
+sea_urchin
+sea_cucumber
+wood_rabbit
+hare
+Angora
+hamster
+porcupine
+fox_squirrel
+marmot
+beaver
+guinea_pig
+sorrel
+zebra
+hog
+wild_boar
+warthog
+hippopotamus
+ox
+water_buffalo
+bison
+ram
+bighorn
+ibex
+hartebeest
+impala
+gazelle
+Arabian_camel
+llama
+weasel
+mink
+polecat
+black-footed_ferret
+otter
+skunk
+badger
+armadillo
+three-toed_sloth
+orangutan
+gorilla
+chimpanzee
+gibbon
+siamang
+guenon
+patas
+baboon
+macaque
+langur
+colobus
+proboscis_monkey
+marmoset
+capuchin
+howler_monkey
+titi
+spider_monkey
+squirrel_monkey
+Madagascar_cat
+indri
+Indian_elephant
+African_elephant
+lesser_panda
+giant_panda
+barracouta
+eel
+coho
+rock_beauty
+anemone_fish
+sturgeon
+gar
+lionfish
+puffer
+abacus
+abaya
+academic_gown
+accordion
+acoustic_guitar
+aircraft_carrier
+airliner
+airship
+altar
+ambulance
+amphibian
+analog_clock
+apiary
+apron
+ashcan
+assault_rifle
+backpack
+bakery
+balance_beam
+balloon
+ballpoint
+Band_Aid
+banjo
+bannister
+barbell
+barber_chair
+barbershop
+barn
+barometer
+barrel
+barrow
+baseball
+basketball
+bassinet
+bassoon
+bathing_cap
+bath_towel
+bathtub
+beach_wagon
+beacon
+beaker
+bearskin
+beer_bottle
+beer_glass
+bell_cote
+bib
+bicycle-built-for-two
+bikini
+binder
+binoculars
+birdhouse
+boathouse
+bobsled
+bolo_tie
+bonnet
+bookcase
+bookshop
+bottlecap
+bow
+bow_tie
+brass
+brassiere
+breakwater
+breastplate
+broom
+bucket
+buckle
+bulletproof_vest
+bullet_train
+butcher_shop
+cab
+caldron
+candle
+cannon
+canoe
+can_opener
+cardigan
+car_mirror
+carousel
+carpenter's_kit
+carton
+car_wheel
+cash_machine
+cassette
+cassette_player
+castle
+catamaran
+CD_player
+cello
+cellular_telephone
+chain
+chainlink_fence
+chain_mail
+chain_saw
+chest
+chiffonier
+chime
+china_cabinet
+Christmas_stocking
+church
+cinema
+cleaver
+cliff_dwelling
+cloak
+clog
+cocktail_shaker
+coffee_mug
+coffeepot
+coil
+combination_lock
+computer_keyboard
+confectionery
+container_ship
+convertible
+corkscrew
+cornet
+cowboy_boot
+cowboy_hat
+cradle
+crane
+crash_helmet
+crate
+crib
+Crock_Pot
+croquet_ball
+crutch
+cuirass
+dam
+desk
+desktop_computer
+dial_telephone
+diaper
+digital_clock
+digital_watch
+dining_table
+dishrag
+dishwasher
+disk_brake
+dock
+dogsled
+dome
+doormat
+drilling_platform
+drum
+drumstick
+dumbbell
+Dutch_oven
+electric_fan
+electric_guitar
+electric_locomotive
+entertainment_center
+envelope
+espresso_maker
+face_powder
+feather_boa
+file
+fireboat
+fire_engine
+fire_screen
+flagpole
+flute
+folding_chair
+football_helmet
+forklift
+fountain
+fountain_pen
+four-poster
+freight_car
+French_horn
+frying_pan
+fur_coat
+garbage_truck
+gasmask
+gas_pump
+goblet
+go-kart
+golf_ball
+golfcart
+gondola
+gong
+gown
+grand_piano
+greenhouse
+grille
+grocery_store
+guillotine
+hair_slide
+hair_spray
+half_track
+hammer
+hamper
+hand_blower
+hand-held_computer
+handkerchief
+hard_disc
+harmonica
+harp
+harvester
+hatchet
+holster
+home_theater
+honeycomb
+hook
+hoopskirt
+horizontal_bar
+horse_cart
+hourglass
+iPod
+iron
+jack-o'-lantern
+jean
+jeep
+jersey
+jigsaw_puzzle
+jinrikisha
+joystick
+kimono
+knee_pad
+knot
+lab_coat
+ladle
+lampshade
+laptop
+lawn_mower
+lens_cap
+letter_opener
+library
+lifeboat
+lighter
+limousine
+liner
+lipstick
+Loafer
+lotion
+loudspeaker
+loupe
+lumbermill
+magnetic_compass
+mailbag
+mailbox
+maillot
+maillot
+manhole_cover
+maraca
+marimba
+mask
+matchstick
+maypole
+maze
+measuring_cup
+medicine_chest
+megalith
+microphone
+microwave
+military_uniform
+milk_can
+minibus
+miniskirt
+minivan
+missile
+mitten
+mixing_bowl
+mobile_home
+Model_T
+modem
+monastery
+monitor
+moped
+mortar
+mortarboard
+mosque
+mosquito_net
+motor_scooter
+mountain_bike
+mountain_tent
+mouse
+mousetrap
+moving_van
+muzzle
+nail
+neck_brace
+necklace
+nipple
+notebook
+obelisk
+oboe
+ocarina
+odometer
+oil_filter
+organ
+oscilloscope
+overskirt
+oxcart
+oxygen_mask
+packet
+paddle
+paddlewheel
+padlock
+paintbrush
+pajama
+palace
+panpipe
+paper_towel
+parachute
+parallel_bars
+park_bench
+parking_meter
+passenger_car
+patio
+pay-phone
+pedestal
+pencil_box
+pencil_sharpener
+perfume
+Petri_dish
+photocopier
+pick
+pickelhaube
+picket_fence
+pickup
+pier
+piggy_bank
+pill_bottle
+pillow
+ping-pong_ball
+pinwheel
+pirate
+pitcher
+plane
+planetarium
+plastic_bag
+plate_rack
+plow
+plunger
+Polaroid_camera
+pole
+police_van
+poncho
+pool_table
+pop_bottle
+pot
+potter's_wheel
+power_drill
+prayer_rug
+printer
+prison
+projectile
+projector
+puck
+punching_bag
+purse
+quill
+quilt
+racer
+racket
+radiator
+radio
+radio_telescope
+rain_barrel
+recreational_vehicle
+reel
+reflex_camera
+refrigerator
+remote_control
+restaurant
+revolver
+rifle
+rocking_chair
+rotisserie
+rubber_eraser
+rugby_ball
+rule
+running_shoe
+safe
+safety_pin
+saltshaker
+sandal
+sarong
+sax
+scabbard
+scale
+school_bus
+schooner
+scoreboard
+screen
+screw
+screwdriver
+seat_belt
+sewing_machine
+shield
+shoe_shop
+shoji
+shopping_basket
+shopping_cart
+shovel
+shower_cap
+shower_curtain
+ski
+ski_mask
+sleeping_bag
+slide_rule
+sliding_door
+slot
+snorkel
+snowmobile
+snowplow
+soap_dispenser
+soccer_ball
+sock
+solar_dish
+sombrero
+soup_bowl
+space_bar
+space_heater
+space_shuttle
+spatula
+speedboat
+spider_web
+spindle
+sports_car
+spotlight
+stage
+steam_locomotive
+steel_arch_bridge
+steel_drum
+stethoscope
+stole
+stone_wall
+stopwatch
+stove
+strainer
+streetcar
+stretcher
+studio_couch
+stupa
+submarine
+suit
+sundial
+sunglass
+sunglasses
+sunscreen
+suspension_bridge
+swab
+sweatshirt
+swimming_trunks
+swing
+switch
+syringe
+table_lamp
+tank
+tape_player
+teapot
+teddy
+television
+tennis_ball
+thatch
+theater_curtain
+thimble
+thresher
+throne
+tile_roof
+toaster
+tobacco_shop
+toilet_seat
+torch
+totem_pole
+tow_truck
+toyshop
+tractor
+trailer_truck
+tray
+trench_coat
+tricycle
+trimaran
+tripod
+triumphal_arch
+trolleybus
+trombone
+tub
+turnstile
+typewriter_keyboard
+umbrella
+unicycle
+upright
+vacuum
+vase
+vault
+velvet
+vending_machine
+vestment
+viaduct
+violin
+volleyball
+waffle_iron
+wall_clock
+wallet
+wardrobe
+warplane
+washbasin
+washer
+water_bottle
+water_jug
+water_tower
+whiskey_jug
+whistle
+wig
+window_screen
+window_shade
+Windsor_tie
+wine_bottle
+wing
+wok
+wooden_spoon
+wool
+worm_fence
+wreck
+yawl
+yurt
+web_site
+comic_book
+crossword_puzzle
+street_sign
+traffic_light
+book_jacket
+menu
+plate
+guacamole
+consomme
+hot_pot
+trifle
+ice_cream
+ice_lolly
+French_loaf
+bagel
+pretzel
+cheeseburger
+hotdog
+mashed_potato
+head_cabbage
+broccoli
+cauliflower
+zucchini
+spaghetti_squash
+acorn_squash
+butternut_squash
+cucumber
+artichoke
+bell_pepper
+cardoon
+mushroom
+Granny_Smith
+strawberry
+orange
+lemon
+fig
+pineapple
+banana
+jackfruit
+custard_apple
+pomegranate
+hay
+carbonara
+chocolate_sauce
+dough
+meat_loaf
+pizza
+potpie
+burrito
+red_wine
+espresso
+cup
+eggnog
+alp
+bubble
+cliff
+coral_reef
+geyser
+lakeside
+promontory
+sandbar
+seashore
+valley
+volcano
+ballplayer
+groom
+scuba_diver
+rapeseed
+daisy
+yellow_lady's_slipper
+corn
+acorn
+hip
+buckeye
+coral_fungus
+agaric
+gyromitra
+stinkhorn
+earthstar
+hen-of-the-woods
+bolete
+ear
+toilet_tissue
diff --git a/examples/classification/images/baseball.jpg b/examples/classification/images/baseball.jpg
new file mode 100644 (file)
index 0000000..836c5b4
Binary files /dev/null and b/examples/classification/images/baseball.jpg differ
diff --git a/examples/classification/images/coffe.jpg b/examples/classification/images/coffe.jpg
new file mode 100644 (file)
index 0000000..370d93c
Binary files /dev/null and b/examples/classification/images/coffe.jpg differ
diff --git a/examples/classification/images/coffe_pot.jpg b/examples/classification/images/coffe_pot.jpg
new file mode 100644 (file)
index 0000000..5d1b2dc
Binary files /dev/null and b/examples/classification/images/coffe_pot.jpg differ
diff --git a/examples/classification/images/img2clip.sh b/examples/classification/images/img2clip.sh
new file mode 100644 (file)
index 0000000..f79f2d4
--- /dev/null
@@ -0,0 +1,2 @@
+convert ../*.jpg -delay 500 -morph 300 -scale 320x320 %05d.jpg
+ffmpeg -i %05d.jpg -vcodec libx264 -profile:v main -pix_fmt yuv420p  -r 15 test.mp4
diff --git a/examples/classification/images/tennis_ball.jpg b/examples/classification/images/tennis_ball.jpg
new file mode 100644 (file)
index 0000000..9cdd085
Binary files /dev/null and b/examples/classification/images/tennis_ball.jpg differ
diff --git a/examples/classification/labels.txt b/examples/classification/labels.txt
new file mode 100644 (file)
index 0000000..bc6c4a9
--- /dev/null
@@ -0,0 +1,9 @@
+shar_pei
+golden_retriever
+afghan_hound
+dachshund
+german_shepherd
+labrador_retriever
+pomeranian
+rottweiler
+background
diff --git a/examples/classification/main.cpp b/examples/classification/main.cpp
new file mode 100644 (file)
index 0000000..e38376a
--- /dev/null
@@ -0,0 +1,710 @@
+/******************************************************************************
+ * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions are met:
+ *       * Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *       * Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *       * Neither the name of Texas Instruments Incorporated nor the
+ *         names of its contributors may be used to endorse or promote products
+ *         derived from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *   THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <signal.h>
+#include <getopt.h>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cassert>
+#include <string>
+#include <functional>
+#include <queue>
+#include <algorithm>
+#include <time.h>
+#include <memory.h>
+#include <string.h>
+
+#include "executor.h"
+#include "execution_object.h"
+#include "configuration.h"
+
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/videoio.hpp"
+
+//#define TWO_ROIs
+#define LIVE_DISPLAY
+//#define PERF_VERBOSE
+
+//#define RMT_GST_STREAMER
+
+#define MAX_NUM_ROI 4
+
+int live_input = 1;
+char video_clip[320];
+
+#ifdef TWO_ROIs
+#define RES_X 400                                                              
+#define RES_Y 300                                                            
+#define NUM_ROI_X 2                                                     
+#define NUM_ROI_Y 1                                                      
+#define X_OFFSET 0                                                           
+#define X_STEP   176                                                        
+#define Y_OFFSET 52                                                         
+#define Y_STEP   224
+#else
+#define RES_X 244
+#define RES_Y 244                                                            
+#define NUM_ROI_X 1                                                     
+#define NUM_ROI_Y 1                                                      
+#define X_OFFSET 10                                                         
+#define X_STEP   224                                                     
+#define Y_OFFSET 10                                                    
+#define Y_STEP   224
+#endif
+
+int NUM_ROI = NUM_ROI_X * NUM_ROI_Y;
+
+//Temporal averaging
+int TOP_CANDIDATES = 2;
+
+using namespace tidl;
+using namespace cv;
+
+#ifdef LIVE_DISPLAY
+void imagenetCallBackFunc(int event, int x, int y, int flags, void* userdata)
+{
+    if  ( event == EVENT_RBUTTONDOWN )
+    {
+        std::cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << " ... prepare to exit!" << std::endl;
+        exit(0);
+    }
+}
+#endif
+
+static int tf_postprocess(uchar *in, int size, int roi_idx, int frame_idx, int f_id);
+static void tf_preprocess(uchar *out, uchar *in, int size);
+static int ShowRegion(int roi_history[]);
+static int selclass_history[MAX_NUM_ROI][3];  // from most recent to oldest at top indices
+
+bool __TI_show_debug_ = false;
+
+bool RunMultipleExecutors(const std::string& config_file_1,
+                          const std::string& config_file_2,
+                          uint32_t num_devices_available);
+
+bool RunConfiguration(const std::string& config_file, int num_devices,
+                      DeviceType device_type);
+bool RunAllConfigurations(int32_t num_devices, DeviceType device_type);
+
+bool ReadFrame(ExecutionObject&     eo,
+               int                  frame_idx,
+               const Configuration& configuration,
+               std::istream&        input_file);
+
+bool WriteFrame(const ExecutionObject &eo,
+                std::ostream& output_file);
+
+static void ProcessArgs(int argc, char *argv[],
+                        std::string& config_file,
+                        int& num_devices,
+                        DeviceType& device_type);
+
+static void DisplayHelp();
+extern std::string labels_classes[];
+extern int IMAGE_CLASSES_NUM;
+extern int selected_items_size;
+extern int selected_items[];
+extern int populate_selected_items (char *filename);
+extern void populate_labels (char *filename);
+
+static double ms_diff(struct timespec &t0, struct timespec &t1)
+{ return (t1.tv_sec - t0.tv_sec) * 1e3 + (t1.tv_nsec - t0.tv_nsec) / 1e6; }
+
+
+int main(int argc, char *argv[])
+{
+    // Catch ctrl-c to ensure a clean exit
+    signal(SIGABRT, exit);
+    signal(SIGTERM, exit);
+
+    // If there are no devices capable of offloading TIDL on the SoC, exit
+    uint32_t num_dla =
+                Executor::GetNumDevices(DeviceType::EVE);
+    uint32_t num_dsp =
+                Executor::GetNumDevices(DeviceType::DSP);
+    if (num_dla == 0 && num_dsp == 0)
+    {
+        std::cout << "TI DL not supported on this SoC." << std::endl;
+        return EXIT_SUCCESS;
+    }
+
+    // Process arguments
+    std::string config_file;
+    int         num_devices = 1;
+    DeviceType  device_type = DeviceType::EVE;
+    ProcessArgs(argc, argv, config_file, num_devices, device_type);
+
+    bool status = true;
+    if (!config_file.empty()) {
+        std::cout << "Run single configuration: " << config_file << std::endl;
+        status = RunConfiguration(config_file, num_devices, device_type);
+    } else
+    {
+        status = false;
+    }
+
+    if (!status)
+    {
+        std::cout << "tidl FAILED" << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    std::cout << "tidl PASSED" << std::endl;
+    return EXIT_SUCCESS;
+}
+
+bool RunConfiguration(const std::string& config_file, int num_devices,
+                      DeviceType device_type)
+{
+    DeviceIds ids;
+    char imagenet_win[160];
+    for (int i = 0; i < num_devices; i++)
+        ids.insert(static_cast<DeviceId>(i));
+
+    // Read the TI DL configuration file
+    Configuration configuration;
+    bool status = configuration.ReadFromFile(config_file);
+    if (!status)
+    {
+        std::cerr << "Error in configuration file: " << config_file
+                  << std::endl;
+        return false;
+    }
+
+    std::ifstream input_data_file(configuration.inData, std::ios::binary);
+    std::ofstream output_data_file(configuration.outData, std::ios::binary);
+    assert (input_data_file.good());
+    assert (output_data_file.good());
+
+    sprintf(imagenet_win, "Imagenet_%sx%d", (device_type == DeviceType::EVE) ? "EVE" : "DSP", num_devices);
+
+    // Determine input frame size from configuration
+    size_t frame_sz_in = configuration.inWidth * configuration.inHeight *
+                         configuration.inNumChannels * (configuration.inNumChannels == 1 ? 1 : 1);
+    size_t frame_sz_out = configuration.inWidth * configuration.inHeight * 3;
+
+    try
+    {
+        // Create a executor with the approriate core type, number of cores
+        // and configuration specified
+        Executor executor(device_type, ids, configuration);
+
+
+        // Query Executor for set of ExecutionObjects created
+        const ExecutionObjects& execution_objects =
+                                                executor.GetExecutionObjects();
+        int num_eos = execution_objects.size();
+
+        // Allocate input and output buffers for each execution object
+        std::vector<void *> buffers;
+        for (auto &eo : execution_objects)
+        {
+            ArgInfo in  = { ArgInfo(malloc_ddr<char>(frame_sz_in),  frame_sz_in)};
+            ArgInfo out = { ArgInfo(malloc_ddr<char>(frame_sz_out), frame_sz_out)};
+            eo->SetInputOutputBuffer(in, out);
+
+            buffers.push_back(in.ptr());
+            buffers.push_back(out.ptr());
+        }
+
+#ifdef LIVE_DISPLAY
+    if(NUM_ROI > 1) 
+    {
+      for(int i = 0; i < NUM_ROI; i ++) {
+        char tmp_string[80];
+        sprintf(tmp_string, "ROI[%02d]", i);
+        namedWindow(tmp_string, WINDOW_AUTOSIZE | CV_GUI_NORMAL);
+      }
+    }
+    Mat sw_stack_image = imread("/usr/share/ti/tidl/examples/classification/tidl-sw-stack-small.png", IMREAD_COLOR); // Read the file
+    if( sw_stack_image.empty() )                      // Check for invalid input
+    {
+      std::cout <<  "Could not open or find the tidl-sw-stack-small image" << std::endl ;
+    } else {
+      namedWindow( "TIDL SW Stack", WINDOW_AUTOSIZE | CV_GUI_NORMAL ); // Create a window for display.
+      cv::imshow( "TIDL SW Stack", sw_stack_image );                // Show our image inside it.
+    }
+
+    namedWindow("ClassList", WINDOW_AUTOSIZE | CV_GUI_NORMAL);
+    namedWindow(imagenet_win, WINDOW_AUTOSIZE | CV_GUI_NORMAL);
+    //set the callback function for any mouse event
+    setMouseCallback(imagenet_win, imagenetCallBackFunc, NULL);
+
+    Mat classlist_image = cv::Mat::zeros(40 + selected_items_size * 20, 220, CV_8UC3);
+    char tmp_classwindow_string[160];
+    //Erase window
+    classlist_image.setTo(Scalar::all(0));
+
+    for (int i = 0; i < selected_items_size; i ++)
+    {
+      sprintf(tmp_classwindow_string, "%2d) %12s", 1+i, labels_classes[selected_items[i]].c_str());
+      cv::putText(classlist_image, tmp_classwindow_string,
+                  cv::Point(5, 40 + i * 20),
+                  cv::FONT_HERSHEY_COMPLEX_SMALL,
+                  0.75,
+                  cv::Scalar(255,255,255), 1, 8);
+    }
+    cv::imshow("ClassList", classlist_image);
+
+#endif
+    Mat r_frame, r_mframe, r_blend;
+    Mat to_stream;
+    VideoCapture cap;
+
+   if(live_input >= 0)
+   {
+      cap.open(live_input);
+      VideoWriter writer;  // gstreamer
+
+      const double fps = cap.get(CAP_PROP_FPS);
+      const int width  = cap.get(CAP_PROP_FRAME_WIDTH);
+      const int height = cap.get(CAP_PROP_FRAME_HEIGHT);
+      std::cout << "Capture camera with " << fps << " fps, " << width << "x" << height << " px" << std::endl;
+
+#ifdef RMT_GST_STREAMER
+      writer.open(" appsrc ! videoconvert ! video/x-raw, format=(string)NV12, width=(int)640, height=(int)480, framerate=(fraction)30/1 ! \
+                ducatih264enc bitrate=2000 ! queue ! h264parse config-interval=1 ! \
+                mpegtsmux ! udpsink host=158.218.102.235 sync=false port=5000",
+                0,fps,Size(640,480),true);
+
+      if (!writer.isOpened()) {
+        cap.release();
+        std::cerr << "Can't create gstreamer writer. Do you have the correct version installed?" << std::endl;
+        std::cerr << "Print out OpenCV build information" << std::endl;
+        std::cout << getBuildInformation() << std::endl;
+        return false;
+      }
+#endif
+   } else {
+     std::cout << "Video input clip: " << video_clip << std::endl;
+     cap.open(std::string(video_clip));
+      const double fps = cap.get(CAP_PROP_FPS);
+      const int width  = cap.get(CAP_PROP_FRAME_WIDTH);
+      const int height = cap.get(CAP_PROP_FRAME_HEIGHT);
+      std::cout << "Clip with " << fps << " fps, " << width << "x" << height << " px" << std::endl;
+
+   }
+   std::cout << "About to start ProcessFrame loop!!" << std::endl;
+
+
+    Rect rectCrop[NUM_ROI];
+    for (int y = 0; y < NUM_ROI_Y; y ++) {
+      for (int x = 0; x < NUM_ROI_X; x ++) {
+         rectCrop[y * NUM_ROI_X + x] = Rect(X_OFFSET + x * X_STEP, Y_OFFSET + y * Y_STEP, 224, 224);
+         std::cout << "Rect[" << X_OFFSET + x * X_STEP << ", " << Y_OFFSET + y * Y_STEP << "]" << std::endl;
+      }
+    }
+    int num_frames = 99999;
+
+    if (!cap.isOpened()) {
+      std::cout << "Video input not opened!" << std::endl;
+      return false;
+    }
+    Mat in_image, image, r_image, show_image, bgr_frames[3];
+    int is_object;
+    for(int k = 0; k < NUM_ROI; k++) {
+      for(int i = 0; i < 3; i ++) selclass_history[k][i] = -1;
+    }
+
+        #define MAX_NUM_EOS  4
+        struct timespec t0[MAX_NUM_EOS], t1;
+
+        // Process frames with available execution objects in a pipelined manner
+        // additional num_eos iterations to flush the pipeline (epilogue)
+        for (int frame_idx = 0;
+             frame_idx < configuration.numFrames + num_eos; frame_idx++)
+        {
+            ExecutionObject* eo = execution_objects[frame_idx % num_eos].get();
+
+            // Wait for previous frame on the same eo to finish processing
+            if (eo->ProcessFrameWait())
+            {
+                clock_gettime(CLOCK_MONOTONIC, &t1);
+                double elapsed_host =
+                                ms_diff(t0[eo->GetFrameIndex() % num_eos], t1);
+                double elapsed_device = eo->GetProcessTimeInMilliSeconds();
+                double overhead = 100 - (elapsed_device/elapsed_host*100);
+#ifdef PERF_VERBOSE
+                std::cout << "frame[" << eo->GetFrameIndex() << "]: "
+                          << "Time on device: "
+                          << std::setw(6) << std::setprecision(4)
+                          << elapsed_device << "ms, "
+                          << "host: "
+                          << std::setw(6) << std::setprecision(4)
+                          << elapsed_host << "ms ";
+                std::cout << "API overhead: "
+                          << std::setw(6) << std::setprecision(3)
+                          << overhead << " %" << std::endl;
+#endif
+
+             int f_id = eo->GetFrameIndex();
+             int curr_roi = f_id % NUM_ROI;
+             is_object = tf_postprocess((uchar*) eo->GetOutputBufferPtr(), IMAGE_CLASSES_NUM, curr_roi, frame_idx, f_id);
+             selclass_history[curr_roi][2] = selclass_history[curr_roi][1];
+             selclass_history[curr_roi][1] = selclass_history[curr_roi][0];
+             selclass_history[curr_roi][0] = is_object;
+
+             if(is_object >= 0) {
+                  std::cout << "frame[" << eo->GetFrameIndex() << "]: "
+                          << "Time on device: "
+                          << std::setw(6) << std::setprecision(4)
+                          << elapsed_device << "ms, "
+                          << "host: "
+                          << std::setw(6) << std::setprecision(4)
+                          << elapsed_host << "ms ";
+             }
+
+             for (int r = 0; r < NUM_ROI; r ++) 
+             {
+               int rpt_id =  ShowRegion(selclass_history[r]);
+                if(rpt_id >= 0)
+                {
+                  // overlay the display window, if ball seen during last two times
+                  cv::putText(show_image, labels_classes[rpt_id].c_str(),
+                    cv::Point(rectCrop[r].x + 5,rectCrop[r].y + 20), // Coordinates
+                    cv::FONT_HERSHEY_COMPLEX_SMALL, // Font
+                    1.0, // Scale. 2.0 = 2x bigger
+                    cv::Scalar(0,0,255), // Color
+                    1, // Thickness
+                    8); // Line type
+                  cv::rectangle(show_image, rectCrop[r], Scalar(255,0,0), 3);
+                  std::cout << "ROI(" << r << ")(" << rpt_id << ")=" << labels_classes[rpt_id].c_str() << std::endl;
+
+                  classlist_image.setTo(Scalar::all(0));
+                  for (int k = 0; k < selected_items_size; k ++)
+                  {
+                     sprintf(tmp_classwindow_string, "%2d) %12s", 1+k, labels_classes[selected_items[k]].c_str());
+                     cv::putText(classlist_image, tmp_classwindow_string,
+                                 cv::Point(5, 40 + k * 20),
+                                 cv::FONT_HERSHEY_COMPLEX_SMALL,
+                                 0.75,
+                                 selected_items[k] == rpt_id ? cv::Scalar(0,0,255) : cv::Scalar(255,255,255), 1, 8);
+                  }
+                  sprintf(tmp_classwindow_string, "FPS:%5.2lf", (double)num_devices * 1000.0 / elapsed_host );
+                  cv::putText(classlist_image, tmp_classwindow_string,
+                              cv::Point(5, 20),
+                              cv::FONT_HERSHEY_COMPLEX_SMALL,
+                              0.75,
+                              cv::Scalar(0,255,0), 1, 8);
+                  cv::imshow("ClassList", classlist_image);
+               }
+             }
+#ifdef LIVE_DISPLAY
+             cv::imshow(imagenet_win, show_image);
+#endif
+
+#ifdef RMT_GST_STREAMER
+             cv::resize(show_image, to_stream, cv::Size(640,480));
+             writer << to_stream;
+#endif
+
+#ifdef LIVE_DISPLAY
+             waitKey(2);
+#endif
+
+            }
+
+
+        if (cap.grab() && frame_idx < num_frames)
+        {
+            if (cap.retrieve(in_image))
+            {
+                cv::resize(in_image, image, Size(RES_X,RES_Y));
+                r_image = Mat(image, rectCrop[frame_idx % NUM_ROI]);
+
+#ifdef LIVE_DISPLAY
+                if(NUM_ROI > 1)
+                {
+                   char tmp_string[80];
+                   sprintf(tmp_string, "ROI[%02d]", frame_idx % NUM_ROI);
+                   cv::imshow(tmp_string, r_image);
+                }
+#endif
+                //Convert from BGR pixel interleaved to BGR plane interleaved!
+                cv::split(r_image, bgr_frames);
+                tf_preprocess((uchar*) eo->GetInputBufferPtr(), bgr_frames[0].ptr(), 224*224);
+                tf_preprocess((uchar*) eo->GetInputBufferPtr()+224*224, bgr_frames[1].ptr(), 224*224);
+                tf_preprocess((uchar*) eo->GetInputBufferPtr()+2*224*224, bgr_frames[2].ptr(), 224*224);
+                eo->SetFrameIndex(frame_idx);
+                clock_gettime(CLOCK_MONOTONIC, &t0[frame_idx % num_eos]);
+                eo->ProcessFrameStartAsync();
+
+#ifdef RMT_GST_STREAMER
+                cv::resize(Mat(image, Rect(0,32,640,448)), to_stream, Size(640,480));
+                writer << to_stream;
+#endif
+
+#ifdef LIVE_DISPLAY
+                //waitKey(2);
+                image.copyTo(show_image);
+#endif
+            }
+        } else {
+          if(live_input == -1) {
+            //Rewind!
+            cap.release();
+            cap.open(std::string(video_clip)); 
+          }
+        }
+        }
+
+        for (auto b : buffers)
+            __free_ddr(b);
+
+    }
+    catch (tidl::Exception &e)
+    {
+        std::cerr << e.what() << std::endl;
+        status = false;
+    }
+
+
+    input_data_file.close();
+    output_data_file.close();
+
+    return status;
+}
+
+bool ReadFrame(ExecutionObject &eo, int frame_idx,
+               const Configuration& configuration,
+               std::istream& input_file)
+{
+    if (frame_idx >= configuration.numFrames)
+        return false;
+
+    char*  frame_buffer = eo.GetInputBufferPtr();
+    assert (frame_buffer != nullptr);
+
+    memset (frame_buffer, 0,  eo.GetInputBufferSizeInBytes());
+    input_file.read(frame_buffer, eo.GetInputBufferSizeInBytes() / (configuration.inNumChannels == 1 ? 2 : 1));
+
+    if (input_file.eof())
+        return false;
+
+    assert (input_file.good());
+
+    // Set the frame index  being processed by the EO. This is used to
+    // sort the frames before they are output
+    eo.SetFrameIndex(frame_idx);
+
+    if (input_file.good())
+        return true;
+
+    return false;
+}
+
+bool WriteFrame(const ExecutionObject &eo, std::ostream& output_file)
+{
+    output_file.write(
+            eo.GetOutputBufferPtr(), eo.GetOutputBufferSizeInBytes());
+    assert(output_file.good() == true);
+
+    if (output_file.good())
+        return true;
+
+    return false;
+}
+
+void ProcessArgs(int argc, char *argv[], std::string& config_file,
+                 int& num_devices, DeviceType& device_type)
+{
+    const struct option long_options[] =
+    {
+        {"labels_classes_file", required_argument, 0, 'l'},
+        {"selected_classes_file", required_argument, 0, 's'},
+        {"config_file", required_argument, 0, 'c'},
+        {"num_devices", required_argument, 0, 'n'},
+        {"device_type", required_argument, 0, 't'},
+        {"help",        no_argument,       0, 'h'},
+        {"verbose",     no_argument,       0, 'v'},
+        {0, 0, 0, 0}
+    };
+
+    int option_index = 0;
+
+    while (true)
+    {
+        int c = getopt_long(argc, argv, "l:c:s:i:n:t:hv", long_options, &option_index);
+
+        if (c == -1)
+            break;
+
+        switch (c)
+        {
+            case 'l': populate_labels(optarg);
+                      break;
+
+            case 's': populate_selected_items(optarg);
+                      break;
+
+            case 'i': if(strlen(optarg) == 1)
+                      {
+                        live_input = atoi(optarg);
+                      } else {
+                        live_input = -1;
+                        strcpy(video_clip, optarg);
+                      }
+                      break;
+
+            case 'c': config_file = optarg;
+                      break;
+
+            case 'n': num_devices = atoi(optarg);
+                      assert (num_devices > 0 && num_devices <= 4);
+                      break;
+
+            case 't': if (*optarg == 'e')
+                          device_type = DeviceType::EVE;
+                      else if (*optarg == 'd')
+                          device_type = DeviceType::DSP;
+                      else
+                      {
+                          std::cerr << "Invalid argument to -t, only e or d"
+                                       " allowed" << std::endl;
+                          exit(EXIT_FAILURE);
+                      }
+                      break;
+
+            case 'v': __TI_show_debug_ = true;
+                      break;
+
+            case 'h': DisplayHelp();
+                      exit(EXIT_SUCCESS);
+                      break;
+
+            case '?': // Error in getopt_long
+                      exit(EXIT_FAILURE);
+                      break;
+
+            default:
+                      std::cerr << "Unsupported option: " << c << std::endl;
+                      break;
+        }
+    }
+}
+
+void DisplayHelp()
+{
+    std::cout << "Usage: tidl\n"
+                 "  Will run all available networks if tidl is invoked without"
+                 " any arguments.\n  Use -c to run a single network.\n"
+                 "Optional arguments:\n"
+                 " -c                   Path to the configuration file\n"
+                 " -n <number of cores> Number of cores to use (1 - 4)\n"
+                 " -t <d|e>             Type of core. d -> DSP, e -> EVE\n"
+                 " -l                   List of label strings (of all classes in model)\n"
+                 " -s                   List of strings with selected classes\n"
+                 " -i                   Video input (for camera:0,1 or video clip)\n"
+                 " -v                   Verbose output during execution\n"
+                 " -h                   Help\n";
+
+}
+
+
+bool tf_expected_id(int id)
+{
+   // Filter out unexpected IDs
+   for (int i = 0; i < selected_items_size; i ++)
+   {
+       if(id == selected_items[i]) return true;
+   }
+   return false;
+}
+
+int tf_postprocess(uchar *in, int size, int roi_idx, int frame_idx, int f_id)
+{
+  // sort and get k largest values and corresponding indices
+  const int k = TOP_CANDIDATES;
+  int accum_in = 0;
+  int rpt_id = -1;
+
+  typedef std::pair<uchar, int> val_index;
+  auto constexpr cmp = [](val_index &left, val_index &right) { return left.first > right.first; };
+  std::priority_queue<val_index, std::vector<val_index>, decltype(cmp)> queue(cmp);
+  // initialize priority queue with smallest value on top
+  for (int i = 0; i < k; i++) {
+    queue.push(val_index(in[i], i));
+    accum_in += (int)in[i];
+  }
+  // for rest input, if larger than current minimum, pop mininum, push new val
+  for (int i = k; i < size; i++)
+  {
+    if (in[i] > queue.top().first)
+    {
+      queue.pop();
+      queue.push(val_index(in[i], i));
+    }
+    accum_in += (int)in[i];
+  }
+
+  // output top k values in reverse order: largest val first
+  std::vector<val_index> sorted;
+  while (! queue.empty())
+   {
+    sorted.push_back(queue.top());
+    queue.pop();
+  }
+
+  for (int i = k-1; i >= 0; i--)
+  {
+      int id = sorted[i].second;
+      char res2show[320];
+      bool found = false;
+
+      if (tf_expected_id(id))
+      {
+        std::cout << "Frame:" << frame_idx << "," << f_id << " ROI[" << roi_idx << "]: rank="
+                  << k-i << ", prob=" << (float) sorted[i].first / 255 << ", "
+                  << labels_classes[sorted[i].second] << " accum_in=" << accum_in << std::endl;
+        rpt_id = id;
+        found  = true;
+      }
+  }
+  return rpt_id;
+}
+
+void tf_preprocess(uchar *out, uchar *in, int size)
+{
+  for (int i = 0; i < size; i++)
+  {
+    out[i] = (uchar) (in[i] /*- 128*/);
+  }
+}
+
+int ShowRegion(int roi_history[])
+{
+  if((roi_history[0] >= 0) && (roi_history[0] == roi_history[1])) return roi_history[0];    
+  if((roi_history[0] >= 0) && (roi_history[0] == roi_history[2])) return roi_history[0];    
+  if((roi_history[1] >= 0) && (roi_history[1] == roi_history[2])) return roi_history[1];    
+  return -1;
+}
+
+
diff --git a/examples/classification/multiple_executors.cpp b/examples/classification/multiple_executors.cpp
new file mode 100644 (file)
index 0000000..78a1789
--- /dev/null
@@ -0,0 +1,216 @@
+/******************************************************************************
+ * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions are met:
+ *       * Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *       * Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *       * Neither the name of Texas Instruments Incorporated nor the
+ *         names of its contributors may be used to endorse or promote products
+ *         derived from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *   THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+//! @file multiple_executors.cpp
+//! Illustrates how to setup multiple Executor instances using
+//! non-overlapping sets of device ids and running the Executor instances
+//! in parallel - each in its own thread
+
+#include <signal.h>
+#include <getopt.h>
+#include <iostream>
+#include <fstream>
+#include <cassert>
+#include <string>
+#include <functional>
+#include <algorithm>
+#include <pthread.h>
+
+#include "executor.h"
+#include "execution_object.h"
+#include "configuration.h"
+
+using namespace tidl;
+
+extern bool ReadFrame(ExecutionObject&     eo,
+               int                  frame_idx,
+               const Configuration& configuration,
+               std::istream&        input_file);
+
+extern bool WriteFrame(const ExecutionObject &eo,
+                std::ostream& output_file);
+
+void* run_network(void *data);
+
+struct ThreadArg
+{
+    std::string config_file;
+    DeviceIds ids;
+    ThreadArg(const DeviceIds& ids, const std::string& s):
+        ids(ids), config_file(s) {}
+
+};
+
+bool thread_status[2];
+
+bool RunMultipleExecutors(const std::string& config_file_1,
+                          const std::string& config_file_2,
+                          uint32_t num_devices_available)
+{
+    // If there is only 1 device available, skip
+    if (num_devices_available == 1)
+        return true;
+
+    DeviceIds ids1, ids2;
+
+    if (num_devices_available == 4)
+    {
+        ids1 = {DeviceId::ID2, DeviceId::ID3};
+        ids2 = {DeviceId::ID0, DeviceId::ID1};
+    }
+    else
+    {
+        ids1 = {DeviceId::ID0};
+        ids2 = {DeviceId::ID1};
+    }
+
+    // Set up devices and config files for each thread
+    ThreadArg arg1(ids2, config_file_1);
+    ThreadArg arg2(ids1, config_file_2);
+
+    // Run network 1 in a thread
+    std::cout << std::endl << "Multiple Executor..." << std::endl;
+    std::cout << "Running network "
+              << arg1.config_file.substr(arg1.config_file.find("tidl"))
+              << " on EVEs: ";
+    for (DeviceId id : arg1.ids)
+        std::cout << static_cast<int>(id) << " ";
+    std::cout << " in thread 0" << std::endl;
+
+    pthread_t network_thread_1;
+    pthread_create(&network_thread_1, 0, &run_network, &arg1);
+
+    // Run network 2 in a thread
+    std::cout << "Running network "
+              << arg2.config_file.substr(arg2.config_file.find("tidl"))
+              << " on EVEs: ";
+    for (DeviceId id : arg2.ids)
+        std::cout << static_cast<int>(id) << " ";
+    std::cout << " in thread 1" << std::endl;
+
+    pthread_t network_thread_2;
+    pthread_create(&network_thread_2, 0, &run_network, &arg2);
+
+    // Wait for both networks to complete
+    void *thread_return_val1;
+    void *thread_return_val2;
+    pthread_join(network_thread_1, &thread_return_val1);
+    pthread_join(network_thread_2, &thread_return_val2);
+
+    if (thread_return_val1 == 0 || thread_return_val2 == 0)
+    {
+        std::cout << "Multiple executors: FAILED" << std::endl;
+        return false;
+    }
+
+    std::cout << "Multiple executors: PASSED" << std::endl;
+    return true;
+}
+
+
+void* run_network(void *data)
+{
+    const ThreadArg* arg = static_cast<const ThreadArg *>(data);
+
+    const DeviceIds& ids = arg->ids;
+    const std::string& config_file = arg->config_file;
+
+    // Read the TI DL configuration file
+    Configuration configuration;
+    bool status = configuration.ReadFromFile(config_file);
+    assert (status != false);
+
+    configuration.outData += std::to_string(pthread_self());
+
+    // Open input and output files
+    std::ifstream input_data_file(configuration.inData, std::ios::binary);
+    std::ofstream output_data_file(configuration.outData, std::ios::binary);
+    assert (input_data_file.good());
+    assert (output_data_file.good());
+
+    // Determine input frame size from configuration
+    size_t frame_sz = configuration.inWidth * configuration.inHeight *
+                      configuration.inNumChannels;
+
+    try
+    {
+        // Create a executor with the approriate core type, number of cores
+        // and configuration specified
+        Executor executor(DeviceType::EVE, ids, configuration);
+
+        const ExecutionObjects& execution_objects =
+                                                executor.GetExecutionObjects();
+        int num_eos = execution_objects.size();
+
+        // Allocate input and output buffers for each execution object
+        std::vector<void *> buffers;
+        for (auto &eo : execution_objects)
+        {
+            ArgInfo in  = { ArgInfo(malloc_ddr<char>(frame_sz), frame_sz)};
+            ArgInfo out = { ArgInfo(malloc_ddr<char>(frame_sz), frame_sz)};
+            eo->SetInputOutputBuffer(in, out);
+
+            buffers.push_back(in.ptr());
+            buffers.push_back(out.ptr());
+        }
+
+        // Process frames with available execution objects in a pipelined manner
+        // additional num_eos iterations to flush the pipeline (epilogue)
+        for (int frame_idx = 0;
+             frame_idx < configuration.numFrames + num_eos; frame_idx++)
+        {
+            ExecutionObject* eo = execution_objects[frame_idx % num_eos].get();
+
+            // Wait for previous frame on the same eo to finish processing
+            if (eo->ProcessFrameWait())
+                WriteFrame(*eo, output_data_file);
+
+            // Read a frame and start processing it with current eo
+            if (ReadFrame(*eo, frame_idx, configuration, input_data_file))
+                eo->ProcessFrameStartAsync();
+        }
+
+
+        for (auto b : buffers)
+            __free_ddr(b);
+    }
+    catch (tidl::Exception &e)
+    {
+        std::cerr << e.what() << std::endl;
+        status = false;
+    }
+
+    input_data_file.close();
+    output_data_file.close();
+
+    // Return 1 for true, 0 for false. void * pattern follows example from:
+    // "Advanced programming in the Unix Environment"
+    if (!status) return ((void *)0);
+
+    return ((void *)1);
+}
diff --git a/examples/classification/readme.md b/examples/classification/readme.md
new file mode 100644 (file)
index 0000000..a149be4
--- /dev/null
@@ -0,0 +1,4 @@
+# Live camera input
+./tidl -n 2 -t e -i 1 -s ./classlist.txt -c ./stream_config_j11_v2.txt
+# Use video clip as input stream
+./tidl -n 2 -t e -i ./clips/test1.mp4 -s ./classlist.txt -c ./stream_config_j11_v2.txt
diff --git a/examples/classification/stream_config_dogs.txt b/examples/classification/stream_config_dogs.txt
new file mode 100644 (file)
index 0000000..a11f130
--- /dev/null
@@ -0,0 +1,8 @@
+numFrames   = 9000
+inData   = /usr/share/ti/tidl/examples/test/testvecs/input/shar_pei.raw
+outData   = "/usr/share/ti/tidl/examples/classification/stats_tool_out.bin"
+netBinFile      = "/usr/share/ti/tidl/examples/test/testvecs/config/tidl_models/dogs_net_j11v2.bin"
+paramsBinFile   = "/usr/share/ti/tidl/examples//test/testvecs/config/tidl_models/dogs_param_j11v2.bin"
+inWidth = 224
+inHeight = 224
+inNumChannels = 3
diff --git a/examples/classification/stream_config_j11_v2.txt b/examples/classification/stream_config_j11_v2.txt
new file mode 100644 (file)
index 0000000..21db243
--- /dev/null
@@ -0,0 +1,8 @@
+numFrames   = 9000
+inData   = /usr/share/ti/tidl/examples/test/testvecs/input/preproc_0_224x224.y
+outData   = "/usr/share/ti/tidl/examples/classification/stats_tool_out.bin"
+netBinFile      = "/usr/share/ti/tidl/examples/test/testvecs/config/tidl_models/tidl_net_imagenet_jacintonet11v2.bin"
+paramsBinFile   = "/usr/share/ti/tidl/examples//test/testvecs/config/tidl_models/tidl_param_imagenet_jacintonet11v2.bin"
+inWidth = 224
+inHeight = 224
+inNumChannels = 3
diff --git a/examples/classification/tidl-sw-stack-small.png b/examples/classification/tidl-sw-stack-small.png
new file mode 100644 (file)
index 0000000..e1e430b
Binary files /dev/null and b/examples/classification/tidl-sw-stack-small.png differ