написание надежного (инвариантного цвета и размера) определения круга с помощью opencv (на основе преобразования Хафа или других функций) - PullRequest
46 голосов
/ 25 марта 2012

Я написал следующий очень простой код Python, чтобы найти круги на изображении:

import cv
import numpy as np

WAITKEY_DELAY_MS = 10
STOP_KEY = 'q'

cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);

key_pressed = False
while key_pressed != STOP_KEY:

    # grab image
    orig = cv.LoadImage('circles3.jpg')

    # create tmp images
    grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
    processed = cv.CreateImage(cv.GetSize(orig), 8, 1)


    cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

    cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

    # do some processing on the grey scale image
    cv.Erode(grey_scale, processed, None, 10)
    cv.Dilate(processed, processed, None, 10)
    cv.Canny(processed, processed, 5, 70, 3)
    cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

    storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

    # these parameters need to be adjusted for every single image
    HIGH = 50
    LOW = 140

    try: 
        # extract circles
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)

        for i in range(0, len(np.asarray(storage))):
            print "circle #%d" %i
            Radius = int(np.asarray(storage)[i][0][2])
            x = int(np.asarray(storage)[i][0][0])
            y = int(np.asarray(storage)[i][0][1])
            center = (x, y)

            # green dot on center and red circle around
            cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

            cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

    except:
        print "nothing found"
        pass

    # show images
    cv.ShowImage("image - press 'q' to quit", orig)
    cv.ShowImage("post-process", processed)

    cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
    key_pressed = chr(cv_key & 255)

Как видно из следующих двух примеров, «качество нахождения круга» сильно варьируется:

case1:

input1 detection1 post-processed1

Случай 2:

input2 detection2 post-processed2

Case1 и Case2 - это одно и то же изображение, но алгоритм все же обнаруживает разные круги. Если я представлю алгоритму изображение с кругами разного размера, обнаружение кругов может даже полностью потерпеть неудачу. В основном это связано с параметрами HIGH и LOW, которые необходимо настраивать индивидуально для каждого нового изображения.

Поэтому мой вопрос: Каковы различные возможности сделать этот алгоритм более надежным? Он должен быть неизменным по размеру и цвету, чтобы можно было обнаружить разные круги разных цветов и разных размеров. Может быть, использование преобразования Хафа - не лучший способ сделать что-то? Есть ли лучшие подходы?

Ответы [ 6 ]

36 голосов
/ 16 апреля 2012

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

Быстрые результаты

Некоторые примеры изображений (все изображения, кроме вашего, загружены с flickr.com и лицензированы CC) с обнаруженными кругами (без изменения / настройки каких-либо параметров, точно следующий код используется для извлечения кругов во всех изображениях ): detected blobs in the sample image 1 detected blobs in the sample image 2 lots of circles blobs in the flickr image 1

Код (на основе детектора BLOB-объектов MSER) ​​

А вот и код:

import cv2
import math
import numpy as np

d_red = cv2.cv.RGB(150, 55, 65)
l_red = cv2.cv.RGB(250, 200, 200)

orig = cv2.imread("c.jpg")
img = orig.copy()
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = cv2.FeatureDetector_create('MSER')
fs = detector.detect(img2)
fs.sort(key = lambda x: -x.size)

def supress(x):
        for f in fs:
                distx = f.pt[0] - x.pt[0]
                disty = f.pt[1] - x.pt[1]
                dist = math.sqrt(distx*distx + disty*disty)
                if (f.size > x.size) and (dist<f.size/2):
                        return True

sfs = [x for x in fs if not supress(x)]

for f in sfs:
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA)
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)

h, w = orig.shape[:2]
vis = np.zeros((h, w*2+5), np.uint8)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
vis[:h, :w] = orig
vis[:h, w+5:w*2+5] = img

cv2.imshow("image", vis)
cv2.imwrite("c_o.jpg", vis)
cv2.waitKey()
cv2.destroyAllWindows()

