Reputation: 4097
I am trying to make converting between a custom class and OpenCV easier.
Converting constructors allow us to declare a class without the explicit
keyword and construct from an alternate data type.
For example, we could declare two classes:
class Foo
{
public:
std::vector<int32_t> data;
Foo(int k) : data(k) {}
};
class FooProxy : public cv::Mat
{
public:
FooProxy(const Foo & foo) : cv::Mat(foo.data.size(), 1, CV_32SC1, (void*)foo.data.data()) {}
};
And then we can create a FooProxy
by setting it equal and then then using any OpenCV function we want:
Foo myFoo(3);
myFoo.data = { 1,2,3 };
FooProxy fp = myFoo;
fp.setTo(1);
float myNorm = cv::norm(fp);
std::cout << "myFoo: " << myFoo.data.at(0) << ", " << myFoo.data.at(1) << ", " << myFoo.data.at(2) << "\n";
std::cout << "fp: " << fp.at<int32_t>(0) << ", " << fp.at<int32_t>(1) << ", " << fp.at<int32_t>(2) << "\n";
std::cout << "The Norm is: " << myNorm << "\n";
with output:
myFoo: 1, 1, 1
fp: 1, 1, 1
The Norm is: 1.73205
However, I would much rather write:
float myNorm = cv::norm(myFoo);
and have c++ automatically convert myFoo
. Is this possible?
This works:
float myNorm2 = cv::norm(FooProxy(myFoo));
but not the simpler version.
Upvotes: 3
Views: 458
Reputation: 59912
You could create a conversion operator
class Foo
{
...
operator cv::Mat()
{
return cv::Mat(data.size(), 1, CV_32SC1, (void*)data.data());
}
};
Edit cv::norm
has the following overloads (notice no cv::Mat
):
cv::norm(const Matx< _Tp, m, n > &M)
cv::norm(const Matx< _Tp, m, n > &M, int normType)
cv::norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray()) // this is the one we want
cv::norm(InputArray src1, InputArray src2, int normType=NORM_L2, InputArray mask=noArray())
cv::norm(const SparseMat &src, int normType)
A cv::InputArray
can be constructed from a cv::Mat
, however you're only allowed 1 user-defined conversion implicitly. So you'll actually need a conversion operator for cv::InputArray
if you want Foo
to work with cv::norm
.
Upvotes: 3
Reputation: 18331
namespace cv{
float norm(const Foo& foo){
return cv::norm(FooProxy(foo));
}
}
Now you can call:
float res = cv::norm(myFoo);
//! 2018.01.17 09:42:16 CST
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
class Foo
{
public:
std::vector<int32_t> data;
Foo(int k) : data(k) {}
};
class FooProxy : public cv::Mat
{
public:
FooProxy(const Foo & foo) : cv::Mat(foo.data.size(), 1, CV_32SC1, (void*)foo.data.data()) {}
};
namespace cv {
float norm(const Foo& foo) {
return cv::norm(FooProxy(foo));
}
}
int main() {
Foo myFoo(3);
myFoo.data = { 1,2,3 };
FooProxy fp = myFoo;
fp.setTo(1);
float myNorm = cv::norm(fp);
std::cout << "myFoo: " << myFoo.data.at(0) << ", " << myFoo.data.at(1) << ", " << myFoo.data.at(2) << "\n";
std::cout << "fp: " << fp.at<int32_t>(0) << ", " << fp.at<int32_t>(1) << ", " << fp.at<int32_t>(2) << "\n";
std::cout << "The Norm is: " << myNorm << "\n";
float myNorm2 = cv::norm(FooProxy(myFoo));
std::cout << "The Norm2 is:"<<myNorm2<<endl;
float myNorm3 = cv::norm(myFoo);
std::cout << "The Norm3 is:"<<myNorm2<<endl;
}
myFoo: 1, 1, 1
fp: 1, 1, 1
The Norm is: 1.73205
The Norm2 is:1.73205
The Norm3 is:1.73205
Upvotes: 2