Пусть я будет кадром w x h из видеопотока 360 °.
Пусть р будет красным прямоугольником на этом кадре. р меньше ширины изображения.
Чтобы вычислить центроид этого прямоугольника, нам нужно различать два случая:
Как видите, в случае 1 будет проблема вычислить центроид классическими методами. Обратите внимание, что меня интересует только горизонтальное перекрытие.
На данный момент я так и делаю. Сначала мы определяем первую найденную точку и используем ее в качестве эталона, затем нормализуем dx, который является разницей между точкой и эталоном, а затем накапливаем:
width = frame.width
rectangle_pixel = (255,0,0)
first_found_coord = (-1,-1)
centroid = (0,0)
centroid_count = 0
for pixel, coordinates in image:
if (pixel != rectangle_pixel):
continue
if (first_found_coord == (-1,-1)):
first_found_coord = coordinates
centroid = coordinates
continue
dx = coordinates.x - first_found_coord.x
if (dx > width/2):
dx -= width
else if (dx < - width/2):
dx -= width
centroid += (dx, coordinates.y)
centroid_count++
final_centroid = centroid / centroid_count
Но это работает не так, как ожидалось. В чем проблема, есть ли более быстрое решение?
Теоретически это верно, но я никогда не столкнусь с этим случаем в своих сценариях. «(...) Меня волнует только горизонтальное перекрытие».





Вот решение, основанное на точках перехода, то есть при переходе от красного к не-красному или другим способом. Чтобы запечатлеть центр по горизонтали, мне понадобилась следующая информация:
gridSize.x: ширина пространства, в котором могут располагаться прямоугольники.
w: ширина вашего прямоугольника.
Псевдокод:
redPixel = (255,0,0);
transitionPoints = [];
betweenTransitionsColor = -1;
// take i and i+1 pixel+position, increment i by one at each step.
for (pixel1, P1), (pixel1, P2) in gridX : // horizontal points for a fixed `y`
if pixel1 != pixel2: // one is red, the other white
nonRedPosition = (pixel1 != redPixel ? P1 : P2)
transitionPoints.append(nonRedPosition)
continue
if (transitionPoints.length == 1 && betweenTransitionsColor == -1):
betweenTransitionsColor = pixel2
if transitionPoints.length == 2:
break
//Case where your rectangle is on the edge (left or right)
if (transitionPoints.length == 1):
if (abs(transitionPoints[0].x - w) < 2):
xCenter = w/2
else:
xCenter = gridSize.x - w/2
else:
[tP1, tP2] = transitionPoints
// case 1 : The rectangle is splitted
if betweenTransitionsColor != redPixel:
xCenter = (tP2.x - gridSize.x + tP1.x)/2
else:
xCenter = (tP1.x + tP1.x)/2
Примечание :
вы должны начать с позиции y, где вы можете получить красные пиксели. Достичь этого не должно быть очень сложно. Если ваш rectangle's height больше, чем gridSize.y/2, вы можете начать с gridSize.y/2. В противном случае вы можете найти первый красный пиксель и установить y в соответствующее положение.
Методы, основанные на точках перехода, в моем случае не сработают, поскольку цветовой шарик может быть не гладким прямоугольником, а скорее фрагментированным. Может быть интересно другим, спасибо, что поделились.
Поскольку я вычисляю ограничивающие прямоугольники в одной и той же области, я делаю это в два этапа. Сначала я накапливаю координаты интересующих пикселей. Затем, когда я проверяю перекрывающиеся ограничительные рамки, я вычитаю с для каждого перекрывающегося цвета в правой половине изображения. В итоге я получаю законченный, но сдвинутый прямоугольник.
В конце я делю на количество точек, найденных для каждого цвета. Если результат отрицательный, я сдвигаю его на размер ширины изображения.
Альтернативно:
def get_centroid(image, interest_color):
acc_x = 0
acc_y = 0
count = 0
first_pixel = (0,0)
for (x,y, color) in image:
if (color not in interest_color):
continue
if (count == 0):
first_pixel = (x,y)
dx = x - first_pixel.x
if (dx > L/2)
dx -= L
else if (dx < -L/2)
dx += L
acc_x += x
acc_y += y
count++
non_scaled_result = acc_x / count, acc_y / count
result = non_scaled_result + first_pixel
return result
На самом деле может быть третий случай, когда прямоугольник пересекает угол и разделяется на 4 части.