Level up your TinyML skills

30 minutes to your very own Esp32 Image Recognition

Create a working image recognition system that runs at 60 FPS in 1 Kb of RAM

Esp32-cam image recognition

Have you ever wanted to perform object recognition on your cheap Esp32-cam in a matter of minutes?

Do you want it to be easy and fast?

This project is for you!

Learn how to quickly implement your own object recognition system on the Esp32-cam by:

  1. collect images from Esp32-cam to create a dataset
  2. train a Machine Learning classifier on your PC to recognize objects in the images
  3. deploy that classifier to your Esp32-cam for real-time object recognition

Image Recognition that is Fast

Image and object recognition is not something entirely new on the Esp32-cam and other microcontrollers, thanks to TensorFlow for Microcontrollers and no-code platforms like Edge Impulse.

They come with pre-trained Neural networks of varying size and complexity that you can leverage to implement your own image recognition system.

But...

Neural Networks for image recognition are heavyweight: they can take anywhere from 50 Kb to 500 Kb of RAM.

Since your cheap Esp32-cam usually comes with limited RAM, you will often be forced to opt for a low complexity, low accuracy network.

Even more, with weight it comes time complexity: classifying an image on the Esp32-cam usually takes about 500 ms (source: Edge Impulse blog).

Can we do better?

Can we do faster?

Yes, we can!

Image and object recognition on Esp32-cam can be implemented in 30 minutes, with minimal code configuration, thanks to the Eloquent Arduino ecosystem of libraries: once deployed, it takes 1 kb of RAM and runs at 60 FPS.

Follow the next steps to get up and running!

Hardware Requirements

To follow this project the only requirement is an Esp32 camera.

You can find many models on the market:

I can't recommend enough the cameras from M5Stack because they come with 4 Mb external PSRAM, but any from the above list should work.

Esp32 cam devices

Software requirements

To capture the images from the Esp32-cam with ease, I suggest you to install the Eloquent Arduino library version 2.1.2. It is available on the Arduino IDE Library Manager.

Eloquent Arduino library

To collect the images on your PC and train the Machine Learning model, you have to install the everywhereml Python package.

Create a new Python project and run

pip install everywhereml==0.0.5

Video walkthrough

from IPython.display import IFrame

IFrame('https://www.youtube.com/embed/ZxRnVBiN_y4?rel=0', width=694, height=390)

Step 1 of 5: Load the CameraWebServer sketch

First step to create a Machine Learning model is to collect data.

Since the Esp32-cam quality is pretty low, I recommend you to:

  1. fix the camera in position with tape and don't let it move
  2. use artificial illumination if possible (image quality degrades in low light conditions)
esp32-cam image recognition setup

Something as simple as a plain background will work best

To keep acquisition speed fast, we will capture at QQVGA resolution (160 x 120). If your project requires you to capture at higher resolutions, change the sketch accordingly.

Image recognition often happens at even lower resolutions anyway, so if you're not using the large version of the image for other purposes, QQVGA is the best choice

Once your setup is ready, load the CameraWebServer sketch below on your board.

Once loaded, the Esp32-cam will connect your WiFi network and start an HTTP video streaming server you can access from any web broswer.

#include "eloquent.h"
#include "eloquent/networking/wifi.h"
#include "eloquent/vision/camera/esp32/webserver.h"

// replace 'm5wide' with your own model
// possible values are 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/m5wide.h"


void setup() {
    Serial.begin(115200);

    // configure camera
    camera.jpeg();
    camera.qqvga();

    // replace with your WiFi credentials
    while (!wifi.connectTo("Abc", "12345678"))
        Serial.println("Cannot connect to WiFi");

    while (!camera.begin())
        Serial.println("Cannot connect to camera");

    webServer.start();
    Serial.print("Camera web server started at http://");
    Serial.println(WiFi.localIP());
}

void loop() {
    // do nothing
}

Now connect your PC to the same WiFi network of your Esp32-cam and open the browser at the address that you read on the Serial Monitor. You should be able to see the live stream from the board.

Step 2 of 5: Collect images from Esp32-cam over HTTP

Now that the Esp32-cam video stream is available over the WiFi network, we can run a program that collects the frames over HTTP.

We will make use of the MjpegCollector class, that needs the URL of the Esp32-cam web server (the one you can read on the Serial Monitor).

"""
Collect images from Esp32-cam web server
"""
from everywhereml.data import ImageDataset
from everywhereml.data.collect import MjpegCollector

base_folder = 'boards_over_http'

try:
    # if our dataset folder already exists, load it
    image_dataset = ImageDataset.from_nested_folders(
        name='Boards', 
        base_folder=base_folder
    )
except FileNotFoundError:
    # if the dataset folder does not exists, collect the samples
    # from the Esp32-cam web server
    # duration is how long (in seconds) the program will collect 
    # the images for each class
    mjpeg_collector = MjpegCollector(address='http://192.168.240.76')
    image_dataset = mjpeg_collector.collect_many_classes(
        dataset_name='Boards', 
        base_folder=base_folder,
        duration=40
    )
  
print(image_dataset)
This is an interactive data capturing procedure.
Keep in mind that as soon as you will enter a class name, the capturing will start, so be ready!

The above snippet will start an interactive data collection procedure: it will ask for a class name and collect the frames for the given amount of time, until you decide to exit.

Put the objects in front of the camera, enter the object name in the input field and press [Enter]. The frame collection will start immediately.

esp32-cam image recognition data collection

Put the objects in front of the camera before starting the collection process

Move the object a little in front of the camera to capture slight variations and make the model more robust.

Once you're done collecting frames, you can get a preview of them and check the quality of your work.

"""
Display a preview of the captured images
"""
image_dataset.preview(
    samples_per_class=10, 
    rows_per_class=2, 
    figsize=(20, 10)
)

