我有一个计算机视觉算法,可以在检测到的对象周围放置边界框。边界框列表如下:
bounding_boxes = [[x, y, w, h], [x2, y2, w2, h2], ...]
其中 x 和 y 是左上角的坐标,h 和 w 是框的高度和宽度。但是,我对完全包含在任何其他较大盒子中的盒子不感兴趣。检测这些的有效方法是什么?
我有一个计算机视觉算法,可以在检测到的对象周围放置边界框。边界框列表如下:
bounding_boxes = [[x, y, w, h], [x2, y2, w2, h2], ...]
其中 x 和 y 是左上角的坐标,h 和 w 是框的高度和宽度。但是,我对完全包含在任何其他较大盒子中的盒子不感兴趣。检测这些的有效方法是什么?
正如您在问题下的评论中确认的那样,您需要识别并删除包含在单个其他框中的框。如果一个盒子包含在其他盒子的并集中,但没有其他单个盒子包含它,那么它不应该被删除(例如,在这种情况下boxes = [[0, 0, 2, 4], [1, 1, 3, 3], [2, 0, 4, 4]]
,第二个盒子包含在第一个和第三个的并集中,但它应该不会被删除)。
此任务的天真(蛮力)算法非常简单。这是伪代码:
for i in [0, 1, ..., n]:
for j in [i+1, i+2, ..., n]:
check if box[i] contains in box[j] and otherwise.
这个算法的复杂度是显而易见的O(n^2)
。这个算法很容易实现,推荐在盒子数量少的情况下(100-500左右,如果你不需要视频处理的实时性能,甚至1000)。
快速算法的复杂度是O(n log n)
,我相信这也是这个问题的最小理论复杂度。形式上,所需的算法采用以下输入并返回以下输出:
Input: boxes[] - Array of n Rectangles, Tuples of (x1, y1, x2, y2), where
(x1, y1) is coordinates of the left bottom corner, (x2, y2)
is the coordinates of the top right corner.
Output: inner_boxes[] - Array of Rectangles that should be removed.
快速算法的伪代码:
1) Allocate an Array events[] with the length 2*n, the elements of which are
Tuples (y, corresponding_box_index, event).
2) For i in [0, 1, ..., n]:
events[2 * i ] = Tuple(boxes[i].y1, i, 'push')
events[2 * i + 1] = Tuple(boxes[i].y2, i, 'pop')
3) Sort events[] by the ascending of y coordinate (from smaller to larger).
If there are equal y coordinates, Then:
- Tuples with 'pop' event are smaller thant Tuples with 'push' event.
- If two Tuples has the same event, they are sorted by the ascending of
the width of their corresponding boxes.
4) Create a Map cross_section_map[], that maps a Key (Value) x to a Tuple
(corresponding_box_index, type), where type can be either 'left' or 'right'.
Make sure that the 'insert' and 'erase' operation of this data structure
has the complexity O(log n), it is iterable, the elements are iterated in
an key-ascending manner, and you can search for a key in O(log n) time.
5) For step in [0, 1, ..., 2*n]:
If events[step].event is 'push':
- Let i = events[step].corresponding_box_index
- Insert a map boxes[i].x1 -> (i, 'left') to cross_section_map[]
- Insert a map boxes[i].x2 -> (i, 'right') to cross_section_map[]
- Search for a 'right'-typed key with x value no less than boxes[i].x2
- Iterate from that key until you found a key, which corresponds to
a box that contains boxes[i], or the x1 coordinate of which is larger
than the x1 coordinate of a newly added box. In the first case, add
boxes[i] to inner_boxes[].
If events[step].event is 'pop':
- Let i = events[step].corresponding_box_index
- Erase the elements with the keys boxes[i].x1 and boxes[i].x2
现在,棘手的部分是(4)
该算法的步骤。实现这样的数据结构似乎很困难。但是,C++ 标准库中有一个开箱即用的出色实现,称为std::map
. 适用的搜索操作O(log n)
是std::map::lower_bound
和std::map::upper_bound
。
该算法的平均复杂度为O(n log n)
,最坏情况复杂度为O(n^2)
,如果框的数量及其大小与图像大小相比相对较小,则复杂度接近O(n)
。