Обнаружение кластеров белых пикселей в изображении с помощью openCV

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

Ожидаемый результат: введите описание изображения здесь

Я собираюсь уместить три (или некоторое количество) многоугольников (в данном случае прямоугольников), чтобы обозначить «большие» белые пятна на этом изображении. Прямоугольники, нарисованные на выходном изображении, соответствуют моему восприятию белых областей. Я не ожидаю, что алгоритм предложит те же самые области строения. Я хочу разместить некоторое количество плотных многоугольников вокруг кластеров белых пикселей.

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

Однако, поскольку белые области сильно фрагментированы с черными областями внутри и выступами по краям, количество контуров, возвращаемых cv2.findContours, очень велико (около 500 или около того). Из-за этого установка выпуклой оболочки не улучшает форму белых областей. Белые области в основном сохраняют свои первоначальные абстрактные формы. Моя цель состояла в том, чтобы объединить множество маленьких контуров белой области в единый, содержащий контур, по которому я затем смогу разместить выпуклую оболочку.

Как мне решить эту проблему? Следует ли мне сначала использовать алгоритм кластеризации по точкам контура, чтобы найти контуры, которые близки друг к другу?


person The mach    schedule 17.06.2013    source источник


Ответы (4)


Сначала вам нужно выполнить морфологическое закрытие (то есть дилатацию с последующей эрозией) на этом изображении. Это закрывает все крошечные «дыры» вашего изображения, сохраняя при этом форму и размер отдельных компонентов. В отличие от него, когда за эрозией следует расширение, он удаляет зашумленные точки на изображении. Я работаю над похожим изображением, и мне пришлось выполнить дилатацию + эрозию целых 10 раз, чтобы выровнять мои компоненты. После этого используйте связанные компоненты или найдите контуры. Это обязательно снизит обратный отсчет контура с 400 до 20-30.

Во-вторых, вы упомянули, что вам нужно 3 кластера. Хотя два маленьких кластера (обозначенные красной линией) могли бы слиться в один. Что я из этого сделал, так это то, что вы хотите, чтобы каждый кластер как можно плотнее вписывался в ограничивающий его прямоугольник. Итак, я предлагаю вам установить пороговую эффективность (скажем, 80%) и использовать иерархическую кластеризацию для объединения каждого подключенного компонента в кластер. Когда ваши белые пиксели занимают менее 80% пространства своего ограничивающего прямоугольника (кластера), вы остановите кластеризацию и получите кластеры.

person Ekansh Gupta    schedule 29.05.2014

Перед нахождением контуров вы можете сначала расширить изображение. Расширение вызывает рост ярких областей. Вы можете думать об этом как о добавлении белых пикселей вокруг каждого существующего белого пикселя в вашем изображении. Таким образом сливаются соседние яркие формы. См. http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

Вы также можете снова размыть и порог, но размытие может быть намного дороже, чем расширение, в зависимости от степени размытия.

person tim k    schedule 18.06.2013

Вы можете использовать кластеризацию kmeans, используя координату x y в качестве функции для каждой белой точки и трех кластеров. Затем возьмем выпуклую оболочку полученных трех кластеров. Возможно, вам придется попробовать разные отправные точки и выбрать лучший результат. См. http://docs.opencv.org/modules/core/doc/clustering.html#kmeans

person Bull    schedule 18.06.2013

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

Просто повторяйте, пока у ваших самых больших трех корпусов не появится какое-либо обязательное свойство (например, если они покрывают 99% всех белых точек).

#include <vector>
using std::vector;
#include <algorithm>
using std::sort;
#include <string>
using std::string;
using std::to_string;
#include <iostream>
using std::clog;
using std::endl;
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
  typedef vector<Point> Polygon;
  typedef vector<Polygon> Polygons;
  Mat mFrame;
  Mat mOrig;
  mFrame = imread("R2TsZ.png");
  mFrame.copyTo(mOrig);
  Mat mOrigHull;
  Mat mOut;
  int fileCounter = 0;
  while(true){
    clog<< "image read"<< endl;
    cvtColor(mFrame, mOut, CV_BGR2GRAY);
    clog<< "image grayscaled"<< endl;
    Polygons contours;
    Polygons aContours;
    Polygons hulls;
    OutputArray hierarchy = {};

    findContours(mOut, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    clog<< contours.size()<< " contours found"<< endl;
    sort(contours.begin(), contours.end(), [](auto p1, auto p2){
      return contourArea(p1) > contourArea(p2);
    });
    clog<< "contours sorted"<< endl;
    aContours.resize(contours.size());
    hulls.resize(contours.size());
    for(size_t i = 0; i < aContours.size() - 1; ++ i){
      approxPolyDP(contours[i], aContours[i], 20, true);
      drawContours(mFrame, aContours, i, Scalar(255, 255, 255), 10);
      convexHull(aContours[i], hulls[i], true);
    }
    mOrig.copyTo(mOrigHull);
    for(size_t i = 0; i < 3; ++ i){
      drawContours(mOrigHull, hulls, i, Scalar(0, 0, 255), 10);
    }
    imshow("out", mOrigHull);
    int key = waitKey() & 0xff;
    if(key == 27){
      return EXIT_SUCCESS;
    }
    if(key == 'p'){
      string file = "test_" + to_string(++ fileCounter) + ".png";
      imwrite(file, mOrigHull);
      clog<< file<< " saved."<< endl;
    }
  }
}

Подробнее см. В этом руководстве от opencv.

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

person nurettin    schedule 14.08.2016
comment
Любая реализация на Python? - person ; 11.11.2019
comment
@Dev Я использовал функцию approxPolyDP из учебника opencv, на который я дал ссылку. Пример в этой ссылке написан на Python. - person nurettin; 11.11.2019