Как вычисляется дефект выпуклости в OpenCV? - PullRequest
0 голосов
/ 24 сентября 2018

Какой алгоритм используется в функции OpenCV convexityDefects() для расчета дефектов выпуклости контура?

Пожалуйста, опишите и проиллюстрируйте работу алгоритма высокого уровня вместе сс его входами и выходами.

1 Ответ

0 голосов
/ 24 сентября 2018

На основании документации вводится два списка координат:

  • contour, определяющий исходный контур (красный на изображении ниже)
  • convexhull определяет выпуклый корпус, соответствующий этому контуру (синий на изображении ниже)

Example contour and convex hull

Алгоритм работает следующим образом:

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

Примечание: В дальнейшем объяснении я предполагаю, что они находятся в одинаковой ориентации, и игнорирую деталио представлении глубины с плавающей точкой в ​​виде целого числа.

Затем для каждой пары соседних точек корпуса (H[i], H[i+1]), определяющих один край выпуклой оболочки, рассчитайте расстояние открай каждой точки контура C[n], который лежит между H[i] и H[i+1] (исключая C[n] == H[i+1]).Если расстояние больше нуля, значит, дефект присутствует.При наличии дефекта запишите i, i+1, максимальное расстояние и индекс (n) точки контура, в которой находится максимум.

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

dx0 = H[i+1].x - H[i].x
dy0 = H[i+1].y - H[i].y

if (dx0 is 0) and (dy0 is 0) then
    scale = 0
else
    scale = 1 / sqrt(dx0 * dx0 + dy0 * dy0)

dx = C[n].x - H[i].x
dy = C[n].y - H[i].y

distance = abs(-dy0 * dx + dx0 * dy) * scale

Может быть проще визуализировать с точки зрения векторов:

  • C: вектор дефекта от H[i] до C[n]
  • H: вектор края корпуса от H[i] до H[i+1]
  • H_rot: вектор края корпуса H повернуто на 90 градусов
  • U_rot: единичный вектор в направлении H_rot

H* Компоненты 1080 * равны [dx0, dy0], поэтому при повороте на 90 градусов [-dy0, dx0].

scale используется для поиска U_rot из H_rot, но поскольку деления в вычислительном отношении дороже, чем умножения, обратное используется в качестве оптимизации.Он также предварительно рассчитывается перед циклом над C[n], чтобы избежать повторного вычисления каждой итерации.

| H |= sqrt (dx0 * dx0 + dy0 * dy0)

U_rot = H_rot / | H |= H_rot * scale

Затем точечное произведение между C и U_rot дает перпендикулярное расстояние отточка дефекта указывает на край корпуса, и abs() используется для получения положительной величины в любой ориентации.

distance = abs (U_rot. C) = abs (-dy0 * dx + dx0 * dy) * scale


В сценарии, изображенном на изображении выше, в первой итерации ребро определяется как H[0] и H[1].Точки контура, которые нужно исследовать для этого края: C[0], C[1] и C[2] (начиная с C[3] == H[1]).

First edge

Тамдефекты на C[1] и C[2].Дефект в C[1] является самым глубоким, поэтому алгоритм будет записывать (0, 1, 1, 50).

Следующее ребро определяется H[1] и H[2] и соответствующей точкой контура C[3].Дефектов нет, поэтому ничего не записывается.

Следующее ребро определяется H[2] и H[3] и соответствующей точкой контура C[4].Дефектов нет, поэтому ничего не записано.

Начиная с C[5] == H[3], последнюю точку контура можно игнорировать - там не может быть дефектов.

...