Starting with JeVois v1.1, you can program machine vision modules for JeVois in Python 3.x.
Overview
The basic framework is as follows:
- Many of the basic facilities provided by the core JeVois software are wrapped so that they can be accessed from Python. This includes, for example, video frame capture, image conversion, video frame output over USB, log messages, sending messages to serial port, etc.
- OpenCV is also wrapped to Python and can be used in JeVois modules written in Python. This allows one to use the machine vision and image processing functions provided by OpenCV. In this framework, images are represented as Python numpy arrays. Functions are exposed by the JeVois core to allow converting camera video frames and output video frames to/from Python numpy arrays.
- JeVois modules written in Python should consist of a single Python class that exposes a specific interface, including a process() function that will be called by the JeVois engine each time a new video frame is to be processed by the module and an output image should be sent over USB to a host computer, and a processNoUSB() function that will be called to process camera frame with no USB video output (both functions have different names because Python does not support member function overloading). Note how this was fixed in JeVois v1.6.2 thanks to user discussions on this thread.
- So, the Python integration works in a two-way manner:
- JeVois core provides a libjevois Python library that can be used by modules written in Python.
- Modules written in python expose a class with specific member functions, which will be instantiated and called by the JeVois core when the modules is loaded.
- Modules written in Python are invoked by the JeVois core just like C++ modules, using a process() function as explained in Concepts used throughout this documentation.
- JeVois modules written in Python are otherwise treated just like modules written in C++: They get loaded when a particular video resolution is selected by the host computer, which corresponds to an entry in videomappings.cfg that matches the modules of interest. They also have a directory under JEVOIS:/modules and they may have the same auxiliary files as C++ modules do.
Examples
Modules in jevoisbase are available to help you understand how this works:
JeVois core expectations from modules written in Python
Just like the Module C++ abstract base class defines an interface for how C++ modules will be used by the JeVois Engine, Python modules should be organized as follow:
- A single .py file in a directory under JEVOIS:/modules/vendor/ declares a Python class, with the filename stem (without extension), directory name, and class name all an exact match.
- The module may declare and implememt (all are optional, but most modules should at least implement one of the process() functions to be useful):
- Constructor with no arguments:
__init__(self)
- Process function with USB output:
process(self, inframe, outframe)
- Process function with no USB output:
processNoUSB(self, inframe)
- JeVois-Pro Process function with GUI output:
processGUI(self, inframe, guihelper)
- Function to parse a serial command forwarded to the module by the JeVois Engine, return a string:
parseSerial(self, str)
- Function to return a string that describes the custom commands the module supports, for the JeVois help message:
supportedCommands(self)
- Function to cleanup just before the module will be unloaded:
uninit()
(in JeVois v1.7.1 and later)
- Note that sendSerial() which is provided by the C++ Module base class to allow derived modules to send messages over the serial port should not be defined and will not be invoked (since it is implemented by the JeVois core library rather than the module); instead, a function
jevois.sendSerial()
is exposed to Python modules by the JeVois core library which achieves the same result. Likewise for the functions that access raw camera or IMU registers:
- jevois.writeCamRegister()
- jevois.readCamRegister()
- jevois.writeIMUregister()
- jevois.readIMUregister()
- jevois.frameNum()
Python bindings provided by JeVois core
The following functions and classes of the JeVois core software are wrapped for use in Python. To use the Python version of a given class or function, just inspect the C++ documentation and assume that the same class name, function name, and number and types of arguments will be used (except for a few exceptions noted below).
Refer to the source code in BOOST_PYTHON_MODULE() in PythonSupport.C for the latest up-to-date list of Python bindings.
The bindings can be imported into Python through:
import pyjevois
if pyjevois.pro: import libjevoispro as jevois
else: import libjevois as jevois
Every JeVois module written in Python should start with that import.
Since all Python bindings are under the jevois module (actually, libjevois which we import as jevois), you should call these by prefixing the jevois module name.
For example, consider the C++ function fccstr() defined in the jevois C++ namespace with signature:
std::string
fccstr(
unsigned int fcc);
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
Invoking this function from Python would take the form:
will invoke the C++ function fccstr() of JeVois, passing it the contents of variable code (which should be a positive integer number as expected by the C++ function, otherwise the binding engine will throw an exception for incorrect input argument type). The C++ string returned by the C++ function will then be copied to Python string s and will be available for further use in Python, as any Python strings.
List of bindings
Click on any of the classes or functions below to see its documentation. Although the doc is for the C++ version, the functions and classes listed here have an exact binding to Python, except that you can ignore any C++ qualifiers (const
and similar) and reference/pointer specifications (&
or *
before an argument name).
- Note
- Refer to the source code in BOOST_PYTHON_MODULE() in PythonSupport.C for the latest up-to-date list of Python bindings.
- General utility functions declared in Utils.H
- Coordinate helpers declared in Coordinates.H
- imgToStd()
- stdToImg()
- imgToStdX()
- imgToStdY()
- imgToStdSize()
- stdToImgSize()
- Support for raw image buffers from camera and to USB from RawImage.H
- class RawImage
- member functions: invalidate(), valid(), clear(), require(), bytesperpix(), bytesize(), coordsOk()
- member variables: width, height, fmt, fps
- Raw format YUYV colors by name as in RawImage.H
- These are mapped to a Python enum jevois.YUYV with values Black = 0x8000, DarkGrey = 0x8050, MedGrey = 0x8080, LightGrey = 0x80a0, White = 0x80ff, DarkGreen = 0x0000, MedGreen = 0x0040, LightGreen = 0x00ff, DarkTeal = 0x7070, MedTeal = 0x7090, LightTeal = 0x70b0, DarkPurple = 0xa030, MedPurple = 0xa050, LightPurple = 0xa080, DarkPink = 0xff00, MedPink = 0xff80, LightPink = 0xffff.
- Video4Linux2 (V4L2) RawImage pixel formats supported by the camera sensor and by the USB output:
- These are mapped to constants jevois.V4L2_PIX_FMT_SRGGB8, jevois.V4L2_PIX_FMT_YUYV, jevois.V4L2_PIX_FMT_GREY, jevois.V4L2_PIX_FMT_RGB565, jevois.V4L2_PIX_FMT_MJPEG, and jevois.V4L2_PIX_FMT_BGR24.
- Input frame wrappers around the InputFrame class from Module.H
- class InputFrame
- member functions: get(), done(), getCvGRAY(), getCvBGR(), getCvRGB(), getCvRGBA()
- Output frame wrappers around the OutputFrame class from Module.H
- class OutputFrame
- member functions: get(), send(), sendCv(), sendCvGRAY(), sendCvBGR(), sendCvRGB(), sendCvRGBA(), sendScaledCvGRAY(), sendScaledCvBGR(), sendScaledCvRGB(), sendScaledCvRGBA()
- Operations on raw images as declared in RawImageOps.H
- cvImage()
- convertToCvGray()
- convertToCvBGR()
- convertToCvRGB()
- convertToCvRGBA()
- byteSwap()
- paste()
- pasteGreyToYUYV()
- roipaste()
- drawDisk()
- drawCircle()
- drawLine()
- drawRect()
- writeText() with font selected through a Python enum jevois.Font with values Font5x7, Font6x10, Font7x13, Font8x13bold, Font9x15bold, Font10x20, Font11x22, Font12x22, Font14x26, Font15x28, Font16x29, Font20x38.
- convertCvGRAYtoRawImage()
- convertCvBGRtoRawImage()
- convertCvRGBtoRawImage()
- convertCvRGBAtoRawImage()
- unpackCvRGBAtoGrayRawImage()
- hFlipYUYV()
- Timer class declared in Timer.H
- class Timer (note that constructor takes arguments; see below for log level definitions)
- member functions: start(), stop()
- Profiler class declared in Profiler.H
- class Profiler (note that constructor takes arguments; see below for log level definitions)
- member functions: start(), checkpoint(), stop()
- System utilities declared in SysInfo.H
- Logging functions, simplified versions of the macros declared in Log.H, taking a single string argument instead of the streaming interface used on the C++ side (hence, Python programmers should use the Python string format() function to place various variable values in that string):
- On JeVois-Pro, functions exposed by GUIhelperPython, which is a proxy to GUIhelper.
Code documentation and accessory files
Follow the same rules as in Programmer SDK and writing new modules, under "Module documentation and metadata"
See the sample Python modules in jevoisbase for examples of how this translates to Python doxygen directives.