2016-10-17 3 views
1

Я работаю над визуальным обнаружением объектов, и я использую каскадный классификатор из Opencv. Он работает хорошо, но для меня это слишком медленно. Я использовал Vtune, чтобы получить все горячие точки, и я нахожу, что на 140-м этапе исполнения (время процессора, реальное было около 60 секунд), есть 123s накладных расходов. cvCascadeClassifier использует TBB быстрее, но кажется, что все потоки TBB ждут больше, чем нужно. Существует код:Как эффективно объединить результаты из потоков TBB

void operator()(const Range& range) const 
{ 
    Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone(); 

    Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor)); 

    int y1 = range.start * stripSize; 
    int y2 = min(range.end * stripSize, processingRectSize.height); 
    for(int y = y1; y < y2; y += yStep) 
    { 
     for(int x = 0; x < processingRectSize.width; x += yStep) 
     { 
      if ((!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) { 
       continue; 
      } 

      double gypWeight; 
      int result = classifier->runAt(evaluator, Point(x, y), gypWeight); 

      #if defined (LOG_CASCADE_STATISTIC) 
      logger.setPoint(Point(x, y), result); 
      #endif 
      if(rejectLevels) 
      { 
       if(result == 1) 
        result = -(int)classifier->data.stages.size(); 
       if(classifier->data.stages.size() + result < 4) 
       { 
        mtx->lock(); 
        rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height)); 
        rejectLevels->push_back(-result); 
        levelWeights->push_back(gypWeight); 
        mtx->unlock(); 
       } 
      } 
      else if(result > 0) 
      { 
       mtx->lock(); 
       rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), 
              winSize.width, winSize.height)); 
       mtx->unlock(); 
      } 
      if(result == 0) 
       x += yStep; 
     } 
    } 
} 

Я думаю, что проблема исходить от слияния результатов. Слишком много блокировки мьютексов, и потоки должны слишком часто ждать. Эта часть кода называется большим количеством времени, и очень мало потоков (3 в моем случае). Я попытался создать локальные векторы (я не пробовал со списком, потому что тип Rect очень маленький) для каждого потока и слияние всех этих векторов в конце. Это решение сокращает накладные расходы (менее 10 с на 140 с процессорного времени), но я хотел бы больше.

Это мой вопрос: Есть ли способ эффективно слить результаты из различных потоков TBB (ака сократить время накладных расходов)?

EDIT: В моем случае я обнаружил ошибку во время ссылки. Создание локальных векторов и слияние в конце с мьютекс хорошо работает. Теперь у меня есть 0.1s накладных расходов на 140s процессорного времени. Это частный случай с небольшим количеством элементов. Антон ответ, кажется, более общий

ответ

3

Существует еще один и, возможно, более эффективный способ объединения результатов. Используйте классы combinable или "ets" для сбора .local() результатов для каждой темы/задачи (не используйте прямые потоки), а затем объедините результаты, используя .combine()

2

Вы можете попробовать использовать TBB concurrent_vector. Интерфейс A grow_by может помочь вам уменьшить накладные расходы при вставке: вы можете создать небольшой массив (например, 16 элементов) в стеке и объединить все элементы из него в concurrent_vector.

Также вы можете заменить push_back на emplace_back с C++ 11, работающим с параллельным_vector.

Смежные вопросы