If you find that some images are bad or totally wrong, take some time to delete them.

If you feel that you may need to capture more images, do so.

Take all the time it takes to collect an high quality dataset, because in Machine Learning "garbage in, garbage out"!

Step 3 of 5: Create an Object Detection pipeline

Having our very own dataset of images, we need a way to transform each image into something a Machine Learning model can classify.

With Neural Networks, you usually feed the raw image as input and the network learns by itself how to extract meaningful features from it.

With traditional Machine Learning it's different: we have to extract the features by ourself.

But don't worry, you don't have to do this on your own.

The everywhereml package has all the tools you need.

First of all, our feature extractor will work with grayscale images, so let's convert the dataset from RGB to Gray.

"""
Image classification with HOG works on grayscale images at the moment
So convert images to grayscale in the range 0-255
"""
image_dataset = image_dataset.gray().uint8()
"""
Preview grayscale images
"""
image_dataset.preview(
    samples_per_class=10, 
    rows_per_class=2, 
    figsize=(20, 10), 
    cmap='gray'
)

Now it's time to actually convert the images to feature vectors.

There exist many feature extractor for images: in this project we will make use of Histogram. of Oriented Gradients.

It is lightweight and pretty fast, so it's a good fit for embedded environments like the Esp32-cam.

To speed the processing up, we will rescale our source image to a lower resolution (40 x 30).

If you later find your classifier achieves low accuracy, you may want to tweak this resolution and see how it impacts both accuracy and execution time.

"""
Create an object detection pipeline with HOG feature extractor
"""
from everywhereml.preprocessing.image.object_detection import HogPipeline
from everywhereml.preprocessing.image.transform import Resize

pipeline = HogPipeline(
    transforms=[
        Resize(width=40, height=30)
    ]
)

# Convert images to feature vectors
feature_dataset = pipeline.fit_transform(image_dataset)
feature_dataset.describe()
HOG: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 3973/3973 [00:06<00:00, 589.60it/s]
hog0 hog1 hog2 hog3 hog4 hog5 hog6 hog7 hog8 hog9 ... hog126 hog127 hog128 hog129 hog130 hog131 hog132 hog133 hog134 target
count 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 ... 3973.0 3973.0 3973.0 3973.0 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000 3973.000000
mean 0.004144 0.013228 0.382175 0.197764 0.065186 0.038199 0.571028 0.607736 0.103253 0.001294 ... 0.0 0.0 0.0 0.0 0.001653 0.008949 0.035351 0.276698 0.390667 1.502643
std 0.011126 0.031442 0.209502 0.075928 0.030605 0.027203 0.082439 0.099930 0.027841 0.005890 ... 0.0 0.0 0.0 0.0 0.012827 0.041605 0.112141 0.125652 0.139484 1.117609
min 0.000000 0.000000 0.042983 0.006226 0.000000 0.000000 0.330738 0.219745 0.012631 0.000000 ... 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.000000 0.105724 0.000000
25% 0.000000 0.000000 0.236713 0.148486 0.042255 0.023224 0.517313 0.547261 0.085016 0.000000 ... 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.190454 0.287429 1.000000
50% 0.000000 0.000000 0.320816 0.188273 0.064217 0.036321 0.582529 0.623214 0.103585 0.000000 ... 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.254019 0.379817 2.000000
75% 0.000000 0.008949 0.485955 0.236276 0.085064 0.049494 0.615910 0.675409 0.122275 0.000000 ... 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.320986 0.441451 3.000000
max 0.101935 0.309142 1.000000 0.623691 0.176081 0.337037 1.000000 0.938173 0.184347 0.059208 ... 0.0 0.0 0.0 0.0 0.189369 0.426923 1.000000 1.000000 1.000000 3.000000

8 rows × 136 columns

"""
Print pipeline description
"""
print(pipeline)
ImagePipeline: HogPipeline
---------
 - Resize(from=(160, 120), to=(40, 30), pixformat=gray)
 > HOG(block_size=8, bins=9, cell_size=3)

The output of the above code is a dataset made of feature vectors, instead of images. These feature vectors are now suitable for Machine Learning models.

To get a visual idea of how informative the extracted features are, we can plot a pairplot of them.

A pairplot compares each feature against the others in a grid format. By highlighting each class with a different color, you can quickly get if the features are able to "isolate" a class (if you can do this by eye, a Machine Learning classifier will be able too!).

"""
Plot pairplot of features.
Feel free to open the image in a new window to see it at full scale.
In the next line:
 - n is the number of points to plot (the greater the value, the longer it takes)
 - k is the number of features (values greater than 10 become messy)
"""
feature_dataset.plot.features_pairplot(n=200, k=8)
/Users/simone/PycharmProjects/ebooks/Getting started with TinyML on Arduino/venv/lib/python3.8/site-packages/sklearn/feature_selection/_univariate_selection.py:112: UserWarning: Features [ 81  82 126 127 128 129] are constant.
  warnings.warn("Features %s are constant." % constant_features_idx, UserWarning)
/Users/simone/PycharmProjects/ebooks/Getting started with TinyML on Arduino/venv/lib/python3.8/site-packages/sklearn/feature_selection/_univariate_selection.py:113: RuntimeWarning: invalid value encountered in true_divide
  f = msb / msw

In this case, we can clearly see that while the wio class and empty class are well clustered, the pi and portenta are always mixed to some degree.

This tells us that the classifier will mis-label them sometimes.

Another kind of visualization is UMAP.

UMAP (Uniform Manifold Approximation and Projection) is a dimensionality reduction algorithm.

It takes a feature vector of length N and "compresses" it to, in our case, length 2, while trying to preserve the topology structure of the original vector.

By collapsing the feature vectors to (x, y) pairs, we can plot them on a scatter plot.

