Ask Your Question
0

Machine Learning: NormalBayesClassifier no results [closed]

asked 2018-12-01 09:38:16 -0600

updated 2018-12-01 09:54:19 -0600

I created a small OpenCV program with 3 Machine Learning classifiers for a lab course to find red strawberries in an image. The green strawberries and everything else are removed from the image.

I use the following classifiers:

  • kNN
  • Normal Bayes
  • SVM

Environment:

  • CMake 3.12.4
  • GCC 8.2.1
  • CLion 2018.3
  • Arch Linux
  • OpenCV 3.4.4

They are all a subclass of ml::StatModel so I can use classifier->predict(pixel, label) to classify if the pixel is a strawberry or not. This works for kNN and SVM fine, but not for Normal Bayes for some reason. The mask is completely black. I added some screenshots of KNN and SVm results below.

Input: Input

KNN: KNN

SVM: SVM

I will re-enable (in the header) an opening and closing operation later to remove the noise and connect the blobs.

Here's my code:

strawberry.h

#ifndef SESSIE_5_3_STRAWBERRY_H
#define SESSIE_5_3_STRAWBERRY_H

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

#define KERNEL_SIZE 5
#define CIRCLE_THICKNESS -1
#define CIRCLE_RADIUS 5
#define KNN_GROUPS 3
#define ML_OPENING_ITER 0
#define ML_CLOSING_ITER 0
#define SVM_ITER 100
#define SVM_EPSILON 1e-6

void runner(int trackbarPos, void *data);
void mouse(int event, int x, int y, int flags, void* userdata);
void descriptor(Mat img, vector<Point2d> foregroundPoints, vector<Point2d> backgroundPoints, Mat&    trainingData, Mat& labels);
void KNN(Mat trainingsData, Mat labels);
void NaiveBayes(Mat trainingsData, Mat labels);
void SVM(Mat trainingsData, Mat labels);
void showResult(Ptr<ml::StatModel> classifier);

#endif //SESSIE_5_3_STRAWBERRY_H

main.cpp

#include "strawberry.h"

vector<Point2d> savedPositivePoints;
vector<Point2d> savedNegativePoints;
Mat strawberryImg;
int mode = 0;

void mouse(int event, int x, int y, int flags, void* userdata) {
if  ( event == EVENT_LBUTTONDOWN )
{
    cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    Point2d p = Point2d(x, y);
    if(mode) {
        savedPositivePoints.push_back(p);
    }
    else {
        savedNegativePoints.push_back(p);
    }
}
else if  ( event == EVENT_RBUTTONDOWN )
{
    cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    if(mode) {
        savedPositivePoints.pop_back();
    }
    else {
        savedNegativePoints.pop_back();
    }
}
else if  ( event == EVENT_MBUTTONDOWN )
{
    cout << "Middle button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    if(mode) {
        cout << "POSITIVE" << endl;
        for (int i = 0; i < savedPositivePoints.size(); i++) {
            cout << savedPositivePoints.at(i) << endl;
        }
    }
    else {
        cout << "NEGATIVE" << endl;
        for (int i = 0; i < savedNegativePoints.size(); i++) {
            cout << savedNegativePoints.at(i) << endl;
        }
    }
}

runner(0, NULL);
}

void descriptor(Mat img, vector<Point2d> foregroundPoints, vector<Point2d> backgroundPoints, Mat& trainingData, Mat& labels) {
Mat hsv;
Mat trainingDataForeground(foregroundPoints.size(), 3, CV_32FC1);
Mat trainingDataBackground(backgroundPoints.size(), 3, CV_32FC1);
Mat labels_fg = Mat::ones(foregroundPoints.size(), 1, CV_32SC1);
Mat labels_bg = Mat::zeros(backgroundPoints.size(), 1, CV_32SC1);
cvtColor(img, hsv, CV_BGR2HSV);

// foreground
for(int i=0; i < foregroundPoints.size(); i++) {
    Vec3b pixel = hsv.at<Vec3b>(foregroundPoints.at(i).y, foregroundPoints.at(i).x);
    trainingDataForeground.at<float>(i, 0) = pixel[0];
    trainingDataForeground.at<float>(i, 1) = pixel[1];
    trainingDataForeground.at<float>(i, 2) = pixel[2];
}

// background
for(int i=0; i < backgroundPoints.size(); i++) {
    Vec3b pixel = hsv.at<Vec3b>(backgroundPoints ...
(more)
edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by DylanVanAssche
close date 2018-12-03 13:24:45.410088

Comments

please put you code here, not on a pastebin, that will expire, thank you.

berak gravatar imageberak ( 2018-12-01 09:40:50 -0600 )edit
1

I will do that, I did it on pastebin to avoid a very long question full of code.

DylanVanAssche gravatar imageDylanVanAssche ( 2018-12-01 09:46:32 -0600 )edit

better than a question with no / expired code ;)

berak gravatar imageberak ( 2018-12-01 09:50:38 -0600 )edit

That's true!

DylanVanAssche gravatar imageDylanVanAssche ( 2018-12-01 09:51:36 -0600 )edit

O_0, -- can it be, this is one of steven's assigments ? 2018_labo_beeldinterpretatie ? ;)

berak gravatar imageberak ( 2018-12-01 09:53:24 -0600 )edit
1

I know, he's a famous guy here :) It's indeed the 5th session of 2018_labo_beeldinterpretatie.

DylanVanAssche gravatar imageDylanVanAssche ( 2018-12-01 09:55:08 -0600 )edit

@berak hahaha great xD @DylanVanAssche might want to come by the office and ask mr Callemein if he can help you out :D Maybe have a look at how you visualize data. Do all 3 classifiers return the same range of values?

StevenPuttemans gravatar imageStevenPuttemans ( 2018-12-01 20:58:59 -0600 )edit
2

@StevenPuttemans I just wanted to apply good lab practices first: use the Internet :)

You set me on the right track! I found the issue now :) I will answer the question with the solution.

EDIT: I have to wait until tomorrow to post the answer due SPAM restriction since I'm a new user.

DylanVanAssche gravatar imageDylanVanAssche ( 2018-12-02 02:31:07 -0600 )edit
1

hehe, found this on my disk ;)

        // ATTENTION
        // NaiveBayes --> output resultaten als integer labels 32S -> int jump
        // SVM --> output resultaten als floating point labels 32F -> float jump
        mask_normalBayes.at<uchar>(i,j) = labels_normalBayes.at<int>(0,0);
        mask_SVM.at<uchar>(i,j) = labels_SVM.at<float>(0,0);

(imho, we can "give it away", because you already found a solution...)

berak gravatar imageberak ( 2018-12-02 08:54:53 -0600 )edit

That's probably the issue. I replace these lines with an IF test which covers both label types.

DylanVanAssche gravatar imageDylanVanAssche ( 2018-12-02 09:38:37 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2018-12-03 12:23:43 -0600

updated 2018-12-03 12:24:10 -0600

Ask @berak pointed out and thanks to @StevenPuttemans to put me on the right track:

mask_normalBayes.at<uchar>(i,j) = labels_normalBayes.at<int>(0,0);
mask_SVM.at<uchar>(i,j) = labels_SVM.at<float>(0,0);

By changing the cast to an IF test we can test the labels of all 3 classifiers:

mask.at<uchar>(r, c) = (uchar)label.at<float>(0, 0); // CV_32F results

Change it to:

if((uchar)label.at<float>(0, 0)) {
    mask.at<uchar>(r, c) = 1;
}

Now it works!

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2018-12-01 09:38:16 -0600

Seen: 297 times

Last updated: Dec 03 '18