Я работаю над визуальным обнаружением объектов и использую каскадный классификатор от Opencv. Работает хорошо, но для меня слишком медленно. Я использовал Vtune, чтобы получить все точки доступа, и я обнаружил, что при 140-секундном выполнении (время процессора, реальное время было около 60-ти) служебное время составляет 123-е секунды. cvCascadeClassifier использует 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 (т. е. сократить время накладных расходов)?
РЕДАКТИРОВАТЬ: В моем случае я обнаружил ошибку во время связывания. Создание локальных векторов и слияние в конце с помощью мьютекса работает хорошо. Теперь у меня есть 0,1 с накладных расходов на 140 с процессорного времени. Это частный случай с несколькими элементами, которые очень малы. Ответ Антона кажется более общим