"""
Plot UMAP of features
If features are discriminative, we should see well defined clusters of points
"""
feature_dataset.plot.umap()
OMP: Info #270: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.

If we see well defined cluster of points (as in the above image), it means that our features do a great job at describing each class.

If you feel like the pairplot and the UMAP "disagree", it is true only to some extent. UMAP applies heavy lifting to data to preserve the cluster isolation; most Machine Learning models won't do so. You should give more importance to the pairplot in the context of TinyML

Step 4 of 5: Train a Machine Learning classifier

From the above graphics we can say that our features are pretty good at characterizing our data, so it is time to train a classifier.

There are many available, but one of the most effective is Random Forest. You can tweak its configuration as you prefer, but the values below should work fine in most cases.

"""
Create and fit RandomForest classifier
"""
from everywhereml.sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(n_estimators=10, max_depth=40)

# fit on train split and get accuracy on the test split
train, test = feature_dataset.split(test_size=0.4)
clf.fit(train)

print('Score on test set: %.2f' % clf.score(test))

# now fit on the whole dataset
clf.fit(feature_dataset)
Score on test set: 1.00
RandomForestClassifier(base_estimator=DecisionTreeClassifier(), bootstrap=True, ccp_alpha=0.0, class_name=RandomForestClassifier, class_weight=None, criterion=gini, estimator_params=('criterion', 'max_depth', 'min_samples_split', 'min_samples_leaf', 'min_weight_fraction_leaf', 'max_features', 'max_leaf_nodes', 'min_impurity_decrease', 'random_state', 'ccp_alpha'), max_depth=40, max_features=auto, max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None, num_outputs=4, oob_score=False, package_name=everywhereml.sklearn.ensemble, random_state=None, template_folder=everywhereml/sklearn/ensemble, verbose=0, warm_start=False)

Depending on your dataset, you can expect your accuracy to range from 0.7 to 1.

If it is lower (or too low for your use case), you can:

  1. improve your dataset (collect more images, fix your setup)
  2. tweak the resize parameter of the HogPipeline to an higher resolution
  3. tweak the RandomForestClassifier parameters (see documentation)

If you're satisfied, it's time to port the whole system to your Esp32-cam.

Step 5 of 5: Port to Esp32

Last step is to convert the HogPipeline and RandomForestClassifier to C++ code that can run on your Esp32-cam.

This process is very straightforward, since you only need a line of code.

Create a new project in the Arduino IDE to hold all the following files.

"""
Export pipeline to C++
Replace the path to your actual sketch path
"""
print(pipeline.to_arduino_file(
    filename='path-to-sketch/HogPipeline.h',
    instance_name='hog'
))
#ifndef UUID5906740848
#define UUID5906740848


    #ifndef UUID5906742576
#define UUID5906742576

/**
  * HOG(block_size=8, bins=9, cell_size=3)
 */
class HOG {
    public:

        /**
         * Transform input image
         */
         template<typename T, typename U>
        bool transform(T *input, U *output) {
            
    uint16_t f = 0;
    uint16_t block = 0;
    float hog[135] = {0};

    // compute gradients
    for (uint16_t blockY = 0; blockY < 3; blockY++) {
        const uint16_t blockOffsetY = blockY * 320;

        for (uint16_t blockX = 0; blockX < 5; blockX++) {
            const uint16_t blockOffsetX = blockX * 8;
            float hist[9] = {0};

            for (uint16_t _y = 1; _y < 7; _y += 1) {
                const uint16_t rowOffset = blockOffsetY + _y * 40 + blockOffsetX;
                const uint16_t rowOffsetBefore = rowOffset - 40;
                const uint16_t rowOffsetAfter = rowOffset + 40;

                for (uint16_t _x = 1; _x < 7; _x += 1) {
                    const uint16_t offset = rowOffset + _x;
                    const uint16_t offsetBefore = rowOffsetBefore + _x;
                    const uint16_t offsetAfter = rowOffsetAfter + _x;
                    const float gy = ((float) input[offsetAfter]) - input[offsetBefore];
                    const float gx = ((float) input[offset + 1]) - input[offset - 1];
                    const float g = sqrt(gy * gy + gx * gx);
                    uint8_t angle = abs(this->arctan(gy, gx) * 180 / 3.141592653589793f / 20);

                    if (angle >= 8) angle = 8;
                    hist[angle] += g;
                }
            }

            for (uint16_t i = 0; i < 9; i++)
                hog[f++] = hist[i];

            block += 1;

            // end of cell, normalize
            if ((block % 3) == 0) {
                const uint16_t offset = (block - 3) * 9;
                float maxGradient = 0.0001;

                for (uint16_t i = 0; i < 27; i++) {
                    const float h = hog[offset + i];

                    if (h > maxGradient)
                        maxGradient = h;
                }

                for (uint16_t i = 0; i < 27; i++) {
                    hog[offset + i] /= maxGradient;
                }

                maxGradient = 0.0001;
            }
        }
    }


    // copy over
    for (uint16_t i = 0; i < 135; i++)
        output[i] = hog[i];


            return true;
        }

    protected:
        

    /**
     * optional atan2 approximation for faster calculation
     */
    float arctan(float y, float x) {
        
            float r = 0;

            if (abs(y) < 0.00000001)
                return 0;
            else if (abs(x) < 0.00000001)
                return 3.14159274 * (y > 0 ? 1 : -1);
            else {
                float a = min(abs(x), abs(y)) / max(abs(x), abs(y));
                float s = a * a;
                r = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a;

                if (abs(y) > abs(x))
                r = 1.57079637 - r;
            }

            if (x < 0)
                r = 3.14159274 - r;
            if (y < 0)
                r = -r;

            return r;
        
    }


};



#endif


