OpenCV (35) --- Преобразование Хафа

OpenCV
OpenCV (35) --- Преобразование Хафа

Что такое преобразование Хафа

Преобразование Хафа — это метод поиска линий, кругов и других простых фигур на изображении. Преобразование Хафа, впервые предложенное Полом Хафом в 1962 году, использует подход, похожий на голосование, для получения набора фигур в текущем изображении.

Начальное линейное преобразование Хафа можно использовать для обнаружения, после проявления преобразование Хафа можно распознавать не только прямолинейно, но и распознавать другие простые графические структуры, обычный круг, овал и тому подобное.

Функция HoughLines

В OpenCV он предоставляет нам функцию cv2.HoughLines() для реализации преобразования линии Хафа, Эта функция требует, чтобы исходное изображение всех операций было двоичным изображением, поэтому перед преобразованием Хафа изображение должно быть двоичным. Или сделайте обнаружение края Canny.

Его полное определение выглядит следующим образом:

def HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None):

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

rho: Точность расстояния r в пикселях. Обычно используется точность 1

тета: точность угла θ. Как правило, используется точность Π/180, что означает, что необходимо искать все возможные углы.

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

линии: возвращаемое значение, каждый элемент которого представляет собой пару чисел с плавающей запятой, представляющих параметры обнаруженной линии, а именно (r, θ). имеет тип numpy.ndarray.

HoughLines в действии

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

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("35.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLines(edges, 1, np.pi / 180, 140)
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

После запуска эффект следующий:

霍夫变换

Реальный бой HoughLinesP

Хотя преобразование Хафа можно выполнить с помощью HoughLines, оно само по себе имеет очень серьезные ложные обнаружения. Чтобы решить эту проблему, OpenCV добавил функцию преобразования Хафа вероятности cv2.HoughLinesP().

Его полное определение выглядит следующим образом:

def HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None): 

Изображение: исходное изображение, такое как одноканальный 8-битный двоичный образ

ро: то же, что и выше

тета: то же, что и выше

порог: такой же, как указано выше

линии: такие же, как указано выше

minLineLength: значение, используемое для управления «минимальной длиной принимаемых строк». Значение по умолчанию – 0.

maxLineGap: используется для управления минимальным зазором между принятыми коллинеарными сегментами линии, то есть максимальным зазором между двумя точками на прямой линии. Если интервал между двумя точками превышает значение параметра maxLineGap, считается, что две точки не лежат на одной прямой. Значение по умолчанию – 0.

Улучшите приведенный выше пример с помощью HoughLinesP следующим образом:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("35.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 10, 10)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 5)
plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

После запуска эффект следующий:

霍夫变换2

Как видите, здесь мы используем функцию HoughLinesP, чтобы полностью отметить линии шахматной доски.

HoughCircles в действии

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

Среди них мы можем использовать преобразование круга Хафа для обнаружения кругов на изображении. Здесь нам нужно только рассмотреть три параметра координаты центра (x, y) и радиуса r.

В OpenCV нужно пройти 2 шага:

  1. Узнайте, где может существовать круг (в центре)
  2. Вычислить радиус от 1

В OpenCV функция преобразования круга Хафа, которую он нам предоставляет, называется cv2.HoughCircle(). Эта функция также сочетает обнаружение краев по Кэнни с преобразованием Хафа.Единственное отличие состоит в том, что вместо обнаружения краев по Кэнни эта функция сначала автоматически выполняет обнаружение краев по Кэнни.

Его полное определение выглядит следующим образом:

def HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None): 

изображение: исходное изображение, 8-битное одноканальное изображение в градациях серого

method: метод обнаружения, HOUGH_GRADIENT — единственное доступное значение параметра. Этот параметр представляет метод, используемый в двух раундах обнаружения при обнаружении круга Хафа.

dp: Разрешение накопителя, которое представляет собой коэффициент деления, используемый для определения отношения разрешения изображения к разрешению центрального накопителя. Например, если dp=1, входное изображение и аккумулятор имеют одинаковое разрешение.

minDist: минимальное расстояние между центрами кругов. Это значение используется в качестве порога.Если есть несколько кругов с расстоянием между их центрами меньше этого значения, будет обнаружен только один. Поэтому, если значение слишком мало, будет обнаружено много соседних кругов; если значение велико, многие круги могут быть пропущены во время обнаружения.

круги: возвращаемое значение, тип numpy.ndarray, состоящий из координат центра и радиуса.

param1: по умолчанию этот параметр имеет значение 100. Соответствует высокому порогу детектора границ Кэнни (нижний порог равен половине верхнего порога).

param2: количество голосов, которое должен получить центр круга. Только в процессе первого тура отбора круги, проголосовавшие больше этого значения, имеют право пройти во второй тур отбора. Следовательно, чем больше значение, тем меньше кругов обнаруживается, чем меньше значение, тем больше кругов обнаруживается. Это также значение по умолчанию, по умолчанию 100.

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

maxRadius: максимальное значение радиуса круга, круги больше этого значения не будут обнаружены. Это также значение по умолчанию, значение по умолчанию равно 0, что не работает.

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

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("35_1.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 300, param1=50, param2=20,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
    cv2.circle(img, (i[0], i[1]), i[2], (255, 0, 0), 12)
    cv2.circle(img, (i[0], i[1]), 2, (255, 0, 0), 12)

plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

После запуска эффект следующий:

霍夫圆