Надежная сегментация изображений в OpenCV

Я пытаюсь написать программу OpenCV, которая подсчитывает количество рыбных яиц для кого-то другого. В настоящее время он берет загруженное изображение, нормализует, размывает, пороговые значения, расширяет, трансформирует расстояние, снова пороговые значения, а затем находит контуры (как в типичном уроке по водоразделу).

У меня проблема в том, что условия освещения могут немного отличаться, поэтому даже при моих адаптивных пороговых значениях точность алгоритма также сильно варьируется. Если на изображении есть градиент яркости, то это выглядит особенно плохо. Иногда объекты очень яркие на фоне, а иногда они почти одинаковой яркости. Существуют ли какие-либо особенно эффективные способы поиска объектов в различных условиях освещения?

Образцы изображений:
IMG
GIF

2

Решение

Поскольку все, что больше 100 пикселей, не относится к вашему изображению, я бы создал полосовой фильтр Фурье для удаления этих структур.

Вот реализация, которую я использую, основанная на той, что в ImageJ. В этой реализации входное изображение дополняется зеркалом для уменьшения краевых артефактов.

static void GenerateBandFilter(thrust::host_vector<float>& filter, const BandPassSettings& band, const FrameSize& frame)
{
//From https://imagej.nih.gov/ij/plugins/fft-filter.html
if (band.do_band_pass == false)
{
return;
}
if (frame.width != frame.height)
{
throw std::runtime_error("Frame height and width should be the same");
}
auto maxN = static_cast<int>(std::max(frame.width, frame.height));//todo make sure they are the same

auto filterLargeC = 2.0f*band.max_dx / maxN;
auto filterSmallC = 2.0f*band.min_dx / maxN;
auto scaleLargeC = filterLargeC*filterLargeC;
auto scaleSmallC = filterSmallC*filterSmallC;

auto filterLargeR = 2.0f*band.max_dy / maxN;
auto filterSmallR = 2.0f*band.min_dy / maxN;
auto scaleLargeR = filterLargeR*filterLargeR;
auto scaleSmallR = filterSmallR*filterSmallR;

// loop over rows
for (auto j = 1; j < maxN / 2; j++)
{
auto row = j * maxN;
auto backrow = (maxN - j)*maxN;
auto rowFactLarge = exp(-(j*j) * scaleLargeR);
auto rowFactSmall = exp(-(j*j) * scaleSmallR);
// loop over columns
for (auto col = 1; col < maxN / 2; col++)
{
auto backcol = maxN - col;
auto colFactLarge = exp(-(col*col) * scaleLargeC);
auto colFactSmall = exp(-(col*col) * scaleSmallC);
auto factor = (((1 - rowFactLarge*colFactLarge) * rowFactSmall*colFactSmall));
filter[col + row] *= factor;
filter[col + backrow] *= factor;
filter[backcol + row] *= factor;
filter[backcol + backrow] *= factor;
}
}
auto fixy = [&](float t){return isinf(t) ? 0 : t; };
auto rowmid = maxN * (maxN / 2);
auto rowFactLarge = fixy(exp(-(maxN / 2)*(maxN / 2) * scaleLargeR));
auto rowFactSmall = fixy(exp(-(maxN / 2)*(maxN / 2) *scaleSmallR));
filter[maxN / 2] *= ((1 - rowFactLarge) * rowFactSmall);
filter[rowmid] *= ((1 - rowFactLarge) * rowFactSmall);
filter[maxN / 2 + rowmid] *= ((1 - rowFactLarge*rowFactLarge) * rowFactSmall*rowFactSmall); //
rowFactLarge = fixy(exp(-(maxN / 2)*(maxN / 2) *scaleLargeR));
rowFactSmall = fixy(exp(-(maxN / 2)*(maxN / 2) *scaleSmallR));
for (auto col = 1; col < maxN / 2; col++){
auto backcol = maxN - col;
auto colFactLarge = exp(-(col*col) * scaleLargeC);
auto colFactSmall = exp(-(col*col) * scaleSmallC);
filter[col] *= ((1 - colFactLarge) * colFactSmall);
filter[backcol] *= ((1 - colFactLarge) * colFactSmall);
filter[col + rowmid] *= ((1 - colFactLarge*rowFactLarge) * colFactSmall*rowFactSmall);
filter[backcol + rowmid] *= ((1 - colFactLarge*rowFactLarge) * colFactSmall*rowFactSmall);
}
// loop along column 0 and expanded_width/2
auto colFactLarge = fixy(exp(-(maxN / 2)*(maxN / 2) * scaleLargeC));
auto colFactSmall = fixy(exp(-(maxN / 2)*(maxN / 2) * scaleSmallC));
for (auto j = 1; j < maxN / 2; j++) {
auto row = j * maxN;
auto backrow = (maxN - j)*maxN;
rowFactLarge = exp(-(j*j) * scaleLargeC);
rowFactSmall = exp(-(j*j) * scaleSmallC);
filter[row] *= ((1 - rowFactLarge) * rowFactSmall);
filter[backrow] *= ((1 - rowFactLarge) * rowFactSmall);
filter[row + maxN / 2] *= ((1 - rowFactLarge*colFactLarge) * rowFactSmall*colFactSmall);
filter[backrow + maxN / 2] *= ((1 - rowFactLarge*colFactLarge) * rowFactSmall*colFactSmall);
}
filter[0] = (band.remove_dc) ? 0 : filter[0];
}

введите описание изображения здесь

Вы можете просмотреть мой код, который использует его здесь: https://github.com/kandel3/DPM_PhaseRetrieval

2

Другие решения

Рассчитайте альфа и бета значения изображения
image = cv :: imread («F: \ Dilated.jpg»);
int x, y;
int a = 0; // переменные для использования в цикле
int count = 0; // переменные для использования в цикле

  for( int y = 0; y < image.rows; y++ )
{ for( int x = 0; x < image.cols; x++ )
{ for( int c = 0; c < 3; c++ )
{
image.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( alpha*(     image.at<Vec3b>(y,x)[c] ) + beta );
}
}
}
0

По вопросам рекламы [email protected]