0

I am trying to execute based on example code:

  using namespace cv;
  using namespace cv::ml;
  // mat is a Mat containing the features computed beforehand
  Ptr<EM> model = EM::create();
  model->setClustersNumber(static_cast<int>(m_numberClusters));
  Mat logs, labels, probs;
  model->trainEM(mat, logs, labels, probs);

setClustersNumber gives a segmentation fault, if commented out then trainEM does. Debugging reveals, that those are pure virtual functions, which is in coincidence with OpenCV API.

See here:

enter image description here

Nevertheless I do not find any implementation class having those pure virtual functions nor other examples for Expectation Maximization by OpenCV with 3.x.x versions.

enter image description here

enter image description here

Jan Hackenberg
  • 481
  • 3
  • 14
  • Have you tried debugging? You should check if `model` ptr is valid before dereferencing it. Where is the variable `mat` defined, that gets passed into the `trainEM` method? – Mansoor Jan 29 '21 at 22:29
  • @M.A yes I did debug, the vPtr reveals that the named functions are pure virtual. As written in the doc line, the mat is computed beforehand. Its valid and also the EM Ptr. Its just that the functions are not implemented. I took code from here: https://programming.vip/docs/gmm-gaussian-mixture-model-method-for-opencv-image-segmentation.html – Jan Hackenberg Jan 29 '21 at 22:33
  • I don't understand what you mean by, `I do not find any implementation of this pure virtual class`, if you did debug, you know the underlying type of the model ptr, this class has the override definition for the setClusterNumber function or one of its base classes. Either you get a segfault when you call the functions, in which case the ptr is not valid, or inside the function, in which case either the model ptr was not constructed correctly or argument passed into the setClustersNumber is not valid. – Mansoor Jan 29 '21 at 22:36
  • @M.A pure virtual functions I meant, the ones I am calling. I added a screenshot and corrected the sentence. – Jan Hackenberg Jan 29 '21 at 22:47
  • Ok, but they can't actually be abstract right, because your compiler would not let you instantiate an abstract type (a type which has an abstract function). – Mansoor Jan 29 '21 at 22:53
  • @M.A this is also what I would assume, but I added a second screenshot which has pure_virtual in the call stack – Jan Hackenberg Jan 29 '21 at 23:07
  • apologies, I was not aware this type of error was possible, but looks like it is, [see here](https://stackoverflow.com/questions/920500/what-is-the-purpose-of-cxa-pure-virtual) and [here](https://stackoverflow.com/questions/99552/where-do-pure-virtual-function-call-crashes-come-from). – Mansoor Jan 29 '21 at 23:12
  • @M.A but I do not even cause the function calls through constructor or destructor. – Jan Hackenberg Jan 29 '21 at 23:23
  • That is just a pathological example. Either way, you either need to define a derived class which implements the interface provided by EM type or use an existing one in the library. – Mansoor Jan 29 '21 at 23:26
  • It's an unlucky scenario because your compiler can only see the interface provided by the OpenCV library, so can't know the dynamic type of what is returned by the `EM::create` static function. So it doesn't know that it actually returns an abstract type. And whatever was compiling the OpenCV library, doesn't care, because its not instantiating any abstract types. I think this is a poor API, why would they provide a create static function that returns an abstract type. – Mansoor Jan 29 '21 at 23:33
  • Out of interest, what happens if you call the virtual function on the temporary rhs of the `EM::Create`, i.e. `EM::Create()->setClusterNumber();` – Mansoor Jan 29 '21 at 23:52

1 Answers1

1

This runtime error is explained by these other answers 1 & 2.

The EM::Create static method returns a ptr to an abstract type, I think this is a poor API design choice. The intention is likely for you to define a derived type that overrides these abstract methods. Since static methods don't have access to the current object, I don't see what purpose it serves.

It may be the case that your compiler has no way of knowing the dynamic type of the object, which happens to be abstract. The single layer of indirection, because of the pointer, may make it difficult for the compiler to detect this issue. Here is a contrived example (godbolt).

struct a
{
    a(int) {};
    virtual int test() = 0;

    static a* Create() {return (a*)(new int{});};
};

int main()
{
    auto aptr = a::Create();
    aptr->test();
}
Mansoor
  • 2,357
  • 1
  • 17
  • 27
  • @JanHackenberg Override methods in a derived class of your own or create a ptr to a concrete type in OpenCV that derives from EM type. Sorry if that wasn't clear – Mansoor Jan 30 '21 at 10:13
  • I tried to find in OpenCV already a concrete type to be able to cast that pointer, but did not find one. Overriding the two functions in a dummy class I tried now to force the vPtr table to be updated correctly, if I understood you here correctly. But it did not work. Writing a non dummy class providing needed functions correctly implemented is out of possibilities. – Jan Hackenberg Jan 30 '21 at 14:52
  • 1
    Can you elaborate on, it didn't work. If you derived a custom class from EM and overrride the abstract methods, then create an instance of that type, you don't even need to rely on virtual lookup, just use a pointer to the derived type. And, your compiler will warn you if you try instantiating without overriding all abstract methods. Also note that you cannot use the EM::Create method to create the derived type. – Mansoor Jan 30 '21 at 14:59
  • 1
    If I have to use my derived class instead of the one from EM::Create I have to implement complete machine learning methods. This is what I meaned is out of possibilities. I thought I could fix the virtual lookup, by just implementing a dervided class with empty dummy functions calls and not using it. That seems not to be the case. There is defenitely a concrete class behind the EM::Create, as I can execute my compiled code on a win machine with VS instead of GCC. But I do not find that concrete class in OpenCV. – Jan Hackenberg Jan 30 '21 at 16:05