Как вы можете видеть, он основан на блоб-детекторе MSER . Код не обрабатывает изображение отдельно от простого преобразования в оттенки серого. Таким образом, ожидается отсутствие этих слабых желтых пятен на изображениях.

Теория

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

Вернуться к основному вопросу: как лучше всего решить эту проблему? Давайте посмотрим на это как на проблему поиска. Для упрощения обсуждения предположим, что мы ищем круги с заданным размером / радиусом. Таким образом, проблема сводится к поиску центров. Каждый пиксель является центром-кандидатом, поэтому пространство поиска содержит все пиксели.

P = {p1, ..., pn} 
P: search space
p1...pn: pixels

Для решения этой поисковой задачи должны быть определены две другие функции:

E(P) : enumerates the search space
V(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list

Предполагая, что сложность алгоритма не имеет значения, можно использовать исчерпывающий или грубый поиск, в котором E отбирает каждый пиксель и переходит к V. В приложениях реального времени важно уменьшить пространство поиска и оптимизировать вычислительные вычисления. КПД В.

Мы приближаемся к основному вопросу. Как мы могли бы определить V, чтобы быть более точным, какие свойства кандидатов должны быть измерены и как следует решить проблему дихотомии, разделив их на желательные и нежелательные. Наиболее распространенный подход состоит в том, чтобы найти некоторые свойства, которые можно использовать для определения простых правил принятия решений на основе измерения свойств. Это то, что вы делаете методом проб и ошибок. Вы программируете классификатор, учась на положительных и отрицательных примерах. Это потому, что используемые вами методы не имеют представления о том, что вы хотите делать. Необходимо настроить / настроить параметры правила принятия решений и / или предварительно обработать данные таким образом, чтобы вариации свойств (желательных кандидатов), используемых методом для задачи дихотомии, были уменьшены. Вы можете использовать алгоритм машинного обучения, чтобы найти оптимальные значения параметров для данного набора примеров. Существует целый ряд алгоритмов обучения, от деревьев решений до генетического программирования, которые вы можете использовать для решения этой проблемы. Вы также можете использовать алгоритм обучения, чтобы найти оптимальные значения параметров для нескольких алгоритмов обнаружения окружностей и посмотреть, какой из них дает лучшую точность. Это берет на себя основную нагрузку на алгоритм обучения, который вам нужен для сбора образцов изображений.

Другой подход к повышению надежности, который часто упускается из виду, заключается в использовании чрезвычайно доступной информации. Если вы знаете цвет кругов практически без лишних усилий, вы можете значительно улучшить точность детектора. Если вы знали положение кругов на плоскости и хотели обнаружить изображенные круги, вы должны помнить, что преобразование между этими двумя наборами позиций описывается 2D-гомографией. И гомография может быть оценена, используя только четыре пункта. Тогда вы могли бы улучшить надежность, чтобы иметь твердый метод. Ценность предметно-ориентированных знаний часто недооценивают. Посмотрите на это так, в первом подходе мы пытаемся приблизить некоторые правила принятия решений на основе ограниченного количества выборок. Во втором подходе мы знаем правила принятия решений и нам нужно только найти способ эффективно использовать их в алгоритме.

Резюме

Подводя итог, можно выделить два подхода к повышению точности / надежности решения:

  1. На основе инструмента : поиск более простого в использовании алгоритма / с меньшим количеством параметров / настройка алгоритма / автоматизация этого процесса с использованием алгоритмов машинного обучения
  2. На основе информации : вы используете всю легкодоступную информацию? В вопросе вы не упоминаете, что вы знаете о проблеме.

Для этих двух изображений, которыми вы поделились, я бы использовал детектор капли, а не метод HT. Для вычитания фона я бы предложил попробовать оценить цвет фона, так как на двух изображениях он не меняется, а цвет кружков меняется. И большая часть площади голая.

28 голосов
/ 13 апреля 2012

Это большая проблема моделирования.У меня есть следующие рекомендации / идеи:

  1. Разделить изображение на RGB, затем обработать.
  2. предварительная обработка.
  3. Динамический поиск параметров.
  4. Добавить ограничения.
  5. Будьте уверены в том, что вы пытаетесь обнаружить.

Более подробно:

1: Как отмечено в другихответы, преобразованные прямо в оттенки серого, отбрасывают слишком много информации - любые круги с яркостью, аналогичной фону, будут потеряны.Гораздо лучше рассмотреть цветовые каналы либо изолированно, либо в другом цветовом пространстве.Здесь есть два основных способа: выполнить HoughCircles на каждом предварительно обработанном канале в отдельности, затем объединить результаты или обработать каналы, затем объединить их и затем выполнить HoughCircles.В моей попытке ниже, я попробовал второй метод, разделение на каналы RGB, обработка, а затем объединение.Остерегайтесь чрезмерного насыщения изображения при объединении, я использую cv.And, чтобы избежать этой проблемы (на этом этапе мои круги всегда являются черными кольцами / дисками на белом фоне).

2: Предварительная обработка довольно сложнаи что-то его часто лучше всего поиграть.Я использовал AdaptiveThreshold, который является действительно мощным методом свертки, который может усиливать края изображения, устанавливая пороговые значения пикселей на основе их локального среднего (аналогичные процессы также происходят на ранних этапах визуальной системы млекопитающих).Это также полезно, так как снижает уровень шума.Я использовал dilate/erode только с одним проходом.И я сохранил другие параметры, как у вас.Кажется, использование Canny до HoughCircles очень помогает в поиске «заполненных кругов», так что, вероятно, лучше сохранить его. Эта предварительная обработка довольно тяжелая и может привести к ложным срабатываниям с несколько более «круглыми кружочками»,но в нашем случае это, возможно, желательно?

3: Как вы отметили, параметр HoughCircles param2 (ваш параметр LOW) необходимо настроить для каждого изображения, чтобы получить оптимальное решение, вфакт из документов :

Чем оно меньше, тем больше ложных кругов можно обнаружить.

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

максимальное количество не перекрывающихся и не содержащихся кругов

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

4: Есть ли еще какие-то ограничения, которые мы можем добавить к модели?Чем больше вещей мы можем сказать нашей модели, тем легче задача, которую мы можем сделать, чтобы обнаружить круги.Например, знаем ли мы:

  • Количество кружков.- полезна даже верхняя или нижняя граница.
  • Возможные цвета кругов, или фона, или "некруглых".
  • Их размеры.
  • Где они могут быть на изображении.

5: Некоторые из капель на ваших изображениях можно назвать вольными кругами!Рассмотрим два «некруглых шарика» на вашем втором изображении, мой код не может их найти (хорошо!), Но… если я «сделаю фотошоп», чтобы они были более круглыми, мой код может их найти ...Может быть, если вы хотите обнаружить вещи, которые не являются кругами, лучше использовать другой подход, например Tim Lukins.

Проблемы

При интенсивной предварительной обработке AdaptiveThresholding и `Canny 'объекты изображения могут сильно искажаться, что может привести к обнаружению ложных окружностей или неправильным отчетам о радиусах. Например, на большом твердом диске после обработки может появиться кольцо, поэтому HughesCircles может найти внутреннее кольцо. Кроме того, даже документы отмечают, что:

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

Если вам нужно более точное обнаружение радиусов, я предлагаю следующий подход (не реализован):

  • На исходном изображении - трассировка лучей от сообщенного центра круга в расширяющемся кресте (4 луча: вверх / вниз / влево / вправо)
  • Делать это отдельно в каждом канале RGB
  • Объедините эту информацию для каждого канала для каждого луча разумным образом (т. Е. При необходимости отразите, сместите, масштабируйте и т. Д.)
  • возьмите среднее значение для первых нескольких пикселей на каждом луче, используйте его, чтобы определить, где происходит значительное отклонение на луче.
  • Эти 4 точки являются оценками точек на окружности.
  • Используйте эти четыре оценки, чтобы определить более точный радиус и центральное положение (!).
  • Это можно обобщить, используя расширяющееся кольцо вместо четырех лучей.

Результаты

Код в конце довольно хорошо работает, эти примеры были сделаны с кодом, как показано:

Обнаруживает все круги на вашем первом изображении: enter image description here

Как выглядит предварительно обработанное изображение до применения фильтра canny (хорошо видны разноцветные круги): enter image description here

Обнаруживает все (кроме двоичных объектов) на втором изображении: enter image description here

Изменено второе изображение (капли округлены, а большой овал сделан более круглым, что улучшает обнаружение), все обнаружено: enter image description here

Довольно хорошо обнаруживает центры на этой картине Кандинского (я не могу найти концентрические кольца из-за граничных условий). enter image description here

Код:

import cv
import numpy as np

output = cv.LoadImage('case1.jpg')
orig = cv.LoadImage('case1.jpg')

# create tmp images
rrr=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
ggg=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
bbb=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
processed = cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

def channel_processing(channel):
    pass
    cv.AdaptiveThreshold(channel, channel, 255, adaptive_method=cv.CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=cv.CV_THRESH_BINARY, blockSize=55, param1=7)
    #mop up the dirt
    cv.Dilate(channel, channel, None, 1)
    cv.Erode(channel, channel, None, 1)

def inter_centre_distance(x1,y1,x2,y2):
    return ((x1-x2)**2 + (y1-y2)**2)**0.5

def colliding_circles(circles):
    for index1, circle1 in enumerate(circles):
        for circle2 in circles[index1+1:]:
            x1, y1, Radius1 = circle1[0]
            x2, y2, Radius2 = circle2[0]
            #collision or containment:
            if inter_centre_distance(x1,y1,x2,y2) < Radius1 + Radius2:
                return True

def find_circles(processed, storage, LOW):
    try:
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, LOW)#, 0, 100) great to add circle constraint sizes.
    except:
        LOW += 1
        print 'try'
        find_circles(processed, storage, LOW)
    circles = np.asarray(storage)
    print 'number of circles:', len(circles)
    if colliding_circles(circles):
        LOW += 1
        storage = find_circles(processed, storage, LOW)
    print 'c', LOW
    return storage

def draw_circles(storage, output):
    circles = np.asarray(storage)
    print len(circles), 'circles found'
    for circle in circles:
        Radius, x, y = int(circle[0][2]), int(circle[0][0]), int(circle[0][1])
        cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
        cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

#split image into RGB components
cv.Split(orig,rrr,ggg,bbb,None)
#process each component
channel_processing(rrr)
channel_processing(ggg)
channel_processing(bbb)
#combine images using logical 'And' to avoid saturation
cv.And(rrr, ggg, rrr)
cv.And(rrr, bbb, processed)
cv.ShowImage('before canny', processed)
# cv.SaveImage('case3_processed.jpg',processed)
#use canny, as HoughCircles seems to prefer ring like circles to filled ones.
cv.Canny(processed, processed, 5, 70, 3)
#smooth to reduce noise a bit more
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)
cv.ShowImage('processed', processed)
#find circles, with parameter search
storage = find_circles(processed, storage, 100)
draw_circles(storage, output)
# show images
cv.ShowImage("original with circles", output)
cv.SaveImage('case1.jpg',output)

cv.WaitKey(0)
12 голосов
/ 12 апреля 2012

Ах, да ... старые инварианты цвета / размера для задачи о кругах (AKA - преобразование Хафа слишком специфично и не устойчиво) ...

В прошлом я больше полагался на Анализ конструкции и формы функции OpenCV вместо.Из папки «samples» вы можете получить очень хорошее представление о том, что возможно, в частности fitellipse.py и squares.py.

. Для вашего пояснения я представляю гибридную версию этих примеров на основе вашего оригинала.источник.Обнаруженные контуры выделены зеленым, а подогнанные эллипсы - красным.

enter image description here

Пока еще не совсем:

  • Для этапов предварительной обработки требуетсянемного настройки, чтобы обнаружить более слабые круги.
  • Вы можете проверить контур дальше, чтобы определить, является ли он кругом или нет ...

Удачи!

import cv
import numpy as np

# grab image
orig = cv.LoadImage('circles3.jpg')

# create tmp images
grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
processed = cv.CreateImage(cv.GetSize(orig), 8, 1)

cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

# do some processing on the grey scale image
cv.Erode(grey_scale, processed, None, 10)
cv.Dilate(processed, processed, None, 10)
cv.Canny(processed, processed, 5, 70, 3)
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

#storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
storage = cv.CreateMemStorage(0)

contours = cv.FindContours(processed, storage, cv.CV_RETR_EXTERNAL)
# N.B. 'processed' image is modified by this!

#contours = cv.ApproxPoly (contours, storage, cv.CV_POLY_APPROX_DP, 3, 1) 
# If you wanted to reduce the number of points...

cv.DrawContours (orig, contours, cv.RGB(0,255,0), cv.RGB(255,0,0), 2, 3, cv.CV_AA, (0, 0)) 

def contour_iterator(contour):
  while contour:
    yield contour
    contour = contour.h_next()

for c in contour_iterator(contours):
  # Number of points must be more than or equal to 6 for cv.FitEllipse2
  if len(c) >= 6:
    # Copy the contour into an array of (x,y)s
    PointArray2D32f = cv.CreateMat(1, len(c), cv.CV_32FC2)

    for (i, (x, y)) in enumerate(c):
      PointArray2D32f[0, i] = (x, y)

    # Fits ellipse to current contour.
    (center, size, angle) = cv.FitEllipse2(PointArray2D32f)

    # Convert ellipse data from float to integer representation.
    center = (cv.Round(center[0]), cv.Round(center[1]))
    size = (cv.Round(size[0] * 0.5), cv.Round(size[1] * 0.5))

    # Draw ellipse
    cv.Ellipse(orig, center, size, angle, 0, 360, cv.RGB(255,0,0), 2,cv.CV_AA, 0)

# show images
cv.ShowImage("image - press 'q' to quit", orig)
#cv.ShowImage("post-process", processed)
cv.WaitKey(-1)

РЕДАКТИРОВАТЬ:

Просто обновление, чтобы сказать, что я считаю основной темой для всех этих ответов является то, что есть множество дополнительных предположений и ограничений, которые могут быть применены кто, что вы стремитесь распознать как циркуляр .Мой собственный ответ не претендует на это - ни в предварительной обработке низкого уровня, ни в геометрической подгонке высокого уровня.Тот факт, что многие круги на самом деле не такие круглые, из-за того, как они нарисованы, или из-за неаффинных / проективных преобразований изображения, а также из-за других свойств их отображения / захвата (цвет, шум, освещение,толщина кромки) - все это приводит к любому числу возможных кругов-кандидатов в одном изображении.

Существуют гораздо более сложные приемы.Но они будут стоить вам.Лично мне нравится идея @fraxel об использовании аддаптивного порога.Это быстро, надежно и достаточно надежно.Затем можно дополнительно проверить конечные контуры (например, использовать моменты Ху) или фитинги с помощью простого теста отношения оси эллипса - например, если ((min (размер) / max (размер))> 0,7).

Как и в случае с Computer Vision, существует противоречие между прагматизмом, принципом и скупостью.Поскольку я люблю рассказывать людям, которые думают, что CV - это легко, это не так - на самом деле это классическая проблема AI complete .Лучшее, на что вы часто можете надеяться, это то, что работает большую часть времени.

9 голосов
/ 26 марта 2012

Просматривая ваш код, я заметил следующее:

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

  • Обнаружение края после удаления шума (стирание / расширение). Это не должно быть необходимым; Кэнни должен позаботиться об этом.

  • Обнаружение канни. Ваши «открытые» круги имеют два ребра, внутреннее и внешнее ребро. Так как они довольно близки, фильтр Гауни Канни может сложить их вместе. Если этого не произойдет, вы будете иметь два края близко друг к другу. То есть перед Кэнни у вас есть открытые и заполненные круги. После этого у вас есть 0/2 и 1 край, соответственно. Поскольку Hough снова вызывает Canny, в первом случае два ребра могут быть сглажены вместе (в зависимости от начальной ширины), поэтому основной алгоритм Hough может обрабатывать открытые и заполненные кружки одинаково.

Итак, моя первая рекомендация - изменить отображение в градациях серого. Не используйте интенсивность, но используйте оттенок / насыщенность / значение. Кроме того, используйте дифференцированный подход - вы ищете края. Итак, вычислите преобразование HSV, сгладьте копию, а затем возьмите разницу между исходной и сглаженной копиями. Это даст вам dH, dS, dV значения (локальное изменение оттенка, насыщенности, значения) для каждой точки. Квадрат и добавить, чтобы получить одномерное изображение, с пиками у всех краев (внутренний и внешний).

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

6 голосов
/ 26 марта 2012

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

Тем не менее, я вижу несколько вещей, которые могут вам помочь с этой функцией:

  1. HoughCircles звонки Canny внутри страны, так что, я думаю, вы можете оставить этот вызов.
  2. param1 (который вы называете HIGH) обычно инициализируется вокруг значения 200. Он используется в качестве параметра для внутреннего вызова Canny: cv.Canny(processed, cannied, HIGH, HIGH/2). Это может помочь запустить Canny самостоятельно, чтобы увидеть, как настройка HIGH влияет на изображение, с которым работает преобразование Хафа.
  3. param2 (который вы называете LOW) обычно инициализируется вокруг значения 100. Это порог голосования для аккумуляторов преобразования Хафа. Установка его выше означает больше ложных негативов, ниже больше ложных срабатываний. Я считаю, что это первое, с чем вы хотите начать возиться.

Ссылка: http://docs.opencv.org/3.0-beta/modules/imgproc/doc/feature_detection.html#houghcircles

Обновление re: заливка окружностей : После того, как вы нашли формы окружностей с помощью преобразования Хафа, вы можете проверить, заполнены ли они, выбрав цвет границы и сравнив его с одной или несколькими точками внутри предполагаемой круг. В качестве альтернативы вы можете сравнить одну или несколько точек внутри предполагаемого круга с заданным цветом фона. Круг заполняется в случае успешного первого сравнения или в случае альтернативного сравнения в случае неудачи.

2 голосов
/ 11 апреля 2012

Хорошо, глядя на изображения.Я предлагаю использовать **Active Contours**

  • Активные контуры Преимущество активных контуров в том, что они почти идеально вписываются в любую заданную форму.Будь то квадраты или треугольники, и в вашем случае они являются идеальными кандидатами.
  • Если вы можете выделить центр кругов, это здорово.Активным контурам всегда нужно начинать с точки, с которой они могут расти или уменьшаться, чтобы соответствовать.Не обязательно, чтобы центры всегда были выровнены по центру.Небольшое смещение все еще будет в порядке.
  • И в вашем случае, если вы позволите контурам расти от центра наружу, они будут ограничивать границы круга.
  • Обратите внимание, что активные контурыдля увеличения или уменьшения используйте энергию воздушного шара , что означает, что вы можете установить направление контуров, внутрь или наружу.
  • Возможно, вам потребуется использовать градиентное изображение в оттенках серого.Но все же вы можете попробовать в цвете.Если это работает!
  • А если вы не предоставите центры, добавьте множество активных контуров, сделайте, а затем увеличивайте / уменьшайте.Контуры, которые успокаиваются, сохраняются, неустановленные - выбрасываются.Это подход грубой силы.Будет ли процессор интенсивным.Но потребуется более тщательная работа, чтобы убедиться, что вы оставляете правильные контуры и выбрасываете плохие.

Я надеюсь, что таким образом вы сможете решить проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...