Вычисление термина данных в Graph Cuts - это вычисление t -линков.Это показано в исходном коде в строке 465 источника grabcut.cpp
- в частности, в функции constructGCGraph
: https://github.com/opencv/opencv/blob/master/modules/imgproc/src/grabcut.cpp#L465. Обратите внимание, что объявление функции static void
, что означает, что она является закрытой, а невидимый вне рабочей области cv
.Это означает, что вы не сможете вызвать его в исходном коде, если не взломаете сам исходный код.
Другими словами:
// set t-weights
double fromSource, toSink;
if( mask.at<uchar>(p) == GC_PR_BGD || mask.at<uchar>(p) == GC_PR_FGD )
{
fromSource = -log( bgdGMM(color) );
toSink = -log( fgdGMM(color) );
}
else if( mask.at<uchar>(p) == GC_BGD )
{
fromSource = 0;
toSink = lambda;
}
else // GC_FGD
{
fromSource = lambda;
toSink = 0;
}
graph.addTermWeights( vtxIdx, fromSource, toSink );
Терминология «источник» и «сток»происходят из алгоритма Graph Cuts, где «источник» означает пиксель переднего плана, а «приемник» означает пиксель фона.Также обратите внимание, что существует четыре типа этикеток.Они определены в enum
под названием cv::GrabCutClasses
(вы можете найти их здесь: https://docs.opencv.org/3.0.0/d7/d1b/group__imgproc__misc.html#gad43d3e4208d3cf025d8304156b02ba38).
В частности:
GC_BGD
: очевидный фоновый пиксель GC_FGD
: очевидный пиксель переднего плана (объекта) GC_PR_BGD
: возможный пиксель фона GC_PR_FGD
: возможный пиксель переднего плана
GC_BGD
и GC_FGD
- это пиксели, которые обозначают передний план и фоновые обводки, используемые для разграничения изображения. Это то, что вы указываете. Для GC_PR_BGD
и GC_PR_FGD
мы, таким образом, полагаемся на построение GMM для переднего плана и фона.и вычислим отрицательные логарифмические вероятности. Суть этого в том, что если цвет определенно принадлежит переднему плану, мы назначаем дешевую привязку его к узлу приемника, чтобы было более привлекательным вырезать эту ссылку, чтобы оставить исходный узел нетронутым,таким образом, классифицируя его как пиксель переднего плана. Вы можете аналогичным образом сделать это для исходного узла и фона. Для тех пикселей, где мы точно знаем, являются ли они передним планом или фоновым.d, мы применяем высокую стоимость lambda
к ссылке, представляющей желаемую метку, чтобы противоположная ссылка была обрезана, тем самым сохраняя желаемую метку для пикселя.Например, если мы знаем, что пиксель является фоновым, мы гарантируем, что стоимость ссылки t на исходный узел равна нулю, чтобы мы могли обрезать эту ссылку без каких-либо последствий, гарантируя, что пиксель назначен наbackground.
Чтобы «обновить» термины данных, это делается путем указания большего количества передних и фоновых штрихов на изображении, чтобы дать лучшее описание объекта, который вы пытаетесь сегментировать.Нет другого способа сделать это без взлома исходного кода самостоятельно.
В качестве заключительного замечания я бы рекомендовал прочитать это резюме о том, как работает алгоритм Graph Cuts: Сегментация изображения с maxflow .Это дает больше перспективы того, что делает исходный код для GrabCut.В конце концов, GrabCut - это просто абстракция Graph Cuts более высокого уровня.