【问题标题】:Automatically convert one c++ type to another自动将一种 c++ 类型转换为另一种
【发布时间】:2018-06-25 19:38:45
【问题描述】:

我正在尝试使自定义类和 OpenCV 之间的转换更容易。

Converting constructors 允许我们声明一个没有explicit 关键字的类并从备用数据类型构造。

例如,我们可以声明两个类:

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()) {}
};

然后我们可以创建一个FooProxy,方法是将其设置为相等,然后使用我们想要的任何 OpenCV 函数:

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";

带输出:

myFoo: 1, 1, 1
fp: 1, 1, 1
The Norm is: 1.73205

但是,我更愿意写:

float myNorm = cv::norm(myFoo);

并让 c++ 自动转换 myFoo。这可能吗?

这行得通:

 float myNorm2 = cv::norm(FooProxy(myFoo));

但不是更简单的版本。

【问题讨论】:

    标签: c++ opencv type-conversion


    【解决方案1】:

    你可以创建一个conversion operator

    class Foo
    {
      ...
    
      operator cv::Mat()
      {
        return cv::Mat(data.size(), 1, CV_32SC1, (void*)data.data());
      }
    };
    

    编辑 cv::norm 有以下重载(注意没有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)
    

    cv::InputArray 可以从 cv::Mat 构造,但是您只能隐式地进行 1 次用户定义的转换。因此,如果您希望 Foocv::norm 一起使用,您实际上需要 cv::InputArray 的转换运算符。

    【讨论】:

    • 这是一个很好的解决方案。有没有办法不让转换运算符成为 Foo 类的成员,这样我就不需要对 OpenCV cv::Mat 的所有使用 Foo 的依赖?
    • @Steve 不幸的是,没有,进行隐式转换的唯一方法是使用构造函数和转换运算符
    • 我尝试运行这段代码,但失败了!错误:没有匹配函数调用‘norm(Foo&)’float myNorm3 = cv::norm(myFoo);
    • 我很害怕,我怀疑它可能不起作用,因为cv::norm 没有cv::Mat 的签名,它有InputArray 的重载但我认为这也是一个用户-定义的转换...(隐式不能超过 1 个)
    【解决方案2】:

    那么你应该像这样在 namespace cv 中定义一个函数:

    namespace cv{
    float norm(const Foo& foo){
        return cv::norm(FooProxy(foo));
    }
    }
    

    现在你可以打电话了:

    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
    

    【讨论】:

    • 这是一个有趣的解决方案。我希望让它进行转换,因为有数百个 OpenCV 函数需要这样的对话。
    猜你喜欢
    • 2020-12-02
    • 2020-12-14
    • 1970-01-01
    • 2012-03-28
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    相关资源
    最近更新 更多