0

This time I got the following problem. I want to speed up skin/background segmentation by starting each as separate thread.

Both of the procedures, do not write to the same variables, do not read from the same variables. The only thing that is important is to synchronize main program thread to wait till both of the procedures (skin and background) finish their job, and then to start working with results.

What I did Is :

In my main class header:

HANDLE fgbg_codebookThread;
HANDLE skinsegThread;

Then in my main loop function:

fgbg_codebookThread =( HANDLE ) _beginthread( fgbg_codebookThreadProc, 0, (void *)this );
skinsegThread =( HANDLE ) _beginthread( skinsegThreadProc, 0, (void *)this );

std::vector < HANDLE > threads;
threads.push_back(fgbg_codebookThread);
threads.push_back(skinsegThread);

if( threads.size() > 0 )
    WaitForMultipleObjects( threads.size(), & threads[ 0 ], TRUE, INFINITE );
cv::bitwise_and(fgbg_codebookResult,skinsegResult,mask);

where my procedure functions look like:

static void __cdecl fgbg_codebookThreadProc( void * Args )
{
    mainApp* app = static_cast<mainApp*>(Args);

    app->fgbg_codebookProc();
    _endthread();
};

static void __cdecl skinsegThreadProc( void * Args )
{
    mainApp* app = static_cast<mainApp*>(Args);

    app->skinsegProc();
    _endthread();
};

which in my opinion should work just fine as long as both procedures does not share variables in any way.

BUT: following code in most cases leads me to the breakpoint (after some random amount of time running), that points to either malloc.c __forceinline void * __cdecl _heap_alloc (size_t size) function or free.c void __cdecl _free_base (void * pBlock) function.

Im beginner when it comes to threading in C++ I never used that before so I have no idea what is happening.

And here are bodys of my threads procedures (to be sure):

void fgbg_codebookProc()
{       
fgbg_codebook.process(fgbg_codebookFrame, &fgbg_codebookResult,frameNumber);        
}

