perClass Documentation
version 5.4 (7-Dec-2018)

Chapter B: Getting Started with perClass and Cubert spectral camera

Table of contents

B.1. Introduction ↩

This tutorial explains how to build classification solutions with perClass software package to develop classification solutions integrated with Cubert spectral cameras.

B.2. Installation ↩

Cubert Utilities 2.0.4 (Fuchsia) contains perClass 5.1 installation.

Cubert Utilities 2.0.6 contains perClass 5.2 installation.

During installation, make sure "perClass Toolbox and SDK" and "DEMO classifier Plug-ins (perClass)" options are selected.

Installing perClass as a part of Cubert utilities package

B.3. Nut classifier FREE demo example ↩

perClass bundled with Cubert utils contains a free demo example classifier for nuts (amandels, peanuts).

Visualizing hyperspectral perClass classifier in Cubert Touch, step1

Visualizing hyperspectral perClass classifier in Cubert Touch, step2

Visualizing hyperspectral perClass classifier in Cubert Touch, step3

Selecting the nuts perClass classifier in the Cubert Utils Touch

perClass classifier separating peanuts and amandels in Cubert Utils Touch

B.4. Activating perClass Demo ↩

In order to develop your own custom classifier with perClass, a demo license needs to be activated. There are two components of the software,namely perClass Toolbox for Matlab and perClass Runtime integrated in Cubert Utils. Therefore, two activation keys are needed.

B.4.1. Activating perClass Runtime ↩

perClass Runtime is activated from within Cubert Utils Touch interface. Go to settings and others (three-dot symbol). Click on "Activate perClass" link.

Activating perClass Runtime from Cubert Utils Touch

Fill-in the activation code "RUNTIME-XXXX-XXXX-XXXX-XXXX".

Activating perClass Runtime from Cubert Utils Touch

Activating perClass Runtime from Cubert Utils Touch

B.4.2. Activating perClass Toolbox ↩

perClass Toolbox is activated from within Matlab environment.

Adding perClass on Matlab path

Activation is initiated by the sdactivate command. Provide activation key formated as "TOOLBOX-XXXX-XXXX-XXXX-XXXX"

>> sdactivate('TOOLBOX-1699-2295-1553-5145')
perClass Demo 5.1 (30-May-2017), Copyright (C) 2007-2017, PR Sys Design, All rights reserved
Demo license. For evaluation purposes only.
 Customer:  ()  Issued: 21-sep-2017
 Toolbox with DB,imaging,export: The license expires on 24-sep-2017.
Activation successful, the license file written to 'C:\Program Files\CubertFuchsia\perClass\perClass_Pro_5.1_29may17\perclass\perclass.lic'.
ans =
     1

B.5. Building nut classifier ↩

In this example, we build a custom nut classifier classifying peanuts and almonds. The data set contains the following images:

image index     classes
----------------------------------------
5, 7           peanuts + almonds
9              peanuts only
29             almonds only
19             hand
47,54          pine seeds only
70,71          walnuts only
79, 80         almonds (normal + open)

Load a hyperspectral image. We will first load the 002_Auto_009_snapshot_cube.tiff image containing only peanuts.

>> im9=sdimage('perclass_nut_data_set_jun17\v002\000k\002_Auto_009_snapshot_cube.tiff','sddata')
2500 by 138 sddata, class: 'unknown'
>> sdimage(im9)
ans =
     1

The sdimage command with 'sddata' option returns a data set containing 2500 image pixels, each with 138 wavelengths. In machine learning terminology, pixels are sampels of our data set and wavelengths are features. Each data sample in perClass has a class label, by default 'unknown'.

Second command opens visualization figure showing image content. By clicking up/down cursor, we can change image band. Note, that some bands show high-values for few (outlier) pixels. While for genuine data, values range in low thousands, for these pixels, some wavelength values are over 60000.

We will first remove these outlier pixels. We could, for example, project the data in suitable subspace and hand-draw polygon classifier enclosing the good data domain. There is, however, an easier way removing these outliers using sdbox command. We may provide it with a range of valid data values. As this solution is simpler and more robust, we will adopt it in this example.

Note, that we need sdbox command from perClass 5.2. If your perClass version is 5.1 (which can be checked with sdversion command), you need to download sdbox.m and sdbox.p files from http://perclass.com/cubert/ and copy them to perclass directory. Exact location of your perclass directory is displayed with sdversion command. Older sdbox files can be overwritten.

We will use sdbox to accept only data in the data range 0 to 50000:

>> p=sdbox(im9,'bounds',[0 50000])
sequential pipeline       138x1 'Box classifier+Decision'
 1 Box classifier        138x1 
 2 Decision                1x1  threshold on 'inside'

If sdbox command with 'bounds' option returns 'unknown option bounds' error, you use older version from perClass 5.1. Make sure the files you downloaded above were correctly copied to the perclass directory.

The sdbox command returns a "pipeline" which can be applied to new data by multiplication. Result is a decision 'inside' or 'outside':

