AxisAlignedBox矩形边界框

矩形边界框

另一种常见的用来界定物体的几何图元是矩形边界框,矩形边界框可以是与轴对齐的或是任意方向的。轴对齐矩形边界框有一个限制,就是它的边必须垂直于坐标轴。缩写AABB常用来表示axially aligned bounding box(轴对齐矩形边界框),OBB用来表示oriented bounding box(方向矩形边界框)。轴对齐矩形边界框不仅容易创建,而且易于使用。

一个3D的AABB就是一个简单的六面体,每一边都平行于一个坐标平面。矩形边界框不一定是立方体,它的长、宽、高可以彼此不同。在图12.10中,画出了一些简单的3D物体和它们的AABB。

 

AABB的表达方法

先介绍AABB的一些重要性质和引用这些值时所用到的记法。AABB内的点满足下列等式:

xmin≤ x ≤ xmax

ymin≤ y ≤ ymax

zmin≤ z ≤ zmax

特别重要的两个点为:

pmin = [xmin ymin   zmin]

pmax = [xmax ymax   zmax]

中心点c为:

c = (pmin + pmax) /2

"尺寸向量"s是从pmin指向pmax的向量,包含了矩形边界的长、宽、高:

s = pmax - pmin

还可以求出矩形边界框的"半径向量"r,它是从中心指向pmax的向量:

r = pmax - c = s/2

明确地定义一个AABB只需要pminpmaxcsr这5个向量中的两个(除sr不能配对外,它们中的任意两个都可配对)。在一些情况下,某些配对形式比其他的会更有用。我们建议用pminpmax表示一个边界框,因为实际应用中,使用它们的频率远高于csr。当然,由pminpmax计算其余三个中的任意一个都是很容易的。

在我们的C++代码中,使用下面的类表示AABB,这是一个缩略的代码清单。

    #ifndef AABB3_H
    #define AABB3_H
   
    #include "vector3.h"
   
    class cMatrix4x3;
   
        //---------------------------------------------------------------------------
    // Implement a 3D axially aligned bounding box
    //---------------------------------------------------------------------------
    class cAABB3
    {
    public:
         cVector3 min, max;
   
    public:
        // query for dimentions
         cVector3 size() const         { return max - min; }
        float      x_size()             { return max.x - min.x; }
        float      y_size()             { return max.y - min.y; }
        float      z_size()             { return max.z - min.z; }
         cVector3 center() const         { return (min + max) * 0.5f; }
   
        // fetch one of the eight corner points
         cVector3 corner(int i) const;
   
        // "Empty" the box, by setting the values to really large/small numbers.
        void empty();
   
        // add a point to the box
        void add(const cVector3& p);
   
        // add an AABB to the box
        void add(const cAABB3& box);
   
        // return true if the box is empty
        bool is_empty() const;
   
        // return true if the box contains a point
        bool contains(const cVector3& p) const;
   
        // transform the box and compute the new AABB
        void set_to_transformed_box(const cAABB3& box, const cMatrix4x3& m);
   
        // return the clostet point on this box to another point
         cVector3 clostet_point_to(const cVector3& p) const;
    };
   
    #endif

计算AABB

计算一个顶点集合的AABB是非常简单的,先将最小值和最大值设为"正负无穷大"或任何比实际中用到的数都大或小得多的数。接着,遍历全部点,并扩展边界框直到它包含所有点为止。

我们在cAABB类中引入了两个辅助函数,第一个函数负责"清空"AABB:

    //---------------------------------------------------------------------------
    // "Empty" the box, by setting the values to really large/small numbers.
    //---------------------------------------------------------------------------
    void cAABB3::empty()
    {
        constfloat big_number = 1e37f;
   
         min.x = min.y = min.z = big_number;
         max.x = max.y = max.z = -big_number;
    }
第二个函数将单个点"加"到AABB中,并在必要的时候扩展AABB以包含每个点:

    //---------------------------------------------------------------------------
    // Add a point to the box
    //---------------------------------------------------------------------------
    void cAABB3::add(const cVector3& p)
    {
        // expand the box as necessary to contain the point
        if(p.x < min.x)         min.x = p.x;
        if(p.x > max.x)         max.x = p.x;
        if(p.y < min.y)         min.y = p.y;
        if(p.y > max.y)         max.y = p.y;
        if(p.z < min.z)         min.z = p.z;
        if(p.z > max.z)         max.z = p.z;
    }
现在,从一个点集创建矩形边界框,可以使用下面的代码:

    Listing 12.1: Computing the AABB for a set of points
   
    // Our list of points
    constint n;
    Vector3 list[n];
   
    // First, empty the box
    AABB3 box;
    box.empty();
   
    // Add each point into the box
    for (int i = 0 ; i < n ; ++i)
       box.add(list[i]);