void skinsegProc()
{                 skinseg.process(skinsegFrame,&skinsegResult,skinseg.lambda,skinseg.vThreshold);   
}




  void FGBG_CODEBOOK::process(cv::Mat input,cv::Mat *output, int nframes)
{
    IplImage* rawImage=cvCloneImage(&(IplImage)input);

    yuvImage = cvCloneImage(rawImage);
    ImaskCodeBook = cvCreateImage( cvGetSize(rawImage), IPL_DEPTH_8U, 1 );
    cvSet(ImaskCodeBook,cvScalar(255));
    cvCvtColor(yuvImage, yuvImage, CV_RGB2YCrCb );//YUV For codebook method

    model->modMin[0] = YUVmin[0];
    model->modMin[1] = YUVmin[1];
    model->modMin[2] = YUVmin[2];
    model->modMax[0] = YUVmax[0];
    model->modMax[1] = YUVmax[0];
    model->modMax[2] = YUVmax[0];

    //Basic learning of backgroundraw->width/2-100/2, raw->height/1.5-100/2),cvPoint(raw->width/2+100,raw->height/1.5+100)
    if( nframes-1 < nframesToLearnBG  )
        cvBGCodeBookUpdate( model, yuvImage);

    //Clean when learned
    if( nframes-1 == nframesToLearnBG  )
    {
        cvBGCodeBookClearStale( model, model->t/2 );
        calibration = false;
    }
    //Start finding foreground after learning
    if( nframes-1 >= nframesToLearnBG  )
    {
        // Find foreground by codebook method
        cvBGCodeBookDiff( model, yuvImage, ImaskCodeBook );

        // Update periodically
        /*if ((nframes-1) % 150 == 0)
        {
            cvBGCodeBookUpdate(model,yuvImage);
            //std::cout <<"update\n";
        }
        if ((nframes-1) % 300 == 0)
        {
            cvBGCodeBookClearStale(model,model->t/2);
            //std::cout <<"clear\n";
        }*/
    }

    cv::Mat(ImaskCodeBook).copyTo(*output);
    cvReleaseImage(&rawImage);
    cvReleaseImage(&yuvImage);
    cvReleaseImage(&ImaskCodeBook);
}


    void SKINSEG::process(cv::Mat src, cv::Mat *dst, double lambda, unsigned int vThreshold)
{

    skinsegResult = cv::Mat(480,640, CV_8UC1, cvScalar(0.));
    cv::cvtColor(src,frameHSV,CV_RGB2HSV);


    CvMat* Cs;
    CvMat* CsInv;
    CvMat* ms;


    Cs = cvCreateMat(2, 2, CV_32FC1);
    cvInitMatHeader(Cs, 2, 2, CV_32FC1, covMatrix);
    CsInv = cvCreateMat(2, 2, CV_32FC1);
    cvInvert(Cs, CsInv);
    ms = cvCreateMat(1, 2, CV_32FC1);
    cvInitMatHeader(ms, 1, 2, CV_32FC1, valAvg);

    CvMat* X = cvCreateMat(1, 2, CV_32FC1);
    CvMat* Xms = cvCreateMat(1, 2, CV_32FC1);
    CvMat* XmsT = cvCreateMat(2, 1, CV_32FC1);
    CvMat* XmsCsInv = cvCreateMat(1, 2, CV_32FC1);
    CvMat* XmsCsInvXmsT = cvCreateMat(1, 1, CV_32FC1);

    uchar* data = (uchar *)frameHSV.data; 
    uchar* dataMask = (uchar *)skinsegResult.data; 

    double temp[2];
    for (int j = 0; j < frameHSV.cols; j++) 
        for (int i = 0; i < frameHSV.rows; i++)
        {
            cvmSet( Xms,0,0,(double)data[i*frameHSV.step+j*frameHSV.channels()+0]- cvmGet(ms,0,0) );
            cvmSet( Xms,0,1,(double)data[i*frameHSV.step+j*frameHSV.channels()+1] - cvmGet(ms,0,1) );

            temp[0] = cvmGet(Xms,0,0);
            temp[1] = cvmGet(Xms,0,1);

            cvmSet(XmsT,0,0,cvmGet(Xms,0,0));
            cvmSet(XmsT,1,0,cvmGet(Xms,0,1));

            cvmSet(XmsCsInv,0,0,(cvmGet(Xms,0,0) * cvmGet(CsInv,0,0)) + (cvmGet(Xms,0,1) * cvmGet(CsInv,1,0)));
            cvmSet(XmsCsInv,0,1,(cvmGet(Xms,0,0) * cvmGet(CsInv,0,1)) + (cvmGet(Xms,0,1) * cvmGet(CsInv,1,1)));

            cvmSet(XmsCsInvXmsT,0,0,(cvmGet(XmsCsInv,0,0) * cvmGet(XmsT,0,0)) + (cvmGet(XmsCsInv,0,1) * cvmGet(XmsT,1,0)));


            double lam = cvmGet(XmsCsInvXmsT, 0, 0);
            dataMask[i*skinsegResult.step+j*skinsegResult.channels()] = (((double)data[i*frameHSV.step+j*frameHSV.channels()] >= vThreshold) && (lam < lambda)) ? 255 : 0;

    }
    skinsegResult.copyTo(*dst);

    // zwalniamy macierze
    cvReleaseMat(&XmsCsInvXmsT);
    cvReleaseMat(&XmsCsInv);
    cvReleaseMat(&XmsT);
    cvReleaseMat(&Xms);
    cvReleaseMat(&X);
    cvReleaseMat(&ms);
    cvReleaseMat(&CsInv);
    cvReleaseMat(&Cs);
}

What am I doing wrong?

patrykos91
  • 3,038
  • 2
  • 18
  • 26

1 Answers1

1

Try to use createthread or beginthreadex instead of beginthread. Look here:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/c727ae29-5a7a-42b6-ad0b-f6b21c1180b2/createthread-vs-beginthreadex?forum=vclanguage

or here:

Windows threading: _beginthread vs _beginthreadex vs CreateThread C++

One other thing that I have seen in your code. You use cvInitMatHeader with a non empty object. This looks for me wrong. It looks like your memory managment of your

void SKINSEG::process(cv::Mat src, cv::Mat *dst, double lambda, unsigned int vThreshold) 

function is wrong. Look at you task manager and you will see that the call of your program will just fill all of your memory.

Community
  • 1
  • 1
jamk
  • 780
  • 1
  • 8
  • 23