3

I have found the following example in the OpenCV documentation for using k-NN. Now my task is to convert the following code to Java and to do some changes on it because my data is not image. I have some difficulties to understand what is happening in the example.


First have is a look at the code:

#include "ml.h"
#include "highgui.h"

int main( int argc, char** argv )
{
    const int K = 10;
    int i, j, k, accuracy;
    float response;
    int train_sample_count = 100;
    CvRNG rng_state = cvRNG(-1);
    CvMat* trainData = cvCreateMat( train_sample_count, 2, CV_32FC1 );
    CvMat* trainClasses = cvCreateMat( train_sample_count, 1, CV_32FC1 );
    IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
    float _sample[2];
    CvMat sample = cvMat( 1, 2, CV_32FC1, _sample );
    cvZero( img );

    CvMat trainData1, trainData2, trainClasses1, trainClasses2;

    // form the training samples
    cvGetRows( trainData, &trainData1, 0, train_sample_count/2 );
    cvRandArr( &rng_state, &trainData1, CV_RAND_NORMAL, cvScalar(200,200), cvScalar(50,50) );

    cvGetRows( trainData, &trainData2, train_sample_count/2, train_sample_count );
    cvRandArr( &rng_state, &trainData2, CV_RAND_NORMAL, cvScalar(300,300), cvScalar(50,50) );

    cvGetRows( trainClasses, &trainClasses1, 0, train_sample_count/2 );
    cvSet( &trainClasses1, cvScalar(1) );

    cvGetRows( trainClasses, &trainClasses2, train_sample_count/2, train_sample_count );
    cvSet( &trainClasses2, cvScalar(2) );

    // learn classifier
    CvKNearest knn( trainData, trainClasses, 0, false, K );
    CvMat* nearests = cvCreateMat( 1, K, CV_32FC1);

    for( i = 0; i < img->height; i++ )
    {
        for( j = 0; j < img->width; j++ )
        {
            sample.data.fl[0] = (float)j;
            sample.data.fl[1] = (float)i;

            // estimate the response and get the neighbors' labels
            response = knn.find_nearest(&sample,K,0,0,nearests,0);

            // compute the number of neighbors representing the majority
            for( k = 0, accuracy = 0; k < K; k++ )
            {
                if( nearests->data.fl[k] == response)
                    accuracy++;
            }
            // highlight the pixel depending on the accuracy (or confidence)
            cvSet2D( img, i, j, response == 1 ?
                (accuracy > 5 ? CV_RGB(180,0,0) : CV_RGB(180,120,0)) :
                (accuracy > 5 ? CV_RGB(0,180,0) : CV_RGB(120,120,0)) );
        }
    }

    // display the original training samples
    for( i = 0; i < train_sample_count/2; i++ )
    {
        CvPoint pt;
        pt.x = cvRound(trainData1.data.fl[i*2]);
        pt.y = cvRound(trainData1.data.fl[i*2+1]);
        cvCircle( img, pt, 2, CV_RGB(255,0,0), CV_FILLED );
        pt.x = cvRound(trainData2.data.fl[i*2]);
        pt.y = cvRound(trainData2.data.fl[i*2+1]);
        cvCircle( img, pt, 2, CV_RGB(0,255,0), CV_FILLED );
    }

    cvNamedWindow( "classifier result", 1 );
    cvShowImage( "classifier result", img );
    cvWaitKey(0);

    cvReleaseMat( &trainClasses );
    cvReleaseMat( &trainData );
    return 0;
}

Link to the source

Now the questions.
1. What is cvRNG's type. Couldn't find it in Java version of OpenCV
2. CvMat sample = cvMat( 1, 2, CV_32FC1, _sample ); - needs a four field constructor which is not available in java.
3. Why do i need to form the training samples? And how do i do this? Here is a mention that "Only CV_ROW_SAMPLE data layout is supported." What does it mean?


All kinds of additional working examples are welcome besides the answers.=)

Gombat
  • 1,994
  • 16
  • 21
Jürgen K.
  • 3,427
  • 9
  • 30
  • 66

1 Answers1

3

The example starts by generating random training data. It builds an Nx2 matrix of training samples (N=100 2D points), along with corresponding class labels (Nx1 matrix). Thus the samples have a "row layout", each row being one sample.

The generated data is split in two; in the first half (N/2)x2 samples are generated from a normal-distribution with mean=200 and variance=50 (both X and Y coordinates), belonging to the first class class=1. Similarly the second half is generated from X~N(300,50) and tagged as having class=2.

So you could imagine the data looking like two blobs of points in 2D space diametrically opposed.

Next we create the K-nearest neighbor classifier (K=10 in the example), and we feed it our training set.

Then the code loops over the grid of points in the range 500x500 (i.e we go over the 2D points [0,0], [0,1], ..., [1,0], [1,1], ... [499,499]). For each point, we use the classifier to find the K-nearest neighbors (based on Euclidean distance) and their corresponding class labels, as well as predicting the label of the grid point (based on a majority vote from the nearest neighbors). It computes a "confidence" measure (by counting how many of the K=10 nearest neighbors have the same class as the predicted one).

We store the predictions in an image of the same size as the grid (500x500), color-coded to represent the class (1 or 2), with the color intensity representing the prediction confidence.

Finally, it plots the original data samples on top of the image, with points colored with their true class label, and shows the resulting image.

Now I didn't run that exact same code, but I imagine it would give something like the following:

classification

I wrote this in . Here is my code in case you're interested (I'm using mexopencv, a toolbox of MATLAB wrappers for OpenCV):

% random training set generated from two normal distributions
N = 100;  % number of training samples
trainData = [randn(N/2,2)*50+200; randn(N/2,2)*50+300];
trainClass = int32([ones(N/2,1)*1; ones(N/2,1)*2]);

% kNN classifier
K = 10;
knn = cv.KNearest();
knn.train(trainData, trainClass);

% build grid of 2D points, predict and find K nearest neigbords
sz = [500 500];
[X,Y] = ndgrid(1:sz(1), 1:sz(2));
[pred,IDX] = knn.findNearest([X(:) Y(:)], K);

% compute prediction confidence
conf = sum(bsxfun(@eq, IDX, pred),2) ./ K;

% evaluate classifier on training set
acc = nnz(knn.predict(trainData) == trainClass) * 100 / N;

% plot (color-coded by class, transparency indicates confidence)
clr1 = lines(2);
clr2 = brighten(clr1, -0.6);
imagesc(ind2rgb(reshape(pred,sz), clr1), 'AlphaData',reshape(conf,sz))
hold on
scatter(trainData(:,1), trainData(:,2), [], clr2(trainClass,:), 'filled')
hold off; xlabel X; ylabel Y;
title(sprintf('kNN Classification Accuracy = %.1f%%',acc))
Amro
  • 123,847
  • 25
  • 243
  • 454