传递函数作为参数

时间:2013-03-14 18:36:15

标签: c++ qt opencv

我正在尝试将函数作为参数传递给另一个函数。 以下代码在没有使用类的情况下有效,但是当我用qt类尝试它时,会发生以下错误...

error: argument of type 'void (MainWindow::)(int, int, int, int, void*)'
does not  match 'void (*)(int, int, int, int, void*)'

我的代码是

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv/cv.h>
#include <opencv/cvaux.h>
#include <opencv/highgui.h>

// for filelisting
#include <stdio.h>
#include <sys/file.h>
#include<io.h>
// for fileoutput
#include <string>
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <sys/types.h>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    roi_x0=0;
     roi_y0=0;
     roi_x1=0;
     roi_y1=0;
     numOfRec=0;
     startDraw = 0;
     window_name="<SPACE>add <B>save and load next <ESC>exit";
}

MainWindow::~MainWindow()
{
    delete ui;
}
string MainWindow::IntToString(int num)
{
    ostringstream myStream; //creates an ostringstream object
    myStream << num << flush;
    /*
    * outputs the number into the string stream and then flushes
    * the buffer (makes sure the output is put into the stream)
    */
    return(myStream.str()); //returns the string form of the stringstream object
}

void MainWindow::on_mouse(int event, int x, int y, int flag, void *param)
{
    if(event==CV_EVENT_LBUTTONDOWN)
    {
        if(!startDraw)
        {
            roi_x0=x;
            roi_y0=y;
            startDraw = 1;
        } else {
            roi_x1=x;
            roi_y1=y;
            startDraw = 0;
        }
    }
    if(event==CV_EVENT_MOUSEMOVE && startDraw)
    {

        //redraw ROI selection
        image2=cvCloneImage(image);
        cvRectangle(image2,cvPoint(roi_x0,roi_y0),cvPoint(x,y),CV_RGB(255,0,255),1);
        cvShowImage(window_name,image2);
        cvReleaseImage(&image2);
    }
}

void MainWindow::on_actionMark_Faces_triggered()
{
    char iKey=0;
    string strPrefix;
    string strPostfix;
    string input_directory;
    string output_file;



    input_directory ="E:/My/";
    output_file ="pos.txt";

    /* Get a file listing of all files with in the input directory */
    DIR    *dir_p = opendir (input_directory.c_str());
    struct dirent *dir_entry_p;

    if(dir_p == NULL) {
        fprintf(stderr, "Failed to open directory %s\n", input_directory.c_str());

    }

    fprintf(stderr, "Object Marker: Input Directory: %s  Output File: %s\n", input_directory.c_str(), output_file.c_str());

    //    init highgui
    cvAddSearchPath(input_directory);
    cvNamedWindow(window_name,1);
    cvSetMouseCallback(window_name,on_mouse,NULL);

    fprintf(stderr, "Opening directory...");
    //    init output of rectangles to the info file
    ofstream output(output_file.c_str());
    fprintf(stderr, "done.\n");

    while((dir_entry_p = readdir(dir_p)) != NULL)
    {
        numOfRec=0;

        if(strcmp(dir_entry_p->d_name, ""))
        fprintf(stderr, "Examining file %s\n", dir_entry_p->d_name);

        /* TODO: Assign postfix/prefix info */
        strPostfix="";
        //strPrefix=input_directory;
        strPrefix=input_directory+dir_entry_p->d_name;
        //strPrefix+=bmp_file.name;
        fprintf(stderr, "Loading image %s\n", strPrefix.c_str());

        if((image=cvLoadImage(strPrefix.c_str(),1)) != 0)
        {

            //    work on current image
            do

    {
                cvShowImage(window_name,image);

                // used cvWaitKey returns:
                //    <B>=66        save added rectangles and show next image
                //    <ESC>=27        exit program
                //    <Space>=32        add rectangle to current image
                //  any other key clears rectangle drawing only
                iKey=cvWaitKey(0);
                switch(iKey)
                {

                case 27:

                        cvReleaseImage(&image);
                        cvDestroyWindow(window_name);
                        return;
                case 32:

                        numOfRec++;
                printf("   %d. rect x=%d\ty=%d\tx2h=%d\ty2=%d\n",numOfRec,roi_x0,roi_y0,roi_x1,roi_y1);
                //printf("   %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
                        // currently two draw directions possible:
                        //        from top left to bottom right or vice versa
                        if(roi_x0<roi_x1 && roi_y0<roi_y1)
                        {

                            printf("   %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x0,roi_y0,roi_x1-roi_x0,roi_y1-roi_y0);
                            // append rectangle coord to previous line content
                            strPostfix+=" "+IntToString(roi_x0)+" "+IntToString(roi_y0)+" "+IntToString(roi_x1-roi_x0)+" "+IntToString(roi_y1-roi_y0);

                        }
                        else
                                                    //(roi_x0>roi_x1 && roi_y0>roi_y1)
                        {
                            printf(" hello line no 154\n");
                            printf("   %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
                            // append rectangle coord to previous line content
                            strPostfix+=" "+IntToString(roi_x1)+" "+IntToString(roi_y1)+" "+IntToString(roi_x0-roi_x1)+" "+IntToString      (roi_y0-roi_y1);
        }

                        break;
                }
            }
            while(iKey!='b');

            {
            // save to info file as later used for HaarTraining:
            //    <rel_path>\bmp_file.name numOfRec x0 y0 width0 height0 x1 y1 width1 height1...
            if(numOfRec>0&&iKey=='b')
            {
                //append line
                /* TODO: Store output information. */
                output << strPrefix << " "<< numOfRec << strPostfix <<"\n";

            cvReleaseImage(&image);
            }

         else
        {
            fprintf(stderr, "Failed to load image, %s\n", strPrefix.c_str());
        }
    }

    }}

    output.close();
    cvDestroyWindow(window_name);
    closedir(dir_p);
}

错误发生在

 cvSetMouseCallback(window_name,on_mouse,NULL);

3 个答案:

答案 0 :(得分:1)

成员函数与常规函数不同(因为它们必须传入一个额外隐藏的'this'参数)。

这就是为什么它说:

void (MainWindow::)(int, int, int, int, void*)

不匹配:

void ()(int, int, int, int, void*)

MainWindow :: 部分非常重要。

如果您使用的是C ++ 11,则可以使用std :: function和std :: bind,它可以工作(参见this question)。静态成员函数也可以工作,因为静态成员函数也没有 this 指针,并且表现得像常规函数(但在命名空间中,并且具有私有成员访问权限)。

答案 1 :(得分:0)

回调方法必须是staticpublic(或非成员函数)。正如您所知,如果它是非成员函数,它会起作用,但如果它是非静态方法则会出错。您应该将MainWindow::on_mouse定义为:

static void MainWindow::on_mouse(int event, int x, int y, int flag, void *param)

答案 2 :(得分:0)

这不是一个罕见的问题。解决方案是使用包装函数:

static void MainWindow::on_mouse_wrapper(int event, int x, int y, int flag, void *param)
{
   MainWindow* self = reinterpret_cast<MainWindow*>(param);
   self->on_mouse(event, x, y, flag, NULL);
}

然后编辑

cvSetMouseCallback(window_name,on_mouse,NULL);

为:

cvSetMouseCallback(window_name,on_mouse,这一点);