JeVoisBase  1.22
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
Loading...
Searching...
No Matches
PyPostClassify.py
Go to the documentation of this file.
1import pyjevois
2if pyjevois.pro: import libjevoispro as jevois
3else: import libjevois as jevois
4
5import 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.loadClassesloadClasses)
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)
Simple classification DNN post-processor written in python.
process(self, outs, preproc)
[Required] Main processing function: parse network output blobs and store resulting labels and scores...
__init__(self)
[Optional] Constructor
loadClasses(self, filename)
[Optional] Parameter callback: Load class names when 'classes' parameter value is changed,...
report(self, outimg, helper, overlay, idle)
[Optional] Report the latest results obtained by process() by drawing them outimg is None or a RawIma...
freeze(self, doit)
[Optional] Freeze some parameters that should not be changed at runtime.
init(self)
[Optional] JeVois parameters initialization