>> dec=im9*p
sdlab with 2500 entries, 2 groups: 'inside'(2457) 'outside'(43) 

We only preserve pixels that fall inside the above-defined range:

>> im9( dec=='inside' )
2457 by 138 sddata, class: 'unknown'

Visualizing the image content without outliers:

>> sdimage( im9( dec=='inside' ) )
ans =
     4

Image with outliers removed

Now, we need to label objects and background. One way would be to use label painting feature. Faster alternative is to apply data clustering and discover underlying clusters.

To initiate k-means clustering procedure from image figure, press 'k'. A dialog will open asking for number of clusters. In our case, we're interested in two, assuming there is a clear separation between background and object spectra. The clustering result is shown on the following screenshot:

Defining image label by k-means clustering

We have enabled image legend (by pressing 'l' key or clicking legend button on the toolbar). Note, that the names of clusters are automatically generated C1 and C2. We need to interpret which one is background and which one represents peanuts. Note also, that re-running the clustering may result in "flipped" naming due to random initialization. If you wish to re-run the clustering, first move to the original 'class' labels by perssing '1' or via "Image/Use labels/1 class" manu as the clustering result forms a new 'cluster' label set. Re-running clustering on 2-class 'cluster' labels would apply k-means to each class separately and produce four cluster result.

In order to define understandable names for the clusters, move mouse pointer to some background pixel and press 'r' to rename the cluster name into 'back' (Tip: in order to operate the Matlab default dialog without mouse, use the TAB key to move from the edit field to the OK button and press ENTER)

Similarly, rename the cluster representing objects in the image into 'peanut'. We may now save the data set into Matlab workspace by pressing 's' key (or "Image/Create data set in workspace" menu) and filling variable name (e.g. 'A').

Creating data set A in the workspace. 2457 by 138 sddata, 2 'cluster' groups: 'back'(1961) 'peanut'(496)

We will now load an image with almonds, remove outliers, cluster and define 'back' and 'almond' classes. Before saving the image data set to Matlab workspace variable 'B', make sure that the color or 'almond' class is not red. You may, for example, move mouse to a 'almond' pixel, press 'c' and select the color from a dialog or press '.' (dot) to randomly change color of class under cursor. The colors defined in the image data set will be propagated to the trained classifier and later to visualization in Cubert Utils.

>> im29=sdimage('perclass_nut_data_set_jun17\v002\000k\002_Auto_029_snapshot_cube.tiff','sddata')
2500 by 138 sddata, class: 'unknown'
>> sdimage( im29( im29*p=='inside' ) )
ans =
     6
Creating data set B in the workspace.
2428 by 138 sddata, 2 'cluster' groups: 'back'(2017) 'almond'(411) 

B.6. Training Peanut/Amandel classifier ↩

We will join data sets A and B to form a full training set tr:

>> tr=[A;B]
4885 by 138 sddata, 3 'cluster' groups: 'back'(3979) 'peanut'(495) 'almond'(411) 

Note that vertical cat is used (denoted by semi-colon), because we join another set of samples in the same 138D feature-space. The resulting data set contains 4885 samples each labeled into one of the three classes, namely 'back', 'peanut' or 'almond'.

In order to build a classifier, we first perform PCA (Principal Component Analysis) to reduce input 138D representation into a lower, e.g. 20D subspace. Hyperspectral data can be typically compressed using PCA to few important dimensions without significant loss of information.

>> p1=sdpca(tr,20)
PCA pipeline              138x20  100% of variance

The sdpca command returns a pipeline that starts from 138D space and generated a new 20D data set. We may apply this pipeline to any 138D data set:

>> tr2=tr*p1
4885 by 20 sddata, 3 'cluster' groups: 'back'(3979) 'peanut'(495) 'almond'(411) 

We may visualize tr2 as any other data set using interactive scatter plot:

>> sdscatter(tr2)
ans =
     1

Interactive scatter plot sdscatter visualizing hyperspectral data

When opening scatter plot on our data set, some classes may have identical markers. It is useful to show leggend ('l' key or toolbar button). Class marker may be changed by right-click and "change marker" command in context menu. Into a dialog box, we may then fill-in the desired matlab marker such as 'r.' for red dot. Another usful option is to switch on the distribution plots by pressing 'd' or via toolbar.

We can see that the three classes in our data set have a uni-modal shape. Therefore, we will use Gaussian classifier:

>> pg=sdgauss(tr2)
sequential pipeline       20x1 'Gaussian model+Decision'
 1 Gaussian model         20x3  full cov.mat.
 2 Decision                3x1  weighting, 3 classes

This will train a Gaussian model on each of the classes and add a default decision step.

In order to create a pipeline that can be applied to raw spectra with 138 wavelengths, we need to join the PCA and classification steps:

>> P1=p1*pg
sequential pipeline       138x1 'PCA+Gaussian model+Decision'
 1 PCA                   138x20 100%% of variance
 2 Gaussian model         20x3  full cov.mat.
 3 Decision                3x1  weighting, 3 classes