/**
  * ImagePipeline: HogPipeline
 * ---------
 *  - Resize(from=(160, 120), to=(40, 30), pixformat=gray)
 *  > HOG(block_size=8, bins=9, cell_size=3)
 */
class HogPipeline {
    public:
        static const size_t NUM_INPUTS = 1200;
        static const size_t NUM_OUTPUTS = 135;
        static const size_t WORKING_SIZE = 135;
        float features[135];

        /**
         * Extract features from input image
         */
        template<typename T>
        bool transform(T *input) {
            time_t start = micros();
            ok = true;

            preprocess(input);

            
                
                    ok = ok && hog.transform(input, features);
                
            

            latency = micros() - start;

            return ok;
        }

        /**
         * Debug output feature vector
         */
        template<typename PrinterInterface>
        void debugTo(PrinterInterface &printer, uint8_t precision=5) {
            printer.print(features[0], precision);

            for (uint16_t i = 1; i < 135; i++) {
                printer.print(", ");
                printer.print(features[i], precision);
            }

            printer.print('\n');
        }

        /**
 * Get latency in micros
 */
uint32_t latencyInMicros() {
    return latency;
}

/**
 * Get latency in millis
 */
uint16_t latencyInMillis() {
    return latency / 1000;
}

    protected:
        bool ok;
        time_t latency;
        
            HOG hog;
        

        template<typename T>
        void preprocess(T *input) {
            
                
    // grayscale rescaling
    const float dy = 4.0f;
    const float dx = 4.0f;

    for (uint16_t y = 0; y < 30; y++) {
        const size_t sourceOffset = round(y * dy) * 160;
        const size_t destOffset = y * 40;

        for (uint16_t x = 0; x < 40; x++)
            input[destOffset + x] = input[sourceOffset + ((uint16_t) (x * dx))];
    }

            
        }
};


static HogPipeline hog;


#endif
"""
Export classifier to C++
Replace the path to your actual sketch path

The class_map parameters convert numeric classes to human-readable strings
"""
print(clf.to_arduino_file(
    filename='path-to-sketch/HogClassifier.h',
    instance_name='classifier', 
    class_map=feature_dataset.class_map
))
#ifndef UUID5920991072
#define UUID5920991072

/**
  * RandomForestClassifier(base_estimator=DecisionTreeClassifier(), bootstrap=True, ccp_alpha=0.0, class_name=RandomForestClassifier, class_weight=None, criterion=gini, estimator_params=('criterion', 'max_depth', 'min_samples_split', 'min_samples_leaf', 'min_weight_fraction_leaf', 'max_features', 'max_leaf_nodes', 'min_impurity_decrease', 'random_state', 'ccp_alpha'), max_depth=40, max_features=auto, max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None, num_outputs=4, oob_score=False, package_name=everywhereml.sklearn.ensemble, random_state=None, template_folder=everywhereml/sklearn/ensemble, verbose=0, warm_start=False)
 */
class RandomForestClassifier {
    public:

