Я пытаюсь использовать модель EAST в OpenCV для обнаружения текста на изображениях. Я успешно получаю результат после запуска изображения через сеть, но мне трудно понять, как работает функция декодирования, которую я использую. Я знаю, что я получаю 5 чисел на выходе из модели, и я думаю, что это расстояния от точки до верхней, нижней, левой и правой сторон прямоугольника, соответственно, и угол поворота в конце. Я не уверен, что делает функция декодирования, чтобы получить ограничивающую рамку для текстовой области.
Я знаю, почему смещение умножается на 4 (при прогоне модели оно уменьшается на 4). Я знаю, почему h и w такие, какие они есть. Я не уверен ни в чем после этого.
баллы — это баллы достоверности для каждого региона; геометрия — это значения геометрии для каждой области (пять чисел, которые я упомянул) scoreThresh — это просто порог для немаксимального подавления
def decode(scores, geometry, scoreThresh):
detections = []
confidences = []
############ CHECK DIMENSIONS AND SHAPES OF geometry AND scores ############
assert len(scores.shape) == 4, "Incorrect dimensions of scores"
assert len(geometry.shape) == 4, "Incorrect dimensions of geometry"
assert scores.shape[0] == 1, "Invalid dimensions of scores"
assert geometry.shape[0] == 1, "Invalid dimensions of geometry"
assert scores.shape[1] == 1, "Invalid dimensions of scores"
assert geometry.shape[1] == 5, "Invalid dimensions of geometry"
assert scores.shape[2] == geometry.shape[2], "Invalid dimensions of scores and geometry"
assert scores.shape[3] == geometry.shape[3], "Invalid dimensions of scores and geometry"
height = scores.shape[2]
width = scores.shape[3]
for y in range(0, height):
# Extract data from scores
scoresData = scores[0][0][y]
x0_data = geometry[0][0][y]
x1_data = geometry[0][1][y]
x2_data = geometry[0][2][y]
x3_data = geometry[0][3][y]
anglesData = geometry[0][4][y]
for x in range(0, width):
score = scoresData[x]
# If score is lower than threshold score, move to next x
if (score < scoreThresh):
continue
# Calculate offset
offsetX = x * 4.0
offsetY = y * 4.0
angle = anglesData[x]
# Calculate cos and sin of angle
cosA = math.cos(angle)
sinA = math.sin(angle)
h = x0_data[x] + x2_data[x]
w = x1_data[x] + x3_data[x]
# Calculate offset
offset = ([offsetX + cosA * x1_data[x] + sinA * x2_data[x], offsetY - sinA * x1_data[x] + cosA * x2_data[x]])
# Find points for rectangle
p1 = (-sinA * h + offset[0], -cosA * h + offset[1])
p3 = (-cosA * w + offset[0], sinA * w + offset[1])
center = (0.5*(p1[0]+p3[0]), 0.5*(p1[1]+p3[1]))
detections.append((center, (w,h), -1*angle * 180.0 / math.pi))
confidences.append(float(score))
# Return detections and confidences
return [detections, confidences]
В основном, почему функция декодирования делает то, что делает?
бумага содержит диаграмму выходного формата. Вместо того, чтобы задавать поле обычным способом, оно указывается как набор расстояний (вверх, вправо, вниз и влево) от смещения (x, y), в дополнение к углу A, количество поворотов поля против часовой стрелки .
Обратите внимание, что scores
и geometry
индексируются y, x
, в отличие от любой логики ниже расчета offset
. Поэтому, чтобы получить максимальные баллы за компоненты геометрии y, x
:
high_scores_yx = np.where(scores[0][0] >= np.max(scores[0][0]))
y, x = high_scores_yx[0][0], high_scores_yx[1][0]
h_upper, w_right, h_lower, w_left, A = geometry[0,:,y,x]
Код использует offset
для хранения смещения нижнего правого угла прямоугольника. Поскольку он находится в правом нижнем углу, ему нужны только w_right
и h_lower
, которые в коде обозначаются x1_data
и x2_data
соответственно.
Расположение правого нижнего угла относительно исходного смещения offsetX, offsetY
зависит от угла поворота. Ниже пунктирные линии показывают ориентацию осей. Компоненты, которые нужно перейти от оригинала к нижнему смещению, помечены фиолетовым (по горизонтали) и фиолетовым (по вертикали). Обратите внимание, что компонент sin(A) * w_right
равен вычтено, потому что y
становится больше по мере опускания в этой системе координат.
Так что это объясняет
offset = ([offsetX + cosA * x1_data[x] + sinA * x2_data[x], offsetY - sinA * x1_data[x] + cosA * x2_data[x]])
Далее: p1
и p3
— левый нижний и правый верхний углы прямоугольника соответственно с учетом поворота. center
— это просто среднее значение этих двух баллов.
Наконец, -1*angle * 180.0 / math.pi
преобразует исходный угол в радианах против часовой стрелки в угол в градусах по часовой стрелке (поэтому окончательный выходной угол должен быть отрицательным для объектов, повернутых против часовой стрелки). Это сделано для совместимости с методом CV2 boxPoints
, используемым в:
Большое вам спасибо, я смог разобраться с некоторыми вещами самостоятельно, но был сбит с толку индексами y, x и знаками некоторых из этих косинусов и синусов. Это здорово!
Итак, каков ваш точный вопрос?