Now, we may want to visualize classifier decision on an unseen image. Let us use the image 5 that contains both peanuts and almonds:

>> im5=sdimage('perclass_nut_data_set_jun17\v002\000k\002_Auto_005_snapshot_cube.tiff','sddata')
2500 by 138 sddata, class: 'unknown'

We show it without outliers:

>> sdimage( im5( im5*p=='inside' ) )
ans =
     2

In the image Figure, select "Image/Apply classifier..." command from menu or press 'd'. A dialog will open where we can specify a pipeline name ('P1' in our case).

Classifier decisions on a new hyperspeactral image.

B.7. Exporting perClass classifier for exacution from Cubert Utils ↩

In order to execute the classifier, we trained, outside Matlab in Cubert Utils, we need to export it. This is accomplished with sdexport command and 'Cubert' option. Cubert utils stores user-defined plugins in Bin\user\plugin directory (.e.g `c:\Program Files\CubertFuchsia\Bin\user\plugin`).

We will first change name of P1 pipeline to a descriptive string and then export it as Cubert plugin:

>> P1=setname(P1,'Almond/Peanut')
sequential pipeline       138x1 'Almond/Peanut'
 1 PCA                   138x20 100%% of variance
 2 Gaussian model         20x3  full cov.mat.
 3 Decision                3x1  weighting, 3 classes

>> sdexport(P1,'c:\Program Files\CubertFuchsia\Bin\user\plugin\clf1.xml','cubert')
Exporting pipeline to Cuber plugin file..ok
This pipeline requires perClass runtime version 4.0 (11-jul-2013) or higher.

We need to close and re-open Cubert Utils Touch as a list of user plugins is refreshed when starting. When we move to the list of images and select View mode, a new 'clf1' classifier option will appear. Selecting it, we will see almonds detected with a color we selected earlier in image figure:

Classifier decisions on a new hyperspeactral image.

We may note, that the split open almonds in images 79 and 80 are misclassified as peanuts.

Let us improve our classifier to accomodate split almonds. We will load the image 79, remove outliers:

>> im79=sdimage('C:\Users\pavel\Desktop\Cubert_share\v002\000k\002_Auto_079_snapshot_cube.tiff','sddata')
2500 by 138 sddata, class: 'unknown'

>> sdimage( im79( im79*p=='inside' ) )
ans =
     3

Labeling split almonds

We cluster the image to three clusters and label 'almond-open' separately. Resulting data set is saved into variable 'C':

Creating data set C in the workspace.
2475 by 138 sddata, 3 'cluster' groups: 'back'(1936) 'almond'(355) 'almond-split'(184) 

>> tr3=[A;B;C]
7360 by 138 sddata, 4 'cluster' groups: 'back'(5915) 'peanut'(495) 'almond'(766) 'almond-split'(184) 

>> p3=sdpca(tr3,20)
PCA pipeline              138x20  100% of variance

In addition to PCA, we use here also LDA (linear discriminant analysis also known as Fisher projection) to derive low-dimensional class-separating subspace:

>> p4=sdlda(tr3*p3)
LDA pipeline              20x3  

Again training Gaussian model:

>> pg=sdgauss(tr3*p3*p4)
sequential pipeline       3x1 'Gaussian model+Decision'
 1 Gaussian model          3x4  full cov.mat.
 2 Decision                4x1  weighting, 4 classes

>> P2=p3*p4*pg
sequential pipeline       138x1 'PCA+LDA+Gaussian model+Decision'
 1 PCA                   138x20 100%% of variance
 2 LDA                    20x3 
 3 Gaussian model          3x4  full cov.mat.
 4 Decision                4x1  weighting, 4 classes

>> P2=setname(P2,'Almond/Almond-Open/Peanut')
sequential pipeline       138x1 'Almond/Almond-Open/Peanut'
 1 PCA                   138x20 100%% of variance
 2 LDA                    20x3 
 3 Gaussian model          3x4  full cov.mat.
 4 Decision                4x1  weighting, 4 classes

>> sdexport(P2,'c:\Program Files\CubertFuchsia\Bin\user\plugin\clf2.xml','cubert')
Exporting pipeline to Cuber plugin file..ok
This pipeline requires perClass runtime version 4.0 (11-jul-2013) or higher.

We close and re-open Cubert Utils Touch and use 'clf2' plugin. The split almonds are now highlighted in yellow.

Hyperspectral classifier labeling also split almonds.

B.8. Where to go from here? ↩

We have seen how to use perClass to define labels and build classifiers and then export them to Cubert Utils.

Example of building SVC classifier on PCA-projeted spectra:

 >> tr3
 7360 by 138 sddata, 4 'cluster' groups: 'back'(5915) 'peanut'(495) 'almond'(766) 'almond-split'(184) 

 >> ps=sdsvc(tr3*p1,'rbf','C',10,'one-against-one')
 >> P4=p1*ps

You may want to include rejection decition discarding all data unseen in training

 >> P5=sdreject(P3,tr3,'reject',0.01)

etc.