найти контуры находит слишком много контуров на моделируемом изображении - PullRequest
0 голосов
/ 23 сентября 2019

Я хочу найти контуры бинарного изображения сегментированных камней.Есть некоторые проблемы с функцией findContours из opencv.

  1. Размер контура составляет около 1000, в то время как контуры из двоичного изображения могут быть около 30-50.

  2. Когда я рисую ВСЕ контуры, они кажутся приличным представлением черных границ двоичного изображения.Но когда я рисую только один контур некоторого случайного индекса, он показывает маленький контур.

Изображения приведены ниже:

  • Двоичное изображение

enter image description here

  • Контуры всего индекса

enter image description here

  • Контур произвольного индекса контура.Маленький зеленый контур

enter image description here

Мне бы хотелось иметь только точное количество контуров, как на двоичном изображении.

Код:

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(input_image, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
  for( int i = 0; i < (int)contours.size(); i++)
  {

      cv::drawContours(input_rgb_image, contours, 512 , cv::Scalar(0,255,0), 1, 8, hierarchy,1);


  }


Ответы [ 2 ]

1 голос
/ 23 сентября 2019

Я бы попробовал пару вещей:

  • Двусторонний фильтр вместо размытия.Он сглаживает вещи, похожие на размытие, но также пытается сохранить границы, что хорошо для сегментации.Недостатки - это вычислительно дорого, но вы можете найти «ваши» параметры, которые хорошо играют бесплатно
  • размытие + сегментация с смещением перед водоразделом.Размытие будет действовать точно так же, как и ожидалось, а среднее смещение будет усреднять и соединять контуры с одинаковыми цветами и, как таковое, уменьшать количество контуров.В зависимости от параметров, средство смещения также дорого.Просто поиграйте с ним.

Более продвинутая вещь - это анализ контуров после.Вы можете объединить некоторых соседей на основе:

  • сходства гистограммы на некоторых каналах hsv;
  • свойств контуров, таких как округлость.Если округлость двух объединенных соседей лучше, чем округлость любого из них, их можно объединить.Примерно так.

Расчет округлости:

float calcRoundness(std::vector<cv::Point> &contour, double area)
{
        float p = cv::arcLength(contour, true);
        if (p == 0)
                return 0;
        float k = (4 * M_PI * area) / pow(p, 2);

        /* 1 is circle, 0.75 - squared area, etc. */
        return k;
}
1 голос
/ 23 сентября 2019

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

Функция OpenCV findContours() находит темные контуры на светлом фоне.Если вы хотите найти пробелы, которые являются камнями, вам нужно сначала инвертировать двоичное изображение.Вы можете инвертировать двоичное изображение, как это invertedImage = 255 - binaryImage.Размытие также помогает, потому что он соединяет пиксели, которые должны быть связаны, но не из-за низкого разрешенияРазмытие выполняется с помощью кода blurredImage = cv2.blur(img, (2,2)).Это перевернутое размытое изображение:

invert and blur

Это код, который я использовал:

import cv2
import random
# Read image
gray = 255-cv2.imread('/home/stephen/Desktop/image.png', 0)
gray = cv2.blur(gray, (2,2))
# Find contours in image
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
img = cv2.imread('/home/stephen/Desktop/image.png')
for cnt in contours:
    color = random.randint(0,255),random.randint(0,255),random.randint(0,255)
    img = cv2.drawContours(img, [cnt], 0, color, cv2.FILLED)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
...