Mr.Hazyzhao
2021-09-08 09:32
采纳率: 100%
浏览 37

类的静态回调函数如何访问类的非静态成员,基于openCV的canny算法

感想上一篇答主baidu_30233079解答的:如何给回调函数传数据
如何给一个回调函数传数据?-编程语言-CSDN问答 CSDN问答为您找到如何给一个回调函数传数据?相关问题答案,如果想了解更多关于如何给一个回调函数传数据? c++、opencv 技术问题等相关问答,请访问CSDN问答。 https://ask.csdn.net/questions/7504028

问题大概是,在OpenCV的Canny边缘检测算法中,我想自己编写一个类去实现这个事情,做到如下这样

Mat img = imread(filename); // 读取图片
MyCanny myCanny(img);
myCanny.canny_process;

三行结束对一个图片的边缘检测,这样很方便以后用对吧
于是我写了个类

class MyCanny{
private:
    Mat src, src_gray;
    Mat dst, detected_edges; // input and output matrix
//    int lowThreshold = 0;
    const int max_lowThreshold = 100;
    const int ratio = 3;
    const int kernel_size = 3;
    const char* window_name = "Edge Map"; // some parameters
    MyCanny * canny_pointer = this;

public:
//    int lowThreshold = 0;

    explicit MyCanny(const Mat &img); // 构造函数,用于对类的对象赋值,由于数据是private的,只能通过此种方式赋值

    Mat get_dst(); // 可以不需要通过static静态就获得dst矩阵
    Mat get_src();
    void canny_process(); // 用于进行主要的CannyEdge处理过程
    static void canny_threshold(int pos, void* userdata);
};

以及类里面的函数,注意,canny_threshold作为回调函数,是静态,由static修饰的

void MyCanny::canny_process() {
    cout << "canny_process is called..." << endl;
    if (src.empty()){
        cout << "Failed to load src..." << endl;
        exit(100);
    }
    dst.create(src.size(), src.type());
    cvtColor(src, src_gray, COLOR_BGR2GRAY);

    namedWindow(window_name, WINDOW_AUTOSIZE); // 这一段代码必须有,是createTrackbar必须的
    createTrackbar("Min Threshold:",
                   window_name,
                   &lowThreshold,
                   max_lowThreshold,
                   canny_threshold);

    canny_threshold(0, this); // callback function 回调函数
    // FIXME: 回调时,lowThreshold这个参数怎么传给Canny_threshold? 通过`pos`
    waitKey(0);
}

void MyCanny::canny_threshold(int pos, void *userdata) {
    // 可以把自己数据封装到结构体、或者类,用usrdata传进来。另外一个参数`pos`是当前trackbar的数值
    // 实例化一个对象,然后通过对象访问非静态成员数据
    auto * myCanny = (MyCanny *) userdata;

    // 这几行代码测试是否被回调了
    cout << "canny_threshold is called..." << endl;
    cout << canny->ratio << endl;
    cout << "pos=" << pos << endl;
    cout << "lowThreshold=" <<lowThreshold << endl;
    cout << "max_lowThreshold=" << myCanny->max_lowThreshold << endl;
    // FIXME: 第二次调用时指针出问题

    // 获取类的数据
    Mat src = myCanny->src;
    Mat dst = myCanny->dst;
    Mat src_gray = myCanny->src_gray;
    Mat detected_edges = myCanny->detected_edges;
//    int lowThreshold = myCanny->lowThreshold;
    int ratio = myCanny->ratio;
    int kernel_size = myCanny->kernel_size;

    // 更新lowThreshold
    lowThreshold = pos;

    // 此时这些参数都是用实例化的对象,通过类传过来的
    blur(myCanny->src_gray, myCanny->detected_edges, Size(3, 3));
    cout << "blur finished..." << endl;
    Canny(myCanny->detected_edges,
          myCanny->detected_edges,
          lowThreshold,
          lowThreshold * ratio,
          kernel_size);
    cout << "canny finished..." << endl;
    myCanny->dst = Scalar::all(0);
    src.copyTo(myCanny->dst, myCanny->detected_edges);
    imshow(myCanny->window_name, myCanny->dst);

    myCanny = nullptr;
    userdata = nullptr;
    // 重置指针,重置不了啊
}

我的主函数

void function2_1(){
    // 实现Canny边缘检测,用类的方法
    cout << "Canny Edge Detector" << endl;
    Mat img = imread("../../images/learn_slam.jpg");
    MyCanny mCanny(img);
    mCanny.canny_process();
}

img

可以看到,在回调函数 canny_threshold里面,写了几个cout用来测试是不是回调了,发现第一个参数pos的传输始终是正常的,但是第二个参数userdata在第一次进行回调的时候,似乎由于实例化类指针的问题,不能再次访问类的数据
我觉得可能是实例化类指针的问题?

  • 收藏

2条回答 默认 最新

相关推荐 更多相似问题