        /**
         * Predict class from features
         */
        int predict(float *x) {
            int predictedValue = 0;
            size_t startedAt = micros();

            
    uint16_t votes[4] = { 0 };
    uint8_t classIdx = 0;
    float classScore = 0;

    
        tree0(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree1(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree2(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree3(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree4(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree5(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree6(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree7(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree8(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    
        tree9(x, &classIdx, &classScore);
        votes[classIdx] += classScore;
    

    // return argmax of votes
uint8_t maxClassIdx = 0;
float maxVote = votes[0];

for (uint8_t i = 1; i < 4; i++) {
    if (votes[i] > maxVote) {
        maxClassIdx = i;
        maxVote = votes[i];
    }
}

predictedValue = maxClassIdx;


            latency = micros() - startedAt;

            return (lastPrediction = predictedValue);
        }


        

/**
 * Predict class label
 */
String predictLabel(float *x) {
    return getLabelOf(predict(x));
}

/**
 * Get label of last prediction
 */
String getLabel() {
    return getLabelOf(lastPrediction);
}

/**
 * Get label of given class
 */
String getLabelOf(int8_t idx) {
    switch (idx) {
        case -1:
            return "ERROR";
        
            case 0:
                return "no_board";
        
            case 1:
                return "pi";
        
            case 2:
                return "portenta";
        
            case 3:
                return "wio";
        
        default:
            return "UNKNOWN";
    }
}


        /**
 * Get latency in micros
 */
uint32_t latencyInMicros() {
    return latency;
}

/**
 * Get latency in millis
 */
uint16_t latencyInMillis() {
    return latency / 1000;
}

    protected:
        float latency = 0;
        int lastPrediction = 0;

        

    
        
            /**
             * Random forest's tree #0
             */
            void tree0(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[44] <= 0.34882040321826935) {
        
            
    if (x[29] <= 0.7726760506629944) {
        
            
    if (x[33] <= 0.06834471225738525) {
        
            
    if (x[124] <= 0.3282292038202286) {
        
            
    if (x[47] <= 0.5531854331493378) {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[70] <= 0.001405696792062372) {
        
            
    if (x[35] <= 0.6536738276481628) {
        
            
    if (x[62] <= 0.19297879934310913) {
        
            
    if (x[105] <= 0.4245643764734268) {
        
            
    if (x[47] <= 0.480339378118515) {
        
            
    if (x[103] <= 0.8523334264755249) {
        
            
    if (x[35] <= 0.5057968348264694) {
        
            
    if (x[103] <= 0.019527442753314972) {
        
            
    *classIdx = 0;
    *classScore = 1024.0;
    return;

        
    }
    else {
        
            
    if (x[59] <= 0.062496721744537354) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[103] <= 0.11949969828128815) {
        
            
    *classIdx = 0;
    *classScore = 1024.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[102] <= 0.32813313603401184) {
        
            
    if (x[118] <= 0.13758118264377117) {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[67] <= 0.13798769563436508) {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    if (x[123] <= 0.03521112445741892) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    if (x[120] <= 0.047595029696822166) {
        
            
    if (x[89] <= 0.15121085569262505) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    if (x[57] <= 0.7914194762706757) {
        
            
    if (x[33] <= 0.2651088684797287) {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    if (x[47] <= 0.8942715525627136) {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[97] <= 0.011335626244544983) {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[61] <= 0.05341171659529209) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[103] <= 0.5189695358276367) {
        
            
    if (x[67] <= 0.09917554631829262) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[1] <= 0.013661682140082121) {
        
            
    if (x[2] <= 0.4697612226009369) {
        
            
    if (x[73] <= 0.4398939609527588) {
        
            
    if (x[55] <= 0.29302120953798294) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[30] <= 0.5657644271850586) {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 989.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[69] <= 0.0010277953697368503) {
        
            
    *classIdx = 0;
    *classScore = 1024.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 973.0;
    return;

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #1
             */
            void tree1(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[108] <= 0.9980662167072296) {
        
            
    if (x[35] <= 0.6530715525150299) {
        
            
    if (x[92] <= 0.6016182899475098) {
        
            
    if (x[55] <= 0.41190458834171295) {
        
            
    if (x[29] <= 0.03986312821507454) {
        
            
    if (x[74] <= 0.36515218019485474) {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[90] <= 0.1574879288673401) {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[34] <= 0.4544176906347275) {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[90] <= 0.09230632148683071) {
        
            
    if (x[124] <= 0.64644855260849) {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[118] <= 0.12322954833507538) {
        
            
    if (x[111] <= 0.150700181722641) {
        
            
    if (x[6] <= 0.42629051208496094) {
        
            
    *classIdx = 3;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[48] <= 0.7166434228420258) {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[37] <= 0.032147668302059174) {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[73] <= 0.029361966997385025) {
        
            
    if (x[36] <= 0.006625032052397728) {
        
            
    *classIdx = 0;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[102] <= 0.22101211547851562) {
        
            
    if (x[133] <= 0.2979653626680374) {
        
            
    *classIdx = 3;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[103] <= 0.4571008160710335) {
        
            
    if (x[104] <= 0.28481045365333557) {
        
            
    *classIdx = 1;
    *classScore = 970.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 978.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #2
             */
            void tree2(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[110] <= 0.14436209201812744) {
        
            
    if (x[28] <= 0.2941649854183197) {
        
            
    if (x[72] <= 0.3283408433198929) {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    if (x[102] <= 0.0585083719342947) {
        
            
    *classIdx = 3;
    *classScore = 969.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[113] <= 0.10785583779215813) {
        
            
    *classIdx = 3;
    *classScore = 969.0;
    return;

        
    }
    else {
        
            
    if (x[90] <= 0.18018318340182304) {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[34] <= 0.07403763756155968) {
        
            
    if (x[118] <= 0.0001979848020710051) {
        
            
    if (x[30] <= 0.0066987317986786366) {
        
            
    *classIdx = 0;
    *classScore = 996.0;
    return;

        
    }
    else {
        
            
    if (x[72] <= 0.6443009823560715) {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    if (x[101] <= 0.08690721355378628) {
        
            
    *classIdx = 3;
    *classScore = 969.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[74] <= 0.27741335332393646) {
        
            
    if (x[56] <= 0.07151037827134132) {
        
            
    *classIdx = 3;
    *classScore = 969.0;
    return;

        
    }
    else {
        
            
    if (x[1] <= 0.018018158618360758) {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[94] <= 0.5572962760925293) {
        
            
    if (x[55] <= 0.19738255441188812) {
        
            
    if (x[27] <= 0.026398222893476486) {
        
            
    if (x[32] <= 0.6138793975114822) {
        
            
    if (x[90] <= 0.19988171756267548) {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 996.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[110] <= 0.2494039237499237) {
        
            
    *classIdx = 3;
    *classScore = 969.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[93] <= 0.13320856541395187) {
        
            
    if (x[92] <= 0.15036539733409882) {
        
            
    *classIdx = 0;
    *classScore = 996.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[105] <= 0.22029637545347214) {
        
            
    if (x[72] <= 0.6407427787780762) {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[7] <= 0.47586889564991) {
        
            
    if (x[45] <= 0.04107788298279047) {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[35] <= 0.6529013812541962) {
        
            
    *classIdx = 2;
    *classScore = 1008.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1000.0;
    return;

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #3
             */
            void tree3(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[111] <= 0.1271604672074318) {
        
            
    if (x[103] <= 0.2605111226439476) {
        
            
    if (x[31] <= 0.18265699222683907) {
        
            
    *classIdx = 3;
    *classScore = 1069.0;
    return;

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 944.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[102] <= 0.22446643561124802) {
        
            
    if (x[32] <= 0.4095272272825241) {
        
            
    if (x[124] <= 0.2904891073703766) {
        
            
    if (x[98] <= 0.013150070793926716) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1069.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[35] <= 0.6665985882282257) {
        
            
    if (x[24] <= 0.09975071251392365) {
        
            
    *classIdx = 0;
    *classScore = 944.0;
    return;

        
    }
    else {
        
            
    if (x[99] <= 0.1322011686861515) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    if (x[2] <= 0.2241016998887062) {
        
            
    *classIdx = 0;
    *classScore = 944.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[79] <= 0.32123638689517975) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 944.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[74] <= 0.16607120633125305) {
        
            
    if (x[72] <= 0.14043395593762398) {
        
            
    if (x[110] <= 0.2803633064031601) {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 944.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[1] <= 0.016240411903709173) {
        
            
    if (x[86] <= 0.2852577716112137) {
        
            
    if (x[0] <= 0.020041065756231546) {
        
            
    if (x[49] <= 0.3927963823080063) {
        
            
    if (x[85] <= 0.5159388184547424) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[102] <= 0.27228139340877533) {
        
            
    if (x[66] <= 0.20544720441102982) {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    if (x[107] <= 0.4991817772388458) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[111] <= 0.18378302454948425) {
        
            
    if (x[73] <= 0.16414403915405273) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[55] <= 0.1263127736747265) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    if (x[64] <= 0.9851962625980377) {
        
            
    if (x[18] <= 0.33054111897945404) {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[13] <= 0.34707100689411163) {
        
            
    *classIdx = 1;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 989.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #4
             */
            void tree4(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[33] <= 0.8076184689998627) {
        
            
    if (x[60] <= 0.09359220415353775) {
        
            
    if (x[122] <= 0.019955490715801716) {
        
            
    if (x[33] <= 0.11990037560462952) {
        
            
    if (x[74] <= 0.3993034213781357) {
        
            
    if (x[112] <= 0.4300600700080395) {
        
            
    *classIdx = 3;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    if (x[34] <= 0.2956773564219475) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[55] <= 0.23046381771564484) {
        
            
    if (x[77] <= 0.022777020931243896) {
        
            
    if (x[77] <= 0.0188904982060194) {
        
            
    if (x[8] <= 0.10785232484340668) {
        
            
    if (x[125] <= 0.06458010710775852) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[111] <= 0.6199979782104492) {
        
            
    if (x[73] <= 0.08471912890672684) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[56] <= 0.8600490689277649) {
        
            
    if (x[7] <= 0.7322711050510406) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    if (x[33] <= 0.19890689104795456) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[91] <= 0.3065017759799957) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[72] <= 0.3768015056848526) {
        
            
    if (x[77] <= 0.8826876580715179) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[87] <= 0.09904004074633121) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[68] <= 0.0949612446129322) {
        
            
    if (x[118] <= 0.10635852441191673) {
        
            
    if (x[78] <= 0.03633681870996952) {
        
            
    if (x[62] <= 0.020262284204363823) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    if (x[102] <= 0.09750007838010788) {
        
            
    *classIdx = 3;
    *classScore = 989.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[117] <= 0.017103446647524834) {
        
            
    if (x[92] <= 0.17420382797718048) {
        
            
    *classIdx = 0;
    *classScore = 940.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[35] <= 0.40874500572681427) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    if (x[97] <= 0.2954152226448059) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[74] <= 0.24020981788635254) {
        
            
    if (x[68] <= 0.09665172174572945) {
        
            
    if (x[90] <= 0.05841563642024994) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[119] <= 0.021288910880684853) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[30] <= 0.15192819386720657) {
        
            
    if (x[102] <= 0.3897913247346878) {
        
            
    if (x[63] <= 0.3944779932498932) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 989.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[132] <= 0.011251544579863548) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[3] <= 0.2989928275346756) {
        
            
    if (x[29] <= 0.5059226676821709) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[73] <= 0.3069322183728218) {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[109] <= 0.2452080100774765) {
        
            
    *classIdx = 0;
    *classScore = 940.0;
    return;

        
    }
    else {
        
            
    if (x[65] <= 0.11384378001093864) {
        
            
    *classIdx = 2;
    *classScore = 1019.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1025.0;
    return;

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #5
             */
            void tree5(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[117] <= 0.00013387331273406744) {
        
            
    if (x[49] <= 0.1782645434141159) {
        
            
    *classIdx = 0;
    *classScore = 1009.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[124] <= 0.2892760783433914) {
        
            
    if (x[118] <= 0.0719534195959568) {
        
            
    if (x[74] <= 0.7270664870738983) {
        
            
    if (x[108] <= 0.7999932169914246) {
        
            
    if (x[56] <= 0.7047905176877975) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[93] <= 0.4128127992153168) {
        
            
    if (x[46] <= 0.082118334248662) {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[87] <= 0.1090206541121006) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[37] <= 0.00039050541818141937) {
        
            
    if (x[7] <= 0.5915172696113586) {
        
            
    if (x[74] <= 0.2869604527950287) {
        
            
    if (x[122] <= 0.047466764226555824) {
        
            
    if (x[32] <= 0.00956386886537075) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    if (x[85] <= 0.4708804190158844) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[63] <= 0.5206140577793121) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[35] <= 0.4593780040740967) {
        
            
    if (x[72] <= 0.17759937047958374) {
        
            
    if (x[67] <= 0.7128052264451981) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[48] <= 0.41547779738903046) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    if (x[120] <= 0.11230740416795015) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[55] <= 0.2175687998533249) {
        
            
    if (x[2] <= 0.4547068923711777) {
        
            
    if (x[64] <= 0.14779002219438553) {
        
            
    if (x[18] <= 0.8743833303451538) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[34] <= 0.5362630486488342) {
        
            
    if (x[79] <= 0.42569495737552643) {
        
            
    if (x[92] <= 0.9590942561626434) {
        
            
    if (x[79] <= 0.35523521900177) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    if (x[74] <= 0.3561253473162651) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[105] <= 0.27445101737976074) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[68] <= 0.07269370928406715) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[7] <= 0.6080211699008942) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[65] <= 0.3070691376924515) {
        
            
    if (x[97] <= 0.08804232999682426) {
        
            
    if (x[20] <= 0.13710345327854156) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[105] <= 0.2622958868741989) {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }
    else {
        
            
    if (x[20] <= 0.12373301014304161) {
        
            
    *classIdx = 1;
    *classScore = 979.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 971.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #6
             */
            void tree6(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[111] <= 0.12414990365505219) {
        
            
    if (x[124] <= 0.29242679476737976) {
        
            
    if (x[28] <= 0.02108311839401722) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1043.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[24] <= 0.20721380412578583) {
        
            
    if (x[103] <= 0.2607061564922333) {
        
            
    *classIdx = 0;
    *classScore = 992.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[104] <= 0.04142299294471741) {
        
            
    *classIdx = 0;
    *classScore = 992.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[33] <= 0.7993143200874329) {
        
            
    if (x[7] <= 0.6232099533081055) {
        
            
    if (x[103] <= 0.7696967124938965) {
        
            
    if (x[57] <= 0.6046026945114136) {
        
            
    if (x[102] <= 0.19621522724628448) {
        
            
    if (x[56] <= 0.19284867495298386) {
        
            
    *classIdx = 3;
    *classScore = 1043.0;
    return;

        
    }
    else {
        
            
    if (x[57] <= 0.18662171065807343) {
        
            
    *classIdx = 0;
    *classScore = 992.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[72] <= 0.264618843793869) {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    if (x[50] <= 0.042270477861166) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[2] <= 0.47287826240062714) {
        
            
    if (x[91] <= 0.4505120813846588) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[86] <= 0.3748128116130829) {
        
            
    if (x[105] <= 0.39076468348503113) {
        
            
    if (x[19] <= 0.6096349954605103) {
        
            
    if (x[39] <= 0.1012711301445961) {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[72] <= 0.13337483629584312) {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    if (x[42] <= 0.00987055292353034) {
        
            
    if (x[35] <= 0.6686932742595673) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[119] <= 0.05600026622414589) {
        
            
    if (x[35] <= 0.4135086387395859) {
        
            
    if (x[100] <= 0.2200469747185707) {
        
            
    if (x[60] <= 0.15482279658317566) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1043.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 992.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[69] <= 0.008275999687612057) {
        
            
    if (x[27] <= 0.02434472367167473) {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1043.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[120] <= 0.0036060481797903776) {
        
            
    *classIdx = 3;
    *classScore = 1043.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[107] <= 0.23002876341342926) {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[37] <= 0.07891307771205902) {
        
            
    *classIdx = 0;
    *classScore = 992.0;
    return;

        
    }
    else {
        
            
    if (x[46] <= 0.0117126798722893) {
        
            
    *classIdx = 1;
    *classScore = 987.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 951.0;
    return;

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #7
             */
            void tree7(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[32] <= 0.46408945322036743) {
        
            
    if (x[108] <= 0.9997795224189758) {
        
            
    if (x[61] <= 0.05563057027757168) {
        
            
    if (x[48] <= 0.23226920515298843) {
        
            
    if (x[63] <= 0.33417370915412903) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    if (x[72] <= 0.356795534491539) {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[92] <= 0.5783127248287201) {
        
            
    if (x[91] <= 0.32426944375038147) {
        
            
    if (x[63] <= 0.967618852853775) {
        
            
    if (x[28] <= 0.10727587714791298) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    if (x[85] <= 0.40172770619392395) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[56] <= 0.5592942535877228) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[92] <= 0.2216704934835434) {
        
            
    if (x[77] <= 0.110720444470644) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[112] <= 0.5046462081372738) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    if (x[28] <= 0.5006683319807053) {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[55] <= 0.22727275639772415) {
        
            
    if (x[35] <= 0.8538295924663544) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    if (x[71] <= 0.004901578649878502) {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 967.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[93] <= 0.14444297552108765) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[103] <= 0.4607554003596306) {
        
            
    if (x[33] <= 0.15707367658615112) {
        
            
    if (x[78] <= 0.19471997767686844) {
        
            
    *classIdx = 3;
    *classScore = 967.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[52] <= 0.016459180042147636) {
        
            
    if (x[109] <= 0.08120637573301792) {
        
            
    *classIdx = 3;
    *classScore = 967.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 1012.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 1016.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[101] <= 0.23662198334932327) {
        
            
    *classIdx = 2;
    *classScore = 978.0;
    return;

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 1016.0;
    return;

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #8
             */
            void tree8(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[60] <= 0.1077520102262497) {
        
            
    if (x[104] <= 0.004705929197371006) {
        
            
    if (x[79] <= 0.31122320890426636) {
        
            
    if (x[103] <= 0.7115482538938522) {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 0;
    *classScore = 981.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[35] <= 0.6589930653572083) {
        
            
    if (x[74] <= 0.2027658447623253) {
        
            
    if (x[124] <= 0.2602975070476532) {
        
            
    if (x[58] <= 0.018068354576826096) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    if (x[133] <= 0.2549393028020859) {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[47] <= 0.1016160100698471) {
        
            
    if (x[0] <= 0.012307468801736832) {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[105] <= 0.42030853033065796) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[86] <= 0.027437899261713028) {
        
            
    if (x[55] <= 0.2510276511311531) {
        
            
    if (x[73] <= 0.7087392210960388) {
        
            
    if (x[91] <= 0.3302614092826843) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[99] <= 0.132009357213974) {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[91] <= 0.11673052608966827) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[69] <= 0.0009058478754013777) {
        
            
    if (x[32] <= 0.32360269129276276) {
        
            
    if (x[7] <= 0.4406959265470505) {
        
            
    if (x[18] <= 0.3518323004245758) {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[59] <= 0.14115191251039505) {
        
            
    if (x[134] <= 0.18190255016088486) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    if (x[57] <= 0.7373461723327637) {
        
            
    if (x[74] <= 0.01606922224164009) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[117] <= 0.5256548672914505) {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[56] <= 0.27944399416446686) {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }
    else {
        
            
    if (x[50] <= 0.07413450628519058) {
        
            
    *classIdx = 2;
    *classScore = 993.0;
    return;

        
    }
    else {
        
            
    if (x[78] <= 0.059987036511301994) {
        
            
    *classIdx = 3;
    *classScore = 1014.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 985.0;
    return;

        
    }

        
    }

        
    }

        
    }

            }
        
    
        
            /**
             * Random forest's tree #9
             */
            void tree9(float *x, uint8_t *classIdx, float *classScore) {
                
    if (x[104] <= 0.0034561443608254194) {
        
            
    if (x[103] <= 0.22259274125099182) {
        
            
    *classIdx = 0;
    *classScore = 955.0;
    return;

        
    }
    else {
        
            
    if (x[105] <= 0.17179572582244873) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[74] <= 0.2546422481536865) {
        
            
    if (x[89] <= 0.9938300251960754) {
        
            
    if (x[73] <= 0.4257603883743286) {
        
            
    if (x[102] <= 0.8706697225570679) {
        
            
    if (x[95] <= 0.3743189871311188) {
        
            
    if (x[105] <= 0.5392614901065826) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[103] <= 0.5518427975475788) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[2] <= 0.33330973982810974) {
        
            
    if (x[75] <= 0.08289218414574862) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[111] <= 0.17766954191029072) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    if (x[28] <= 0.046525053679943085) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }

        
    }
    else {
        
            
    if (x[57] <= 0.5310525596141815) {
        
            
    if (x[112] <= 0.14862050116062164) {
        
            
    if (x[40] <= 0.06038179434835911) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[123] <= 0.1867407262325287) {
        
            
    if (x[50] <= 0.027964655309915543) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    if (x[39] <= 0.05603167042136192) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[105] <= 0.154810331761837) {
        
            
    if (x[110] <= 0.08112771436572075) {
        
            
    if (x[65] <= 0.45561954379081726) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[57] <= 0.6225695312023163) {
        
            
    if (x[37] <= 0.029015579260885715) {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }
    else {
        
            
    if (x[99] <= 0.009332598187029362) {
        
            
    if (x[46] <= 0.04988980293273926) {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }
    else {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[7] <= 0.49448050558567047) {
        
            
    if (x[68] <= 0.1152210608124733) {
        
            
    if (x[34] <= 0.13007009029388428) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }
    else {
        
            
    if (x[77] <= 0.464005246758461) {
        
            
    if (x[67] <= 0.09719692543148994) {
        
            
    *classIdx = 3;
    *classScore = 1026.0;
    return;

        
    }
    else {
        
            
    if (x[65] <= 0.4737531244754791) {
        
            
    if (x[47] <= 0.992998480796814) {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }

        
    }

        
    }
    else {
        
            
    if (x[18] <= 0.7166556417942047) {
        
            
    if (x[85] <= 0.09961009211838245) {
        
            
    *classIdx = 2;
    *classScore = 1031.0;
    return;

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }
    else {
        
            
    *classIdx = 1;
    *classScore = 961.0;
    return;

        
    }

        
    }

        
    }

        
    }

        
    }

        
    }

            }
        
    


};



static RandomForestClassifier classifier;


#endif

And this is the main code to put in the .ino file.

#include "eloquent.h"
#include "eloquent/print.h"
#include "eloquent/tinyml/voting/quorum.h"

// replace 'm5wide' with your own model
// possible values are 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/m5wide.h"

#include "HogPipeline.h"
#include "HogClassifier.h"

Eloquent::TinyML::Voting::Quorum<7> quorum;


void setup() {
  Serial.begin(115200);
  delay(3000);
  Serial.println("Begin");

  camera.qqvga();
  camera.grayscale();

  while (!camera.begin())
    Serial.println("Cannot init camera");
}

void loop() {
  if (!camera.capture()) {
      Serial.println(camera.getErrorMessage());
      delay(1000);
      return;
  }
  
  // apply HOG pipeline to camera frame
  hog.transform(camera.buffer);

  // get a stable prediction
  // this is optional, but will improve the stability of predictions
  uint8_t prediction = classifier.predict(hog.features);
  int8_t stablePrediction = quorum.vote(prediction);

  if (quorum.isStable()) {
    eloquent::print::printf(
      Serial, 
      "Stable prediction: %s \t(DSP: %d ms, Classifier: %d us)\n", 
      classifier.getLabelOf(stablePrediction),
      hog.latencyInMillis(),
      classifier.latencyInMicros()
    );
  }

  camera.free();
}

Hit upload and put your objects in front of the camera: you will see the predicted label.

Demo video

If you follow the above steps, you will end with the following result.

You can see that the portenta and pi are mis-labelled quite often: this is expected result as we saw from the features pairplot.

"""
Play demo video
"""
from IPython.display import Video

Video("assets/esp32 image object classification live demo.mp4", width=728)

Processing time is 12 milliseconds, while classification time is < 20 microseconds (1 / 1000 th of DSP!). If you do the math, this translates to ~80 FPS, which is greater than your Esp32-cam frame rate.

In the next release of everywhereml, thanks to some approximated math, DSP will lower to 6 milliseconds (a.k.a. 160 FPS!)

Conclusion

When it comes to image recognition on Esp32-cam, you have two options:

  1. If you're looking for the best accuracy possibile, you should stick to Neural Networks: they achieve state-of-the-art results. Platforms like Edge Impulse will speed up your development time.
  2. If you're goal is to implement something that works good and really fast, you now have an alternative option to choose thanks to the Eloquent Arduino libraries.

Get the video tutorial

Enter your email to receive the 30 minutes walkthrough video tutorial of this project

We use Mailchimp as our marketing platform. By submitting this form, you acknowledge that the information you provided will be transferred to Mailchimp for processing in accordance with their terms of use. We will use your email to send you updates relevant to this website.

Having troubles? Ask a question

Need a one to one call? Book now!

© Copyright 2022 Eloquent Arduino. All Rights Reserved.