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

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

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

Примеры изображений: img  гиф


person vityav    schedule 18.06.2014    source источник
comment
en.wikipedia.org/wiki/Histogram_equalization на уровне патча (разделите изображение, например, на 5x5= 25 патчей, чтобы можно было оценить разную статистику при другом освещении)   -  person Pavel    schedule 18.06.2014
comment
Я чувствую, что это будет иметь последствия для патчей, которые перекрывают разные яйца и регионы без яиц. Я использовал AdaptiveThreshold() с большими размерами блоков, и он всегда обнаруживал посторонние объекты, хотя помогал с градиентным освещением.   -  person vityav    schedule 19.06.2014


Ответы (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

person Mikhail    schedule 23.01.2017
comment
Хотя я еще не убедился, что это помогает в данном случае (поскольку внутренности яиц, вероятно, значительно проявляются в этой форме обнаружения краев), это, безусловно, интересно и привело к кроличьей норе обработки изображений с полосовыми фильтрами. - person vityav; 24.01.2017

Вычислить альфа- и бета-значения изображения image = cv::imread("F:\Dilated.jpg"); интервал х, у; инт а=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 );
           }
       }
  }
person Maddy    schedule 20.06.2014
comment
Как рассчитать альфа и бета? Похоже, вы делаете какую-то линейную регрессию, но я не понимаю, к чему вы подходите. - person vityav; 24.06.2014