void MLBSTrackingFilter< NumImageFeatures >::ThreadedGenerateData(const InputImageRegionType &regionForThread, ThreadIdType threadId)
{
    m_Mutex.Lock();
    m_Threads++;
    m_Mutex.Unlock();
    typedef ImageRegionConstIterator< ItkUcharImgType >     MaskIteratorType;
    MaskIteratorType    sit(m_SeedImage, regionForThread );
    MaskIteratorType    mit(m_MaskImage, regionForThread );

    sit.GoToBegin();
    mit.GoToBegin();
    itk::Point<double> worldPos;
    while( !sit.IsAtEnd() )
    {
        if (sit.Value()==0 || mit.Value()==0)
        {
            ++sit;
            ++mit;
            continue;
        }

        for (int s=0; s<m_SeedsPerVoxel; s++)
        {
            FiberType fib;
            double tractLength = 0;
            typename FeatureImageType::IndexType index = sit.GetIndex();
            itk::ContinuousIndex<double, 3> start;
            unsigned int counter = 0;

            if (m_SeedsPerVoxel>1)
            {
                start[0] = index[0]+GetRandDouble(-0.5, 0.5);
                start[1] = index[1]+GetRandDouble(-0.5, 0.5);
                start[2] = index[2]+GetRandDouble(-0.5, 0.5);
            }
            else
            {
                start[0] = index[0];
                start[1] = index[1];
                start[2] = index[2];
            }

            // get staring position
            m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos );

            // get starting direction
            int candidates = 0;
            double prob = 0;
            vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0);
            vnl_vector_fixed<double,3> dir = Classify(worldPos, candidates, dirOld, 0, prob);
            if (dir.magnitude()<0.0001)
                continue;

            // forward tracking
            tractLength = FollowStreamline(threadId, worldPos, dir, &fib, 0, false);
            fib.push_front(worldPos);

            if (m_RemoveWmEndFibers)
            {
                itk::Point<double> check = fib.back();
                dirOld.fill(0.0);
                vnl_vector_fixed<double,3> check2 = GetNewDirection(check, dirOld);
                if (check2.magnitude()>0.001)
                {
                    MITK_INFO << "Detected WM ending. Discarding fiber.";
                    continue;
                }
            }

            // backward tracking
            tractLength = FollowStreamline(threadId, worldPos, -dir, &fib, tractLength, true);
            counter = fib.size();

            if (m_RemoveWmEndFibers)
            {
                itk::Point<double> check = fib.front();
                dirOld.fill(0.0);
                vnl_vector_fixed<double,3> check2 = GetNewDirection(check, dirOld);
                if (check2.magnitude()>0.001)
                {
                    MITK_INFO << "Detected WM ending. Discarding fiber.";
                    continue;
                }
            }

            if (tractLength<m_MinTractLength || counter<2)
                continue;

            m_Mutex.Lock();
            m_Tractogram.push_back(fib);
            m_Mutex.Unlock();

            if (m_AbortTracking)
                break;
        }
        if (m_AbortTracking)
            break;
        ++sit;
        ++mit;
    }
    m_Threads--;
    std::cout << "Thread " << threadId << " finished tracking" << std::endl;
}
vnl_vector_fixed<double,3> MLBSTrackingFilter<  ShOrder, NumImageFeatures >::GetNewDirection(itk::Point<double, 3> &pos, vnl_vector_fixed<double, 3>& olddir)
{
    if (m_DemoMode)
    {
        m_SamplingPointset->Clear();
        m_AlternativePointset->Clear();
    }
    vnl_vector_fixed<double,3> direction; direction.fill(0);

    ItkUcharImgType::IndexType idx;
    m_StoppingRegions->TransformPhysicalPointToIndex(pos, idx);
    if (m_StoppingRegions->GetLargestPossibleRegion().IsInside(idx) && m_StoppingRegions->GetPixel(idx)>0)
        return direction;

    if (m_MaskImage.IsNotNull() && ((m_MaskImage->GetLargestPossibleRegion().IsInside(idx) && m_MaskImage->GetPixel(idx)<=0) || !m_MaskImage->GetLargestPossibleRegion().IsInside(idx)) )
        return direction;

    if (olddir.magnitude()>0)
        olddir.normalize();

    int candidates = 0; // number of directions with probability > 0
    double w = 0;       // weight of the direction predicted at each sampling point
    if (IsValidPosition(pos))
    {
        direction = m_ForestHandler.Classify(pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage); // get direction proposal at current streamline position
        direction *= w;  // HERE WE ARE WEIGHTING AGAIN EVEN THOUGH THE OUTPUT DIRECTIONS ARE ALREADY WEIGHTED!!! THE EFFECT OF THIS HAS YET TO BE EVALUATED.
    }

    itk::OrientationDistributionFunction< double, 50 >  probeVecs;
    itk::Point<double, 3> sample_pos;
    int alternatives = 1;
    for (int i=0; i<m_NumberOfSamples; i++)
    {
        vnl_vector_fixed<double,3> d;

        if (m_RandomSampling)
        {
            d[0] = GetRandDouble();
            d[1] = GetRandDouble();
            d[2] = GetRandDouble();
            d.normalize();
            d *= GetRandDouble(0,m_SamplingDistance);
        }
        else
        {
            d = probeVecs.GetDirection(i)*m_SamplingDistance;
        }

        sample_pos[0] = pos[0] + d[0];
        sample_pos[1] = pos[1] + d[1];
        sample_pos[2] = pos[2] + d[2];
        if(m_DemoMode)
            m_SamplingPointset->InsertPoint(i, sample_pos);

        candidates = 0;
        vnl_vector_fixed<double,3> tempDir; tempDir.fill(0.0);
        if (IsValidPosition(sample_pos))
            tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage); // sample neighborhood
        if (candidates>0 && tempDir.magnitude()>0.001)
        {
            direction += tempDir*w;
        }
        else if (m_AvoidStop && candidates==0 && olddir.magnitude()>0) // out of white matter
        {
            double dot = dot_product(d, olddir);
            if (dot >= 0.0) // in front of plane defined by pos and olddir
                d = -d + 2*dot*olddir; // reflect
            else
                d = -d; // invert

            // look a bit further into the other direction
            sample_pos[0] = pos[0] + d[0];
            sample_pos[1] = pos[1] + d[1];
            sample_pos[2] = pos[2] + d[2];
            if(m_DemoMode)
                m_AlternativePointset->InsertPoint(alternatives, sample_pos);
            alternatives++;
            candidates = 0;
            vnl_vector_fixed<double,3> tempDir; tempDir.fill(0.0);
            if (IsValidPosition(sample_pos))
                tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage); // sample neighborhood

            if (candidates>0 && tempDir.magnitude()>0.001)  // are we back in the white matter?
            {
                direction += d;         // go into the direction of the white matter
                direction += tempDir*w;  // go into the direction of the white matter direction at this location
            }
        }
    }

    if (direction.magnitude()>0.001)
    {
        direction.normalize();
        olddir[0] = direction[0];
        olddir[1] = direction[1];
        olddir[2] = direction[2];
    }
    else
        direction.fill(0);

    return direction;
}