取得AABB的顶点:

    //--------------------------------------------------------------------------------------
    // Return one of the 8 corner points.   The points are numbered as follows:
    //
    //             6                                 7
    //               ------------------------------
    //              /|                            /|
    //             / |                           / |
    //            /   |                          /   |
    //           /    |                         /    |
    //          /     |                        /     |
    //         /      |                       /      |
    //        /       |                      /       |
    //       /        |                     /        |
    //      /         |                    /         |
    //   2 /          |                 3 /          |
    //    /----------------------------/           |
    //    |           |                  |           |
    //    |           |                  |           |       +Y
    //    |         4 |                  |           |
    //    |           |-----------------|----------|       |
    //    |          /                   |          /   5     |
    //    |         /                    |         /         |        +Z
    //    |        /                     |        /          |
    //    |       /                      |       /           |      /
    //    |      /                       |      /            |     /
    //    |     /                        |     /             |    /
    //    |    /                         |    /              |   /
    //    |   /                          |   /               | /
    //    | /                           | /                |/
    //    |/                            |/                 ----------------- +X
    //    ------------------------------
    //   0                               1
    //
    // Bit 0 selects min.x vs. max.x
    // Bit 1 selects min.y vs. max.y
    // Bit 2 selects min.z vs. max.z
    //--------------------------------------------------------------------------------------
    cVector3 cAABB3::corner(int i) const
    {
         assert(i >= 0 && i <= 7);    // make sure index is in range
   
        return cVector3((i & 1) ? max.x : min.x,
                         (i & 2) ? max.y : min.y,
                         (i & 4) ? max.z : min.z);
    }
其他的相关函数,具体功能详见注释:

    //---------------------------------------------------------------------------
    // Add an AABB to the box
    //---------------------------------------------------------------------------
    void cAABB3::add(const cAABB3& box)
    {
        // expand the box as necessary
        if(box.min.x < min.x)     min.x = box.min.x;
        if(box.min.x > max.x)     max.x = box.min.x;
        if(box.min.y < min.y)     min.y = box.min.y;
        if(box.min.y > max.y)     max.y = box.min.y;
        if(box.min.z < min.z)     min.z = box.min.z;
        if(box.min.z > max.z)     max.z = box.min.z;
    }
   
    //---------------------------------------------------------------------------
    // Return true if the box is empty
    //---------------------------------------------------------------------------
    bool cAABB3::is_empty() const
    {
        // check if we're inverted on any axis
        return (min.x > max.x) || (min.y > max.y) || (min.z > max.z);
    }
   
    //---------------------------------------------------------------------------
    // Return true if the box contains a point
    //---------------------------------------------------------------------------
    bool cAABB3::contains(const cVector3& p) const
    {
        // check for overlap on each axis
        return (p.x >= min.x) && (p.x <= max.x) &&
                (p.y >= min.y) && (p.y <= max.y) &&
                (p.z >= min.z) && (p.z <= max.z);
    }
   
    //---------------------------------------------------------------------------
    // return the closest point on this box to another point
    //---------------------------------------------------------------------------
    cVector3 cAABB3::clostet_point_to(const cVector3& p) const
    {
        // "push" p into the box, on each dimension.
   
         cVector3 r;
   
        if(p.x < min.x)
             r.x = min.x;
        elseif(p.x > max.x)
             r.x = max.x;
        else
             r.x = p.x;
   
        if(p.y < min.y)
             r.y = min.y;
        elseif(p.y > max.y)
             r.y = max.y;
        else
             r.y = p.y;
   
        if(p.z < min.z)
             r.z = min.z;
        elseif(p.z > max.z)
             r.z = max.z;
        else
             r.z = p.z;
   
        return r;
    }

AABB与边界球

很多情况下,AABB比边界球更适合于做定界球:

(1)计算一个点集的AABB,在编程上更容易实现,并能在较短的时间内完成。计算边界球则困难得多。

(2)对实际世界里的许多物体,AABB提供了一种"更紧凑"的边界。当然,对于某些物体,边界球更好(设想一个本身就是球形的物体)。在极端情况下,AABB的体积可能仅相当于边界球体积的1/2,大部分时候边界球的体积会比矩形框的体积大得多,比较一下电线杆的边界球和AABB就知道了。图12.11所示为不同物体的AABB与边界球的比较。

边界球的根本问题是它的形状只有一个自由度----半径,而AABB却有三个自由度----长、宽、高。因此,它可以调节这些自由度以适应不同物体。对图12.11中的大部分物体,除了右上角的星形体外,AABB都比边界球小。对这颗星,边界球也仅比AABB略小一些。通过图12.11,我们可以注意到AABB对物体的方向很敏感。比较下面两支枪的AABB,图中枪的大小都是相同的,只是方向不同而已;还应注意到在这一情况下边界球大小相同,因为边界球对物体方向不敏感。

注:转载源地址
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过`cv2.findContours`函数获取所有最小矩形边界框中的最小边界框。具体来说,您可以使用`cv2.minAreaRect`函数找到每个轮廓的最小矩形边界框,然后计算该边界框的最小边界框。 以下是一些示例代码,用于获取所有最小矩形边界框中的最小边界框: ``` python import cv2 # 读取图像 img = cv2.imread('test.png') # 转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 获取所有轮廓的最小边界框 rects = [] for contour in contours: rect = cv2.minAreaRect(contour) rects.append(rect) # 获取所有最小矩形边界框中的最小边界框 min_rects = [] for rect in rects: box = cv2.boxPoints(rect) box = np.int0(box) rect_w, rect_h = rect[1] if rect_w > rect_h: rect_w, rect_h = rect_h, rect_w min_rect = (rect[0], (rect_w, rect_h), rect[2]) min_rects.append(min_rect) ``` 当然,如果您只是想简单地获取所有最小矩形边界框中的最小边界框,也可以使用`cv2.minEnclosingTriangle`函数直接获取所有轮廓的最小边界框,如下所示: ``` python min_rects = [] for contour in contours: (x, y), radius = cv2.minEnclosingCircle(contour) rect_w, rect_h = radius, radius min_rect = ((int(x), int(y)), (int(rect_w), int(rect_h)), 0) min_rects.append(min_rect) ``` 这种方法比较简单,但是可能会存在一些精度问题,因为它只是使用了轮廓的最小外接圆来估计最小矩形边界框。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值