JeVoisBase  1.20
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
PyPostClassify.py
Go to the documentation of this file.
1 import pyjevois
2 if pyjevois.pro: import libjevoispro as jevois
3 else: import libjevois as jevois
4 
5 import numpy as np
6 
7 ## Simple classification DNN post-processor written in python
8 #
9 # Compare this code to the C++ PostProcessorClassify (which has more functionality than here):
10 # - Abstract base: https://github.com/jevois/jevois/blob/master/include/jevois/DNN/PostProcessor.H
11 # - Header: https://github.com/jevois/jevois/blob/master/include/jevois/DNN/PostProcessorClassify.H
12 # - Implementation: https://github.com/jevois/jevois/blob/master/src/jevois/DNN/PostProcessorClassify.C
13 #
14 # @author Laurent Itti
15 #
16 # @email itti\@usc.edu
17 # @address University of Southern California, HNB-07A, 3641 Watt Way, Los Angeles, CA 90089-2520, USA
18 # @copyright Copyright (C) 2022 by Laurent Itti, iLab and the University of Southern California
19 # @mainurl http://jevois.org
20 # @supporturl http://jevois.org/doc
21 # @otherurl http://iLab.usc.edu
22 # @license GPL v3
23 # @distribution Unrestricted
24 # @restrictions None
25 # @ingroup pydnn
27  # ###################################################################################################
28  ## [Optional] Constructor
29  def __init__(self):
30  self.results = [] # list of strings containing our latest top predictions and scores
31  self.classmap = None # map from class index to class name
32 
33  # ###################################################################################################
34  ## [Optional] JeVois parameters initialization
35  def init(self):
36  pc = jevois.ParameterCategory("DNN Post-Processing Options", "")
37 
38  self.classes = jevois.Parameter(self, 'classes', 'str',
39  "Path to text file with names of object classes",
40  '', pc)
41  self.classes.setCallback(self.loadClasses)
42 
43  self.cthresh = jevois.Parameter(self, 'cthresh', 'float',
44  "Classification threshold, in percent confidence",
45  20.0, pc)
46 
47  self.top = jevois.Parameter(self, 'top', 'uint',
48  "Max number of predictions above cthresh to report",
49  5, pc)
50 
51  self.classoffset = jevois.Parameter(self, 'classoffset', 'int',
52  "Offset to apply to class indices",
53  0, pc)
54 
55  # ###################################################################################################
56  ## [Optional] Freeze some parameters that should not be changed at runtime.
57  ## The JeVois core will call this with doit being either True or False
58  def freeze(self, doit):
59  self.classes.freeze(doit)
60 
61  # ###################################################################################################
62  ## [Optional] Parameter callback: Load class names when 'classes' parameter value is changed,
63  ## when a pipeline is selected from the model zoo
64  def loadClasses(self, filename):
65  if filename:
66  jevois.LINFO(f"Loading {filename}...")
67  f = open(pyjevois.share + '/' + filename, 'rt') # will throw if file not found
68  self.classmap = f.read().rstrip('\n').split('\n')
69 
70  # ###################################################################################################
71  ## [Required] Main processing function: parse network output blobs and store resulting labels and scores locally.
72  ## outs is a list of numpy arrays for the network's outputs.
73  ## preproc is a handle to the pre-processor that was used, useful to recover transforms from original image
74  ## to cropped/resized network inputs (not used here).
75  def process(self, outs, preproc):
76  # Clear any old results:
77  self.results.clear()
78 
79  # Getting the value of a JeVois Parameter is somewhat costly, so cache it if we will be using that value
80  # repeatedly in an inner loop:
81  fudge = self.classoffset.get()
82  topn = self.top.get()
83 
84  # Process the newly received network outputs:
85  for o in outs:
86  # Remove all dimensions that are 1, e.g., from 1x1x1000 to 1000
87  o = np.squeeze(o)
88 
89  # Sort descending by scores and get the top scores:
90  topNidxs = np.argsort(o)[::-1][:topn]
91 
92  # Store results for later display in report():
93  cth = self.cthresh.get() * 0.01
94 
95  if self.classmap:
96  # Show class name and confidence:
97  for (i, idx) in enumerate(topNidxs):
98  if o[idx] > cth:
99  classidx = idx + fudge
100  if classidx >= 0 and classidx < len(self.classmap):
101  self.results.append('%s: %.2f' % (self.classmap[classidx], o[idx]*100))
102  else:
103  self.results.append('Unknown: %.2f' % o[idx])
104  else:
105  # Show class number and confidence:
106  for (i, idx) in enumerate(topNidxs):
107  if o[idx] > cth:
108  self.results.append('%d: %.2f' % (idx, o[idx]*100))
109 
110  # Make sure we always display topn lines of results for each output blob:
111  while len(self.results) < topn * len(outs):
112  self.results.append('-')
113 
114  # ###################################################################################################
115  ## [Optional] Report the latest results obtained by process() by drawing them
116  ## outimg is None or a RawImage to draw into when in Legacy mode (drawing to an image sent to USB)
117  ## helper is None or a GUIhelper to do OpenGL drawings when in JeVois-Pro GUI mode
118  ## overlay is True if user wishes to see overlay text
119  ## idle is true if keyboard/mouse have been idle for a while, which typically would reduce what is displayed
120  ##
121  ## Note that report() is called on every frame even though the network may run slower or take some time to load and
122  ## initialize, thus you should be prepared for report() being called even before process() has ever been called
123  ## (i.e., create some class member variables to hold the reported results, initialize them to some defaults in your
124  ## constructor, report their current values here, and update their values in process()).
125  def report(self, outimg, helper, overlay, idle):
126  # Legacy JeVois mode: Write results into YUYV RawImage to send over USB:
127  if outimg is not None:
128  if overlay:
129  x, y = 220, 16 # mirror C++ PostProcessorClassify::report()
130  jevois.writeText(outimg, 'Top-%d above %.2f%%' % (self.top.get(), self.cthresh.get()),
131  x, y, jevois.YUYV.White, jevois.Font.Font6x10)
132  y += 15
133  for r in self.results:
134  jevois.writeText(outimg, r, x, y, jevois.YUYV.White, jevois.Font.Font6x10)
135  y += 11
136 
137  # JeVois-Pro mode: Write the results as OpenGL overlay text on top of the video:
138  if helper is not None:
139  if overlay:
140  for r in self.results:
141  # itext writes one line of text and keeps track of incrementing the ordinate:
142  helper.itext(r, 0, -1)
PyPostClassify.PyPostClassify.classmap
classmap
Definition: PyPostClassify.py:31
split
std::vector< std::string > split(std::string const &input, std::string const &regex="\\s+")
PyPostClassify.PyPostClassify.init
def init(self)
[Optional] JeVois parameters initialization
Definition: PyPostClassify.py:35
PyPostClassify.PyPostClassify
Simple classification DNN post-processor written in python.
Definition: PyPostClassify.py:26
PyPostClassify.PyPostClassify.top
top
Definition: PyPostClassify.py:47
PyPostClassify.PyPostClassify.report
def report(self, outimg, helper, overlay, idle)
[Optional] Report the latest results obtained by process() by drawing them outimg is None or a RawIma...
Definition: PyPostClassify.py:125
PyPostClassify.PyPostClassify.classes
classes
Definition: PyPostClassify.py:38
PyPostClassify.PyPostClassify.loadClasses
def loadClasses(self, filename)
[Optional] Parameter callback: Load class names when 'classes' parameter value is changed,...
Definition: PyPostClassify.py:64
jevois::ParameterCategory
PyPostClassify.PyPostClassify.cthresh
cthresh
Definition: PyPostClassify.py:43
PyPostClassify.PyPostClassify.results
results
Definition: PyPostClassify.py:30
PyPostClassify.PyPostClassify.process
def process(self, outs, preproc)
[Required] Main processing function: parse network output blobs and store resulting labels and scores...
Definition: PyPostClassify.py:75
PyPostClassify.PyPostClassify.classoffset
classoffset
Definition: PyPostClassify.py:51
PyPostClassify.PyPostClassify.freeze
def freeze(self, doit)
[Optional] Freeze some parameters that should not be changed at runtime.
Definition: PyPostClassify.py:58
PyPostClassify.PyPostClassify.__init__
def __init__(self)
[Optional] Constructor
Definition: PyPostClassify.py:29