0

I have a SVM classifer saved as "classifier.xml". I take input images from webcam and want to classify them. So, instead of loading the classifier for each input image, i just want to load the classifier only once (something like static) using the following code:

mySvm.load("classifier.xml");

PROBLEM: Currently i have declared cv::SVM mySvm; as global variable but i want to get rid of global variable. So, what should i do to make cv::SVM mySvm; as a member variable of Class Classifier ?

The structure of my files is following:

(1) classifier.h

class Classifier
{
    private:


    public:
        void getSvm();
};

(2) main.cpp

int main()
{
    Classifier objectSvm;
    objectSvm.getSvm();                     
}

(3) loadSVM.cpp

#include "classifier.h"

cv::SVM mySvm;
void svm::getSvm()
{
    mySvm.load("classifier.xml");
}
user2756695
  • 676
  • 1
  • 7
  • 22
  • Use a static class variable, or class variable of a re-used class? `cv::SVM mySvm;` moves under `private:` in classifier.h. It could optionally be marked `static`. If you're concerned about early header pull-in, forward declare `namespace cv{class SVM;}`. –  Mar 10 '14 at 15:06
  • i tried to use it as a static member variable by using `cv::SVM Classifier::mySvm.load("classifier.xml");` in `main()` but it is giving me error – user2756695 Mar 10 '14 at 15:09
  • maybe a `private: static cv::SVM mySvm;` and a `private: static mInitialized = false;` and `cv::SVM getSVM()` getter which calls `.load("classifier.xml");` only if `initialized == false`? would be some kind of singleton. – Micka Mar 10 '14 at 15:10
  • @Micka OP would have already had the same problem using a global unprotected from reload of the XML. user2756695 what is the error you are getting? Is it compile time or run time? PS - `Classifier::mySvm.load("classifier.xml");` is a static method not a static variable. –  Mar 10 '14 at 15:11
  • @ebyrob: I don't think he gets any error, as far as I understand the question (it's not so clear as far as I see) he just wants to get rid of the (working) global variable declaration. – Micka Mar 10 '14 at 15:16
  • @ebrob: I am getting error only if i try to declare it as `static` variable in the class. The complie time error is: `Classifier.h:55:18: error: expected initializer before ‘.’ token` – user2756695 Mar 10 '14 at 15:20
  • @Micka: Yes, i just wantto get rid of global variable. So, i tried to declare it as `static` member variable. But then i got the error. My ultimate aim is to get rid of global varibale. – user2756695 Mar 10 '14 at 15:21
  • @user2756695 That's a compiler error. I don't have the code, nor do I know which line in the code I don't have it was for... Makes it hard to diagnose. See my answer below, I kind of recommend against making this `static`. If you want it to be available in some kind of singleton, then put it in one or make a separate class that has a static one of these in it. (Note: splitting the load() from constructor as faranwath does is OK too) The method prefix "get" is misleading since it usually means you're returning something back that was retrieved, not doing an internal read operation. –  Mar 10 '14 at 15:22

2 Answers2

0

You can use a static member variable and provide a way to access it:

class Classifier
{
private:
    static cv::SVM svm;

public:
    void loadSvm(const char* fileName) { /* code for loading SVM */ }
    cv::SVM& getSVM() { return svm; }
};

Member function loadSVM does the loading, and getSVM simply returns a reference to the variable.

If you're concerned about a user loading the SVM more than once, add a static member of type bool that indicates whether or not the object has been loaded.

class Classifier
{
private:
    static cv::SVM svm;
    static bool already_loaded = false; // required C++11

public:
    void loadSvm(const char* fileName)
    {
        if (already_initialized)
            return;

        // code for loading SVM
    }

    cv::SVM& getSVM() { return svm; }
};

You then create an instance of Classifier as usual and load the XML.

int main()
{
    Classifier c;
    c.loadSVM("foo.xml");

    // Whenever you want to use the SVM, go for member function `getSVM()`.
    // E.g. assuming the SVM has a `foo` member function:
    c.getSVM().foo();
}
  • Sorry, i don't have much programming skills...can you tell me how to do it by using the statement i have used in my question i.e. `mySvm.load("classifier.xml");` – user2756695 Mar 10 '14 at 15:14
  • why this `cv::SVM& getSVM() { return svm; }` is required when i am loading the SVM in `void loadSvm()` ? – user2756695 Mar 10 '14 at 15:17
  • Because the static member variable is `private`. This function gives you a reference to it. –  Mar 10 '14 at 15:21
  • @faranwath I'm guessing he's got other functions that do stuff that he didn't share with us, and that his `getSVM()` method is simply misnamed... (ie: could be load etc) –  Mar 10 '14 at 15:28
  • I see. Without additional information, there's really not much I (we) can do. –  Mar 10 '14 at 15:36
0

(1) classifier.h

namespace cv { class SVM; }
class Classifier
{
    private:
        cv::SVM mySvm;
        void loadSvm();

    public:
        Classifier();
        void getSvm();
};

(3) loadSVM.cpp

#include "classifier.h"

void Classifier::loadSVM() {  mySvm.load("classifier.xml"); }
Classifier::Classifier() { /* loadSVM(); could load early */ }
void Classifier::getSvm() { loadSVM(); }

(2) main.cpp

int main()
{
    Classifier objectSvm;
    objectSvm.getSvm();   // loading happens on this line, as your example
                          // loading only shared for this instance of Classifier

    objectSvm.doSomething();
    objectSvm.doSomethingAgainWithSameClassifier();

    Classifier objectSvmAnother;
    objectSvmAnother.getSvm();  // load another classifier

    objectSvmAnother.doSomethingWithDifferentClassifierInstance();
}
  • what is the purpose of `Classifier()` ? – user2756695 Mar 10 '14 at 15:39
  • `Classifier` is your class. Therefore `Classifier()` is the default constructor of your class. I'm putting it here expliclity, where it's normally compiled in implicitly. I did that to show you could read the xml configuration there, if you're so inclined, rather than putting it in a "load" type method which is called later. –  Mar 10 '14 at 15:41
  • This method didn't work. My other functions/methods couldn't get the same copy of `mySvm` – user2756695 Mar 10 '14 at 15:48
  • @user2756695 If you just want a global this is how you can create a singleton class which you would make this a retrievable member of: http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289 Although, to be honest singletons and static-members have a lot of the same problems that globals had. Alternatively you could have `class StaticClassifier { public: static Classifier mySvm; };` But you'd want the initialization in the constructor in that case... Access as: `StaticClassifier::mySvm;` –  Mar 10 '14 at 16:13